Restore the old customOptions table but within a separate "items" tab

This commit is contained in:
Henriette Darge
2026-02-19 14:12:18 +01:00
parent dd581b800b
commit 72a274dbd5
15 changed files with 587 additions and 176 deletions
@@ -46,12 +46,18 @@ module Admin
}
]
if @custom_field.hierarchical_list? || @custom_field.list?
if @custom_field.hierarchical_list?
tabs << {
name: "items",
path: custom_field_items_path(@custom_field),
label: t(:label_item_plural)
}
elsif @custom_field.list?
tabs << {
name: "items",
path: list_items_custom_field_path(@custom_field),
label: t(:label_item_plural)
}
end
if @custom_field.is_a?(WorkPackageCustomField) ||
@@ -44,7 +44,11 @@ module CustomFields
alias_method :custom_field, :model
def form_url
model.new_record? ? custom_fields_path : custom_field_path(model)
if model.new_record?
model.type == "ProjectCustomField" ? admin_settings_project_custom_fields_path : custom_fields_path
else
model.type == "ProjectCustomField" ? admin_settings_project_custom_field_path(model) : custom_field_path(model)
end
end
def form_method
@@ -65,7 +69,7 @@ module CustomFields
def show_top_banner?
case custom_field.field_format
when "hierarchy", "weighted_item_list"
when "hierarchy", "weighted_item_list", "list"
persisted_cf_has_no_items_or_projects?
else
false
@@ -74,12 +78,16 @@ module CustomFields
def top_banner_text
case custom_field.field_format
when "hierarchy", "weighted_item_list"
when "hierarchy", "weighted_item_list", "list"
I18n.t("custom_fields.admin.notice.remember_items_and_projects")
end
end
def persisted_cf_has_no_items_or_projects?
if custom_field.list? && custom_field.custom_options.empty? && custom_field.projects.empty?
return true
end
custom_field.persisted? &&
custom_field.hierarchical_list? &&
custom_field.hierarchy_root.children.empty? &&
@@ -51,6 +51,12 @@ module Settings
path: admin_settings_project_custom_field_items_path(@custom_field),
label: t(:label_item_plural)
}
elsif @custom_field.list?
tabs << {
name: "items",
path: list_items_admin_settings_project_custom_field_path(@custom_field),
label: t(:label_item_plural)
}
end
if @custom_field.user?
@@ -43,7 +43,7 @@ module Admin::Settings
before_action :find_custom_field,
only: %i(show edit project_mappings new_link link unlink update destroy delete_option reorder_alphabetical
move drop role_assignment update_role_assignment role_assignment_preview_dialog
attribute_help_text update_attribute_help_text)
attribute_help_text update_attribute_help_text list_items)
before_action :prepare_custom_option_position, only: %i(update create)
before_action :find_custom_option, only: :delete_option
before_action :project_custom_field_mappings_query, only: %i[project_mappings unlink]
@@ -74,6 +74,8 @@ module Admin::Settings
def edit; end
def list_items; end
def project_mappings; end
def role_assignment; end
@@ -49,6 +49,14 @@ module CustomFields
end
end
def list_item_path(custom_field, params = {})
if custom_field.type == "ProjectCustomField"
list_items_admin_settings_project_custom_field_path(**params)
else
list_items_custom_field_path(**params)
end
end
def create # rubocop:disable Metrics/AbcSize
call = ::CustomFields::CreateService
.new(user: current_user)
@@ -66,10 +74,14 @@ module CustomFields
end
def update
perform_update(get_custom_field_params)
if custom_options_attributes
perform_update(get_custom_field_params, tab: :list_items)
else
perform_update(get_custom_field_params)
end
end
def perform_update(custom_field_params)
def perform_update(custom_field_params, tab: :edit)
call = ::CustomFields::UpdateService
.new(user: current_user, model: @custom_field)
.call(custom_field_params)
@@ -77,7 +89,13 @@ module CustomFields
if call.success?
flash[:notice] = t(:notice_successful_update)
call_hook(:controller_custom_fields_edit_after_save, custom_field: @custom_field)
redirect_back_or_default(edit_path(@custom_field, id: @custom_field.id))
path = if tab == :list_items
list_item_path(@custom_field,
id: @custom_field.id)
else
edit_path(@custom_field, id: @custom_field.id)
end
redirect_to(path)
else
render action: :edit, status: :unprocessable_entity
end
@@ -89,10 +107,10 @@ module CustomFields
.sort_by(&:value)
.each_with_index
.map do |custom_option, index|
{ id: custom_option.id, position: index + 1 }
{ id: custom_option.id, position: index + 1 }
end
perform_update(custom_options_attributes: reordered_options)
perform_update({ custom_options_attributes: reordered_options }, tab: :list_items)
end
def destroy
@@ -115,7 +133,7 @@ module CustomFields
flash[:error] = @custom_option.errors.full_messages
end
redirect_to edit_path(@custom_field, id: @custom_field.id), status: :see_other
redirect_to list_item_path(@custom_field, id: @custom_field.id), status: :see_other
end
def new_custom_field
@@ -139,14 +157,18 @@ module CustomFields
end
def prepare_custom_option_position
return unless params[:custom_field][:custom_options_attributes]
return unless custom_options_attributes
index = 0
params[:custom_field][:custom_options_attributes].each_value do |attributes|
custom_options_attributes.each_value do |attributes|
attributes[:position] = (index = index + 1)
end
end
def custom_options_attributes
params[:custom_field][:custom_options_attributes]
end
end
end
end
+6 -1
View File
@@ -31,11 +31,14 @@
class CustomFieldsController < ApplicationController
include CustomFields::SharedActions # share logic with ProjectCustomFieldsControlller
include CustomFields::AttributeHelpTextActions
layout "admin"
# rubocop:disable Rails/LexicallyScopedActionFilter
before_action :require_admin
before_action :find_custom_field, only: %i(edit update destroy delete_option reorder_alphabetical attribute_help_text update_attribute_help_text)
before_action :find_custom_field,
only: %i(edit update destroy delete_option reorder_alphabetical attribute_help_text update_attribute_help_text
list_items)
before_action :prepare_custom_option_position, only: %i(update create)
before_action :find_custom_option, only: :delete_option
before_action :validate_enterprise_token, only: %i(create)
@@ -67,6 +70,8 @@ class CustomFieldsController < ApplicationController
render_attribute_help_text_form
end
def list_items; end
def update_attribute_help_text
update_help_text
end
+18 -20
View File
@@ -61,23 +61,21 @@ module CustomFields
end
if show_min_max_field?
details_form.group(layout: :horizontal) do |g|
g.text_field(
name: :min_length,
type: :number,
label: label(:min_length),
caption: instructions(:min_max),
input_width: :xsmall
)
details_form.text_field(
name: :min_length,
type: :number,
label: label(:min_length),
caption: instructions(:min_max),
input_width: :small
)
g.text_field(
name: :max_length,
type: :number,
label: label(:max_length),
caption: instructions(:min_max),
input_width: :xsmall
)
end
details_form.text_field(
name: :max_length,
type: :number,
label: label(:max_length),
caption: instructions(:min_max),
input_width: :small
)
end
if show_regex_field?
@@ -220,7 +218,7 @@ module CustomFields
end
def show_default_text_field?
%w[list bool date text user version hierarchy calculated_value].exclude?(model.field_format)
%w[list bool date text user version hierarchy weighted_item_list calculated_value].exclude?(model.field_format)
end
def show_default_rich_text_field?
@@ -232,11 +230,11 @@ module CustomFields
end
def show_min_max_field?
%w[list bool date user version link hierarchy calculated_value].exclude?(model.field_format)
%w[list bool date user version link hierarchy weighted_item_list calculated_value].exclude?(model.field_format)
end
def show_regex_field?
%w[list bool date user version hierarchy calculated_value].exclude?(model.field_format)
%w[list bool date user version hierarchy weighted_item_list calculated_value].exclude?(model.field_format)
end
def show_right_to_left_field?
@@ -260,7 +258,7 @@ module CustomFields
end
def show_is_searchable_field?
%w[bool date float int user version hierarchy calculated_value].exclude?(model.field_format)
%w[bool date float int user version hierarchy weighted_item_list calculated_value].exclude?(model.field_format)
end
def show_non_open_versions_field?
-3
View File
@@ -61,9 +61,6 @@ class CustomField < ApplicationRecord
acts_as_list scope: [:type]
validates :field_format, presence: true
validates :custom_options,
presence: { message: ->(*) { I18n.t(:"activerecord.errors.models.custom_field.at_least_one_custom_option") } },
if: ->(*) { field_format == "list" }
validates :name,
presence: true,
length: { maximum: 256 },
@@ -0,0 +1,76 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) the OpenProject GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See COPYRIGHT and LICENSE files for more details.
++#%>
<% html_title t(:label_administration), t("settings.project_attributes.heading"), @custom_field.name %>
<%=
render(
Settings::ProjectCustomFields::EditFormHeaderComponent.new(
custom_field: @custom_field,
selected: :project_custom_field_edit
)
)
%>
<%= settings_primer_form_with(
model: @custom_field,
scope: :custom_field,
url: admin_settings_project_custom_field_path(@custom_field),
html: { method: :put, id: "custom_field_form" }
) do |f| %>
<%= render partial: "custom_fields/custom_options", locals: { custom_field: @custom_field, f: f } %>
<%=
flex_layout(mt: 4) do |flex|
flex.with_column do
render Primer::Beta::Button.new(
scheme: :secondary,
tag: :a,
href: reorder_alphabetical_admin_settings_project_custom_field_path(@custom_field),
data: {
turbo_method: :post,
turbo_confirm: t("custom_fields.reorder_confirmation")
},
mr: 2
) do
t("custom_fields.reorder_alphabetical")
end
end
flex.with_column do
render Primer::Beta::Button.new(
scheme: :primary,
type: :submit,
) do |button|
button.with_leading_visual_icon(icon: :check)
t(:button_submit)
end
end
end
%>
<% end %>
@@ -0,0 +1,170 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) the OpenProject GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See COPYRIGHT and LICENSE files for more details.
++#%>
<% content_controller "admin--custom-fields",
"admin--custom-fields-multi-select-value": @custom_field.multi_value? %>
<% custom_field.custom_options.build if custom_field.custom_options.empty? %>
<div class="generic-table--container">
<div class="generic-table--results-container">
<table class="generic-table" id="custom-options-table" data-controller="table-highlighting">
<colgroup>
<col>
<col>
<col>
<col data-highlight="false">
</colgroup>
<thead>
<tr>
<th>
<div class="generic-table--sort-header-outer">
<div class="generic-table--sort-header">
<span>
<%= t("activerecord.attributes.custom_value.value") %>
</span>
</div>
</div>
</th>
<th>
<div class="generic-table--sort-header-outer">
<div class="generic-table--sort-header">
<span>
<%= t(:label_default) %>
</span>
</div>
</div>
</th>
<th>
<div class="generic-table--sort-header-outer">
<div class="generic-table--sort-header">
<span>
<%= t(:button_sort) %>
</span>
</div>
</div>
</th>
<th style="max-width:200px;">
<div class="generic-table--empty-header">
</div>
</th>
</tr>
</thead>
<tbody
data-test-selector="dragula-container"
data-admin--custom-fields-target="dragContainer">
<% custom_field.custom_options.each_with_index do |custom_option, i| %>
<%= f.fields_for :custom_options, custom_option do |co_f| %>
<tr
class="dragula-element custom-option-row"
data-admin--custom-fields-target="customOptionRow">
<td>
<span class="dragula-handle icon icon-table icon-drag-handle"></span>
<%= co_f.hidden_field :id,
class: "custom-option-id" %>
<span class="custom-option-value">
<%= co_f.text_field :value,
no_label: true %>
</span>
</td>
<td>
<%= co_f.check_box :default_value,
container_class: "custom-option-default-value",
data: {
"admin--custom-fields-target": "customOptionDefaults",
action: "click->admin--custom-fields#uncheckOtherDefaults"
},
no_label: true %>
</td>
<td>
<span class="reorder-icons">
<a
title="<%= t(:label_sort_highest) %>"
rel="nofollow"
href="#"
class="sort-up-custom-option"
data-action="admin--custom-fields#moveRowToTheTop">
<%= op_icon("icon-context icon-sort-up icon-small") %>
</a>
<a
title="<%= t(:label_sort_higher) %>"
rel="nofollow"
href="#"
class="move-up-custom-option"
data-action="admin--custom-fields#moveRowUp">
<%= op_icon("icon-context icon-arrow-up2 icon-small") %>
</a>
<a
title="<%= t(:label_sort_lower) %>"
rel="nofollow" href="#"
class="move-down-custom-option"
data-action="admin--custom-fields#moveRowDown">
<%= op_icon("icon-context icon-arrow-down2 icon-small") %>
</a>
<a
title="<%= t(:label_sort_lowest) %>"
rel="nofollow"
href="#"
class="sort-down-custom-option"
data-action="admin--custom-fields#moveRowToTheBottom">
<%= op_icon("icon-context icon-sort-down icon-small") %>
</a>
</span>
</td>
<td>
<%= link_to "",
delete_option_of_custom_field_path(id: custom_field.id || 0, option_id: custom_option.id || 0),
data: {
turbo_method: :delete,
action: "admin--custom-fields#removeOption",
turbo_confirm: t(:"custom_fields.confirm_destroy_option")
},
class: "icon icon-delete delete-custom-option",
title: t(:button_delete) %>
</td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
</div>
</div>
<%=
render Primer::Beta::Button.new(
scheme: :link,
test_selector: "add-custom-option",
data: { action: "admin--custom-fields#addOption" },
mt: 2
) do |button|
button.with_leading_visual_icon(icon: :plus)
t(:button_add)
end
%>
@@ -0,0 +1,69 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) the OpenProject GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See COPYRIGHT and LICENSE files for more details.
++#%>
<% html_title t(:label_administration), "#{CustomField.model_name.human} #{h @custom_field.name}", t(:label_item_plural) %>
<%= render(Admin::CustomFields::EditFormHeaderComponent.new(custom_field: @custom_field, selected: :items)) %>
<%= settings_primer_form_with(
model: @custom_field,
scope: :custom_field,
url: custom_field_path(@custom_field),
html: { id: "custom_field_form" }
) do |f| %>
<%= render partial: "custom_fields/custom_options", locals: { custom_field: @custom_field, f: f } %>
<%=
flex_layout(mt: 4) do |flex|
flex.with_column do
render Primer::Beta::Button.new(
scheme: :secondary,
tag: :a,
href: reorder_alphabetical_custom_field_path(@custom_field),
data: {
turbo_method: :post,
turbo_confirm: t("custom_fields.reorder_confirmation")
},
mr: 2
) do
t("custom_fields.reorder_alphabetical")
end
end
flex.with_column do
render Primer::Beta::Button.new(
scheme: :primary,
type: :submit,
) do |button|
button.with_leading_visual_icon(icon: :check)
t(:button_submit)
end
end
end
%>
<% end %>
+1 -1
View File
@@ -389,7 +389,7 @@ en:
contained_in_type: "Contained in type"
confirm_destroy_option: "Deleting an option will delete all of its occurrences (e.g. in work packages). Are you sure you want to delete it?"
reorder_alphabetical: "Reorder values alphabetically"
reorder_confirmation: "Warning: The current order of available values will be lost. Continue?"
reorder_confirmation: "Warning: The current order of available values as well as all unsaved values will be lost. Are you sure you want to continue?"
placeholder_version_select: "Work package or project selection is required first"
calculated_field_not_editable: "Non-editable attribute. This value is calculated automatically."
no_role_assigment: "No role assignment"
+4
View File
@@ -218,6 +218,8 @@ Rails.application.routes.draw do
get :attribute_help_text
put :update_attribute_help_text
get :list_items
end
scope module: :admin do
@@ -694,6 +696,8 @@ Rails.application.routes.draw do
get :attribute_help_text
put :update_attribute_help_text
get :list_items
end
resources :items, controller: "/admin/settings/project_custom_fields/hierarchy/items" do
@@ -0,0 +1,186 @@
/*
* -- copyright
* OpenProject is an open source project management software.
* Copyright (C) the OpenProject GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 3.
*
* OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
* Copyright (C) 2006-2013 Jean-Philippe Lang
* Copyright (C) 2010-2013 the ChiliProject Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* See COPYRIGHT and LICENSE files for more details.
* ++
*/
import { Controller } from '@hotwired/stimulus';
import dragula from 'dragula';
export default class CustomFieldsController extends Controller {
static targets = [
'dragContainer',
'customOptionDefaults',
'customOptionRow',
];
static values = {
multiSelect: Boolean,
};
declare readonly multiSelectValue:boolean;
declare readonly dragContainerTarget:HTMLElement;
declare readonly hasDragContainerTarget:boolean;
declare readonly customOptionDefaultsTargets:HTMLInputElement[];
declare readonly customOptionRowTargets:HTMLTableRowElement[];
connect() {
if (this.hasDragContainerTarget) {
this.setupDragAndDrop();
}
}
moveRowUp(event:{ target:HTMLElement }) {
const row = event.target.closest('tr')!;
const idx = this.customOptionRowTargets.indexOf(row);
if (idx > 0) {
this.customOptionRowTargets[idx - 1].before(row);
}
return false;
}
moveRowDown(event:{ target:HTMLElement }) {
const row = event.target.closest('tr')!;
const idx = this.customOptionRowTargets.indexOf(row);
if (idx < this.customOptionRowTargets.length - 1) {
this.customOptionRowTargets[idx + 1].after(row);
}
return false;
}
moveRowToTheTop(event:{ target:HTMLElement }) {
const row = event.target.closest('tr')!;
const first = this.customOptionRowTargets[0];
if (first && first !== row) {
first.before(row);
}
return false;
}
moveRowToTheBottom(event:{ target:HTMLElement }) {
const row = event.target.closest('tr')!;
const last = this.customOptionRowTargets[this.customOptionRowTargets.length - 1];
if (last && last !== row) {
last.after(row);
}
return false;
}
removeOption(event:MouseEvent) {
const self = event.target as HTMLAnchorElement;
if (self.href === '#' || self.href.endsWith('/0')) {
const row = self.closest('tr');
if (row && this.customOptionRowTargets.length > 1) {
row.remove();
}
event.preventDefault();
event.stopImmediatePropagation();
}
return true; // send off deletion
}
addOption() {
const count = this.customOptionRowTargets.length;
const last = this.customOptionRowTargets[count - 1];
const dup = last.cloneNode(true) as HTMLElement;
const input = dup.querySelector('.custom-option-value input') as HTMLInputElement;
input.setAttribute('name', `custom_field[custom_options_attributes][${count}][value]`);
input.setAttribute('id', `custom_field_custom_options_attributes_${count}_value`);
input.value = '';
dup
.querySelector('.custom-option-id')
?.remove();
const defaultValueCheckbox = dup.querySelector('input[type="checkbox"]') as HTMLInputElement;
const defaultValueHidden = dup.querySelector('input[type="hidden"]') as HTMLInputElement;
defaultValueHidden.setAttribute('name', `custom_field[custom_options_attributes][${count}][default_value]`);
defaultValueHidden.removeAttribute('id');
defaultValueCheckbox.setAttribute('name', `custom_field[custom_options_attributes][${count}][default_value]`);
defaultValueCheckbox.setAttribute('id', `custom_field_custom_options_attributes_${count}_default_value`);
defaultValueCheckbox.checked = false;
last.insertAdjacentElement('afterend', dup);
return false;
}
uncheckOtherDefaults(event:{ target:HTMLElement }) {
const cb = event.target as HTMLInputElement;
if (cb.checked && !this.multiSelectValue) {
this.customOptionDefaultsTargets.forEach((el) => (el.checked = false));
cb.checked = true;
}
}
private setupDragAndDrop() {
// Make custom fields draggable
const drake = dragula([this.dragContainerTarget], {
isContainer: () => false,
moves: (el, source, handle:HTMLElement) => handle.classList.contains('dragula-handle'),
accepts: () => true,
invalid: () => false,
direction: 'vertical',
copy: false,
copySortSource: false,
revertOnSpill: true,
removeOnSpill: false,
mirrorContainer: this.dragContainerTarget,
ignoreInputTextSelection: true,
});
// Setup autoscroll
void window.OpenProject.getPluginContext().then((pluginContext) => {
new pluginContext.classes.DomAutoscrollService(
[
document.getElementById('content-body')!,
],
{
margin: 25,
maxSpeed: 10,
scrollWhenOutside: true,
autoScroll: () => drake.dragging,
},
);
});
}
}
@@ -1,138 +0,0 @@
# frozen_string_literal: true
# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
# ++
require "spec_helper"
RSpec.describe CustomFields::DetailsComponent, type: :component do
describe ".supported?" do
context "with a bool cf" do
let(:custom_field) { build_stubbed(:boolean_wp_custom_field) }
it "is supported" do
expect(described_class).to be_supported(custom_field)
end
end
context "with a string cf" do
let(:custom_field) { build_stubbed(:string_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a text cf" do
let(:custom_field) { build_stubbed(:text_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a link cf" do
let(:custom_field) { build_stubbed(:link_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with an int cf" do
let(:custom_field) { build_stubbed(:integer_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a version cf" do
let(:custom_field) { build_stubbed(:version_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a user cf" do
let(:custom_field) { build_stubbed(:user_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a date cf" do
let(:custom_field) { build_stubbed(:date_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a list cf" do
let(:custom_field) { build_stubbed(:list_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a float cf" do
let(:custom_field) { build_stubbed(:float_wp_custom_field) }
it "is not supported" do
expect(described_class).not_to be_supported(custom_field)
end
end
context "with a calculated_value cf" do
let(:custom_field) { build_stubbed(:calculated_value_project_custom_field) }
it "is supported" do
expect(described_class).to be_supported(custom_field)
end
end
context "with a hierarchy cf" do
let(:custom_field) { build_stubbed(:hierarchy_wp_custom_field) }
it "is supported" do
expect(described_class).to be_supported(custom_field)
end
end
context "with a weighted_item_list cf" do
let(:custom_field) { build_stubbed(:weighted_item_list_wp_custom_field) }
it "is supported" do
expect(described_class).to be_supported(custom_field)
end
end
end
end