diff --git a/app/assets/images/enterprise/hierarchies.png b/app/assets/images/enterprise/hierarchies.png new file mode 100644 index 00000000000..b6fc29b1a74 Binary files /dev/null and b/app/assets/images/enterprise/hierarchies.png differ diff --git a/app/assets/images/enterprise/weighted_item_lists.png b/app/assets/images/enterprise/weighted_item_lists.png new file mode 100644 index 00000000000..afc8289e523 Binary files /dev/null and b/app/assets/images/enterprise/weighted_item_lists.png differ diff --git a/app/components/custom_fields/details_component.rb b/app/components/custom_fields/details_component.rb index d18942ddef6..a9e0beefaba 100644 --- a/app/components/custom_fields/details_component.rb +++ b/app/components/custom_fields/details_component.rb @@ -55,9 +55,9 @@ module CustomFields def enterprise_addon @enterprise_addon ||= case custom_field.field_format when "hierarchy" - { key: :custom_field_hierarchies, image: "enterprise/homescreen.png" } + { key: :custom_field_hierarchies, image: "enterprise/hierarchies.png" } when "weighted_item_list" - { key: :weighted_item_lists, image: "enterprise/homescreen.png" } + { key: :weighted_item_lists, image: "enterprise/weighted_item_lists.png" } else {} end diff --git a/spec/contracts/custom_fields/hierarchy/generate_root_contract_spec.rb b/spec/contracts/custom_fields/hierarchy/generate_root_contract_spec.rb index 4c215a3353b..f792cd7de1b 100644 --- a/spec/contracts/custom_fields/hierarchy/generate_root_contract_spec.rb +++ b/spec/contracts/custom_fields/hierarchy/generate_root_contract_spec.rb @@ -64,7 +64,7 @@ RSpec.describe CustomFields::Hierarchy::GenerateRootContract, with_ee: [:custom_ end end - context "when inputs are valid" do + context "when inputs are valid", with_ee: %i[weighted_item_lists] do let(:custom_field) { create(:weighted_item_list_wp_custom_field, hierarchy_root: nil) } it "creates a success result" do diff --git a/spec/contracts/custom_fields/hierarchy/insert_weighted_item_contract_spec.rb b/spec/contracts/custom_fields/hierarchy/insert_weighted_item_contract_spec.rb index 948f79c9bd6..9aafa92c2aa 100644 --- a/spec/contracts/custom_fields/hierarchy/insert_weighted_item_contract_spec.rb +++ b/spec/contracts/custom_fields/hierarchy/insert_weighted_item_contract_spec.rb @@ -38,7 +38,7 @@ RSpec.describe CustomFields::Hierarchy::InsertWeightedItemContract do let(:parent) { create(:hierarchy_item) } context "when all required fields are valid" do - let(:params) { { parent:, label: "Valid Label", score: 0.1337 } } + let(:params) { { parent:, label: "Valid Label", weight: 0.1337 } } it "is valid" do result = subject.call(params) @@ -47,13 +47,13 @@ RSpec.describe CustomFields::Hierarchy::InsertWeightedItemContract do end context "when inputs are empty" do - let(:params) { { parent:, label: "", score: "" } } + let(:params) { { parent:, label: "", weight: "" } } it "is invalid" do result = subject.call(params) expect(result).to be_failure expect(result.errors.to_h).to include(label: ["must be filled."]) - expect(result.errors.to_h).to include(score: ["must be filled."]) + expect(result.errors.to_h).to include(weight: ["must be filled."]) end end @@ -64,13 +64,13 @@ RSpec.describe CustomFields::Hierarchy::InsertWeightedItemContract do result = subject.call(params) expect(result).to be_failure expect(result.errors.to_h).to include(label: ["is missing."]) - expect(result.errors.to_h).to include(score: ["is missing."]) + expect(result.errors.to_h).to include(weight: ["is missing."]) end end context "when parent is not of type 'Item'" do let(:invalid_parent) { create(:custom_field) } - let(:params) { { parent: invalid_parent, label: "Valid Label", score: 0.1337 } } + let(:params) { { parent: invalid_parent, label: "Valid Label", weight: 0.1337 } } it "is invalid" do result = subject.call(params) @@ -80,9 +80,9 @@ RSpec.describe CustomFields::Hierarchy::InsertWeightedItemContract do end context "when label is not unique within the same hierarchy level" do - let(:params) { { parent:, label: "Duplicate Label", score: 0.1337 } } + let(:params) { { parent:, label: "Duplicate Label", weight: 0.1337 } } - before { create(:hierarchy_item, parent:, label: "Duplicate Label", score: 0.1337) } + before { create(:hierarchy_item, parent:, label: "Duplicate Label", weight: 0.1337) } it "is invalid" do result = subject.call(params) @@ -117,21 +117,21 @@ RSpec.describe CustomFields::Hierarchy::InsertWeightedItemContract do end end - context "when score is not a decimal value" do - let(:params) { { parent:, label: "Valid Label", score: "pi" } } + context "when weight is not a decimal value" do + let(:params) { { parent:, label: "Valid Label", weight: "pi" } } it "is invalid with localized validation errors" do result = subject.call(params) expect(result).to be_failure - expect(result.errors.to_h).to include(score: ["must be a decimal."]) + expect(result.errors.to_h).to include(weight: ["must be a decimal."]) end end context "when inputs are valid" do it "creates a success result" do [ - { parent:, label: "A label", score: 0.1337 }, - { parent:, label: "Another label", score: 1.47e12 } + { parent:, label: "A label", weight: 0.1337 }, + { parent:, label: "Another label", weight: 1.47e12 } ].each { |params| expect(subject.call(params)).to be_success } end end @@ -139,15 +139,15 @@ RSpec.describe CustomFields::Hierarchy::InsertWeightedItemContract do context "when inputs are invalid" do it "creates a failure result" do [ - { parent:, label: "A label", score: "" }, - { parent:, label: "A label", score: nil }, - { parent:, label: "", score: 1.47e12 }, - { parent:, label: nil, score: 1.47e12 }, + { parent:, label: "A label", weight: "" }, + { parent:, label: "A label", weight: nil }, + { parent:, label: "", weight: 1.47e12 }, + { parent:, label: nil, weight: 1.47e12 }, { parent: }, { parent: nil }, - { parent: nil, label: "A label", score: 1.47e12 }, - { parent: "parent", label: "A label", score: 1.47e12 }, - { parent: 42, label: "A label", score: 1.47e12 } + { parent: nil, label: "A label", weight: 1.47e12 }, + { parent: "parent", label: "A label", weight: 1.47e12 }, + { parent: 42, label: "A label", weight: 1.47e12 } ].each { |params| expect(subject.call(params)).to be_failure } end end diff --git a/spec/contracts/custom_fields/hierarchy/update_weighted_item_contract_spec.rb b/spec/contracts/custom_fields/hierarchy/update_weighted_item_contract_spec.rb index d1069c3c612..7e9cf651e8a 100644 --- a/spec/contracts/custom_fields/hierarchy/update_weighted_item_contract_spec.rb +++ b/spec/contracts/custom_fields/hierarchy/update_weighted_item_contract_spec.rb @@ -36,15 +36,15 @@ RSpec.describe CustomFields::Hierarchy::UpdateWeightedItemContract do # rubocop:disable Rails/DeprecatedActiveModelErrorsMethods describe "#call" do let!(:impact) { create(:hierarchy_item) } - let!(:high) { create(:hierarchy_item, label: "HIGH", score: 1.17e-12, parent: impact) } - let!(:middle) { create(:hierarchy_item, label: "Middle", score: 1, parent: impact) } - let!(:low) { create(:hierarchy_item, label: "low", score: 9.81e6, parent: impact) } + let!(:high) { create(:hierarchy_item, label: "HIGH", weight: 1.17e-12, parent: impact) } + let!(:middle) { create(:hierarchy_item, label: "Middle", weight: 1, parent: impact) } + let!(:low) { create(:hierarchy_item, label: "low", weight: 9.81e6, parent: impact) } context "when all required fields are valid" do it "is valid" do [ - { item: high, label: "VERY HIGH", score: 1.17e-12 }, - { item: high, label: "HIGH", score: 1.17e-11 } + { item: high, label: "VERY HIGH", weight: 1.17e-12 }, + { item: high, label: "HIGH", weight: 1.17e-11 } ].each { |params| expect(subject.call(params)).to be_success } end end @@ -98,12 +98,12 @@ RSpec.describe CustomFields::Hierarchy::UpdateWeightedItemContract do {}, { item: nil }, { item: high, label: 42 }, - { item: high, score: "pi" }, - { item: high, label: nil, score: 4 }, - { item: high, label: "pi", score: nil }, - { item: high, label: "pi", score: "threepointonefour" }, - { item: high, label: 42, score: 4 }, - { item: high, label: "", score: 4 } + { item: high, weight: "pi" }, + { item: high, label: nil, weight: 4 }, + { item: high, label: "pi", weight: nil }, + { item: high, label: "pi", weight: "threepointonefour" }, + { item: high, label: 42, weight: 4 }, + { item: high, label: "", weight: 4 } ].each { |params| expect(subject.call(params)).to be_failure } end end diff --git a/spec/forms/custom_fields/inputs/calculated_value_spec.rb b/spec/forms/custom_fields/inputs/calculated_value_spec.rb index 7c8dd9f50ac..febd07abbe5 100644 --- a/spec/forms/custom_fields/inputs/calculated_value_spec.rb +++ b/spec/forms/custom_fields/inputs/calculated_value_spec.rb @@ -30,7 +30,10 @@ require "spec_helper" -RSpec.describe CustomFields::Inputs::CalculatedValue, type: :forms, with_flag: { calculated_value_project_attribute: true } do +RSpec.describe CustomFields::Inputs::CalculatedValue, + type: :forms, + with_ee: %i[calculated_values], + with_flag: { calculated_value_project_attribute: true } do include_context "with rendered custom field input form" let(:custom_field) { create(:calculated_value_project_custom_field, name: "Calculated value field", formula: "1 + 1") } diff --git a/spec/lib/api/v3/utilities/custom_field_injector_spec.rb b/spec/lib/api/v3/utilities/custom_field_injector_spec.rb index 1cbce0ee54a..f436303224e 100644 --- a/spec/lib/api/v3/utilities/custom_field_injector_spec.rb +++ b/spec/lib/api/v3/utilities/custom_field_injector_spec.rb @@ -296,7 +296,7 @@ RSpec.describe API::V3::Utilities::CustomFieldInjector do { hierarchy: { with_ee: [:custom_field_hierarchies] }, - weighted_item_list: {} + weighted_item_list: { with_ee: [:weighted_item_lists] } }.each do |format, tags| describe "#{format} custom field", **tags do let(:custom_field) do diff --git a/spec/lib/api/v3/work_packages/work_package_representer_spec.rb b/spec/lib/api/v3/work_packages/work_package_representer_spec.rb index 6dbac33720a..13d684a35fa 100644 --- a/spec/lib/api/v3/work_packages/work_package_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_representer_spec.rb @@ -1252,7 +1252,7 @@ RSpec.describe API::V3::WorkPackages::WorkPackageRepresenter do .insert_item(contract_class:, parent: custom_field.hierarchy_root, label: "TIE Fighter", weight: 16.7) .value! end - let(:value) { wighted_item.id } + let(:value) { weighted_item.id } it_behaves_like "has a titled link" do let(:link) { "customField#{custom_field.id}" } diff --git a/spec/lib/open_project/custom_field_format_spec.rb b/spec/lib/open_project/custom_field_format_spec.rb index ab2d4aee00a..1c4954db301 100644 --- a/spec/lib/open_project/custom_field_format_spec.rb +++ b/spec/lib/open_project/custom_field_format_spec.rb @@ -41,30 +41,32 @@ RSpec.describe OpenProject::CustomFieldFormat do end context "for a 'Project' class" do - context "with calculated values feature flag enabled", with_flag: { calculated_value_project_attribute: true } do + context "with some enterprise addons", + with_ee: %i[calculated_values weighted_item_lists custom_field_hierarchies], + with_flag: { calculated_value_project_attribute: true } do it_behaves_like "custom field formats", "Project", - %w[bool calculated_value date float int link list weighted_item_list string text user version] + %w[bool calculated_value date float hierarchy int link list string text user version weighted_item_list] end - context "with calculated values feature flag disabled" do + context "without enterprise addons" do it_behaves_like "custom field formats", "Project", - %w[bool date float int link list weighted_item_list string text user version] + %w[bool date float int link list string text user version] end end context "for a 'WorkPackage' class" do - context "with a custom_field_hierarchies ee", with_ee: [:custom_field_hierarchies] do + context "with some enterprise addons", with_ee: %i[weighted_item_lists custom_field_hierarchies] do it_behaves_like "custom field formats", "WorkPackage", %w[bool date float hierarchy int link list weighted_item_list string text user version] end - context "without a custom_field_hierarchies ee" do + context "without enterprise addons" do it_behaves_like "custom field formats", "WorkPackage", - %w[bool date float int link list weighted_item_list string text user version] + %w[bool date float int link list string text user version] end end @@ -104,18 +106,50 @@ RSpec.describe OpenProject::CustomFieldFormat do context "with a custom_field_hierarchies ee", with_ee: [:custom_field_hierarchies] do it_behaves_like "available custom field formats", "including hierarchy", - %w[bool date float hierarchy int link list weighted_item_list string text user version empty] + %w[bool date float hierarchy int link list string text user version empty] + end + + context "with a weighted item lists ee", with_ee: [:weighted_item_lists] do + it_behaves_like "available custom field formats", + "including hierarchy", + %w[bool date float int link list string text user version weighted_item_list empty] end context "without a custom_field_hierarchies ee" do it_behaves_like "available custom field formats", "excluding hierarchy", - %w[bool date float int link list weighted_item_list string text user version empty] + %w[bool date float int link list string text user version empty] - context "with calculated values feature flag enabled", with_flag: { calculated_value_project_attribute: true } do + context "with a calculated values ee", + with_ee: [:calculated_values], + with_flag: { calculated_value_project_attribute: true } do it_behaves_like "available custom field formats", "including calculated values", - %w[bool calculated_value date float int link list weighted_item_list string text user version empty] + %w[bool calculated_value date float int link list string text user version empty] + end + end + end + + describe ".enabled_for_class_name" do + shared_examples_for "custom field formats" do |class_name, expected_formats| + it "returns all custom field formats for the '#{class_name}' class", :aggregate_failures do + formats = described_class.enabled_for_class_name(class_name) + expect(formats).to all(be_a described_class) + expect(formats.map(&:name)).to match_array(expected_formats) + end + end + + context "for a 'Project' class" do + context "with feature flags enabled", with_flag: { calculated_value_project_attribute: true } do + it_behaves_like "custom field formats", + "Project", + %w[bool calculated_value date float hierarchy int link list string text user version weighted_item_list] + end + + context "with no feature flags enabled", with_flag: {} do + it_behaves_like "custom field formats", + "Project", + %w[bool date float hierarchy int link list string text user version weighted_item_list] end end end diff --git a/spec/models/acts_as_customizable/calculated_value_spec.rb b/spec/models/acts_as_customizable/calculated_value_spec.rb index 854ac3da095..5665de7ecd5 100644 --- a/spec/models/acts_as_customizable/calculated_value_spec.rb +++ b/spec/models/acts_as_customizable/calculated_value_spec.rb @@ -30,7 +30,9 @@ require "spec_helper" -RSpec.describe ActsAsCustomizable::CalculatedValue, with_flag: { calculated_value_project_attribute: true } do +RSpec.describe ActsAsCustomizable::CalculatedValue, + with_ee: %i[calculated_values], + with_flag: { calculated_value_project_attribute: true } do using CustomFieldFormulaReferencing include CalculatedValues::ErrorsHelper diff --git a/spec/models/custom_field/calculated_value_spec.rb b/spec/models/custom_field/calculated_value_spec.rb index 4f6a98027c2..22f1f2cfce1 100644 --- a/spec/models/custom_field/calculated_value_spec.rb +++ b/spec/models/custom_field/calculated_value_spec.rb @@ -30,7 +30,9 @@ require "spec_helper" -RSpec.describe CustomField::CalculatedValue, with_flag: { calculated_value_project_attribute: true } do +RSpec.describe CustomField::CalculatedValue, + with_ee: %i[calculated_values weighted_item_lists], + with_flag: { calculated_value_project_attribute: true } do using CustomFieldFormulaReferencing subject(:custom_field) { create(:calculated_value_project_custom_field, formula: "1 + 1") } diff --git a/spec/services/custom_fields/create_service_spec.rb b/spec/services/custom_fields/create_service_spec.rb index 060408be3b1..ab3f0cd9db6 100644 --- a/spec/services/custom_fields/create_service_spec.rb +++ b/spec/services/custom_fields/create_service_spec.rb @@ -60,7 +60,9 @@ RSpec.describe CustomFields::CreateService, type: :model do .to receive(:new).with(instance_of(ProjectCustomField), user, options: {}).and_return(contract_instance) end - describe "calculated value custom field", with_flag: { calculated_value_project_attribute: true } do + describe "calculated value custom field", + with_ee: %i[calculated_values], + with_flag: { calculated_value_project_attribute: true } do using CustomFieldFormulaReferencing shared_let(:project_custom_field_section) { create(:project_custom_field_section) } diff --git a/spec/services/custom_fields/hierarchy/hierarchical_item_service_spec.rb b/spec/services/custom_fields/hierarchy/hierarchical_item_service_spec.rb index 40ff3fd8638..36ea37c810a 100644 --- a/spec/services/custom_fields/hierarchy/hierarchical_item_service_spec.rb +++ b/spec/services/custom_fields/hierarchy/hierarchical_item_service_spec.rb @@ -331,7 +331,9 @@ RSpec.describe CustomFields::Hierarchy::HierarchicalItemService, with_ee: [:cust end end - context "with weighted item list and calculated values", with_flag: { calculated_value_project_attribute: true } do + context "with weighted item list and calculated values", + with_ee: %i[calculated_values weighted_item_lists], + with_flag: { calculated_value_project_attribute: true } do current_user { create(:admin) } let!(:project_using_one) { create(:project) } diff --git a/spec/services/custom_fields/update_service_spec.rb b/spec/services/custom_fields/update_service_spec.rb index ba68eda118d..5c07aede449 100644 --- a/spec/services/custom_fields/update_service_spec.rb +++ b/spec/services/custom_fields/update_service_spec.rb @@ -65,7 +65,9 @@ RSpec.describe CustomFields::UpdateService, type: :model do end end - describe "calculated value custom field", with_flag: { calculated_value_project_attribute: true } do + describe "calculated value custom field", + with_ee: %i[calculated_values], + with_flag: { calculated_value_project_attribute: true } do using CustomFieldFormulaReferencing shared_let(:project1) { create(:project) } diff --git a/spec/services/projects/set_attributes_service_spec.rb b/spec/services/projects/set_attributes_service_spec.rb index 94e9050a389..6a5db0bf0ff 100644 --- a/spec/services/projects/set_attributes_service_spec.rb +++ b/spec/services/projects/set_attributes_service_spec.rb @@ -311,7 +311,9 @@ RSpec.describe Projects::SetAttributesService, type: :model do end end - describe "calculated custom fields", with_flag: { calculated_value_project_attribute: true } do + describe "calculated custom fields", + with_ee: %i[calculated_values], + with_flag: { calculated_value_project_attribute: true } do shared_let(:project) { create(:project) } before do