diff --git a/app/contracts/custom_fields/delete_contract.rb b/app/contracts/custom_fields/delete_contract.rb index bf483055e13..3e065c8db03 100644 --- a/app/contracts/custom_fields/delete_contract.rb +++ b/app/contracts/custom_fields/delete_contract.rb @@ -53,6 +53,10 @@ module CustomFields validate :not_referenced + def validate_model? + false + end + def not_referenced referencing = model.class.with_formula_referencing(model) return if referencing.empty? diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index d14a439b0a4..c69be7e68f8 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -123,10 +123,13 @@ class CustomField < ApplicationRecord end def validate_field_format_inclusion - available = OpenProject::CustomFieldFormat.available_formats # When creating a new custom field, only the available formats are allowed. # But you can edit and update existing custom fields, even if they have a field format that is disabled. - allowed = new_record? ? available : (available + OpenProject::CustomFieldFormat.disabled_formats).uniq + allowed = if new_record? + OpenProject::CustomFieldFormat.available_formats + else + OpenProject::CustomFieldFormat.registered_formats + end unless allowed.include?(field_format) errors.add(:field_format, :inclusion) diff --git a/config/initializers/custom_field_format.rb b/config/initializers/custom_field_format.rb index 89187002d31..07a693407a2 100644 --- a/config/initializers/custom_field_format.rb +++ b/config/initializers/custom_field_format.rb @@ -28,83 +28,80 @@ # See COPYRIGHT and LICENSE files for more details. #++ -OpenProject::CustomFieldFormat.map do |fields| - fields.register OpenProject::CustomFieldFormat.new("string", - label: :label_string, - order: 1) - fields.register OpenProject::CustomFieldFormat.new("text", - label: :label_text, - order: 2, - formatter: "CustomValue::FormattableStrategy") - fields.register OpenProject::CustomFieldFormat.new("link", - label: :label_link_url, - only: %w(WorkPackage Project), - order: 3, - formatter: "CustomValue::LinkStrategy") - fields.register OpenProject::CustomFieldFormat.new("int", - label: :label_integer, - order: 4, - formatter: "CustomValue::IntStrategy") - fields.register OpenProject::CustomFieldFormat.new("float", - label: :label_float, - order: 5, - formatter: "CustomValue::FloatStrategy") - fields.register OpenProject::CustomFieldFormat.new("list", - label: :label_list, - order: 6, - multi_value_possible: true, - formatter: "CustomValue::ListStrategy") - fields.register OpenProject::CustomFieldFormat.new("date", - label: :label_date, - order: 7, - formatter: "CustomValue::DateStrategy") - fields.register OpenProject::CustomFieldFormat.new("bool", - label: :label_boolean, - order: 8, - formatter: "CustomValue::BoolStrategy") - fields.register OpenProject::CustomFieldFormat.new("user", - label: Proc.new { User.model_name.human }, - only: %w(WorkPackage TimeEntry Version Project), - edit_as: "list", - order: 9, - multi_value_possible: true, - formatter: "CustomValue::UserStrategy") - fields.register OpenProject::CustomFieldFormat.new("version", - label: Proc.new { Version.model_name.human }, - only: %w(WorkPackage TimeEntry Version Project), - edit_as: "list", - order: 10, - multi_value_possible: true, - formatter: "CustomValue::VersionStrategy") +OpenProject::CustomFieldFormat.tap do |formats| + formats.register("string", + label: :label_string, + order: 1) + formats.register("text", + label: :label_text, + order: 2, + formatter: "CustomValue::FormattableStrategy") + formats.register("link", + label: :label_link_url, + only: %w(WorkPackage Project), + order: 3, + formatter: "CustomValue::LinkStrategy") + formats.register("int", + label: :label_integer, + order: 4, + formatter: "CustomValue::IntStrategy") + formats.register("float", + label: :label_float, + order: 5, + formatter: "CustomValue::FloatStrategy") + formats.register("list", + label: :label_list, + order: 6, + multi_value_possible: true, + formatter: "CustomValue::ListStrategy") + formats.register("date", + label: :label_date, + order: 7, + formatter: "CustomValue::DateStrategy") + formats.register("bool", + label: :label_boolean, + order: 8, + formatter: "CustomValue::BoolStrategy") + formats.register("user", + label: Proc.new { User.model_name.human }, + only: %w(WorkPackage TimeEntry Version Project), + edit_as: "list", + order: 9, + multi_value_possible: true, + formatter: "CustomValue::UserStrategy") + formats.register("version", + label: Proc.new { Version.model_name.human }, + only: %w(WorkPackage TimeEntry Version Project), + edit_as: "list", + order: 10, + multi_value_possible: true, + formatter: "CustomValue::VersionStrategy") # This is an internal formatter used as a fallback in case a value is not found. # Setting the label to nil in order to avoid it becoming available for selection as a custom value format. - fields.register OpenProject::CustomFieldFormat.new("empty", - label: nil, - order: 11, - formatter: "CustomValue::EmptyStrategy") + formats.register("empty", + label: nil, + order: 11, + formatter: "CustomValue::EmptyStrategy") - fields.register OpenProject::CustomFieldFormat.new("hierarchy", - label: :label_hierarchy, - only: %w(Project WorkPackage), - order: 12, - multi_value_possible: true, - enterprise_feature: :custom_field_hierarchies, - formatter: "CustomValue::HierarchyStrategy") + formats.register("hierarchy", + label: :label_hierarchy, + only: %w(Project WorkPackage), + order: 12, + multi_value_possible: true, + enterprise_feature: :custom_field_hierarchies, + formatter: "CustomValue::HierarchyStrategy") - fields.register OpenProject::CustomFieldFormat.new("weighted_item_list", - label: :label_weighted_item_list, - only: %w(Project WorkPackage), - order: 13, - enterprise_feature: :weighted_item_lists, - formatter: "CustomValue::WeightedItemListStrategy") + formats.register("weighted_item_list", + label: :label_weighted_item_list, + only: %w(Project WorkPackage), + order: 13, + enterprise_feature: :weighted_item_lists, + formatter: "CustomValue::WeightedItemListStrategy") - fields.register OpenProject::CustomFieldFormat.new("calculated_value", - label: :label_calculated_value, - only: %w(Project), - order: 14, - enabled: lambda do - OpenProject::FeatureDecisions.calculated_value_project_attribute_active? - end, - enterprise_feature: :calculated_values, - formatter: "CustomValue::CalculatedValueStrategy") + formats.register("calculated_value", + label: :label_calculated_value, + only: %w(Project), + order: 14, + enterprise_feature: :calculated_values, + formatter: "CustomValue::CalculatedValueStrategy") end diff --git a/config/initializers/feature_decisions.rb b/config/initializers/feature_decisions.rb index 33879704458..72595aa330a 100644 --- a/config/initializers/feature_decisions.rb +++ b/config/initializers/feature_decisions.rb @@ -45,10 +45,6 @@ OpenProject::FeatureDecisions.add :built_in_oauth_applications, description: "Allows the display and use of built-in OAuth applications.", force_active: true -OpenProject::FeatureDecisions.add :calculated_value_project_attribute, - description: "Allows the use of calculated values as a project attribute.", - force_active: true - OpenProject::FeatureDecisions.add :minutes_styling_meeting_pdf, description: "Allow exporting a meeting with FITKO styling. " \ "See #65124 for details." diff --git a/lib/open_project/custom_field_format.rb b/lib/open_project/custom_field_format.rb index f17507a7f71..308e4ad09ee 100644 --- a/lib/open_project/custom_field_format.rb +++ b/lib/open_project/custom_field_format.rb @@ -82,53 +82,46 @@ module OpenProject end def for_class_name?(class_name) - @class_names.nil? || @class_names.include?(class_name) + (@class_names.nil? || @class_names.include?(class_name)) && !label.nil? end class << self - def registered = registered_by_name.values + def register(name, **) + return if registered_by_name.has_key?(name) - def map(&) - yield self - end - - # Registers a custom field format - def register(custom_field_format, _options = {}) - return if registered_by_name.has_key?(custom_field_format.name) - - registered_by_name[custom_field_format.name] = custom_field_format - end - - def available - registered.select(&:available?) - end - - def enabled - registered.select(&:enabled?) - end - - def available_formats - available.map(&:name) + registered_by_name[name] = new(name, **) + @registered = nil end def find_by(name:) registered_by_name[name.to_s] end + def registered + @registered ||= registered_by_name.values.sort_by(&:order) + end + + def available = registered.select(&:available?) + def enabled = registered.select(&:enabled?) + def disabled = registered.select(&:disabled?) + + def registered_formats = registered.map(&:name) + def available_formats = available.map(&:name) + def enabled_formats = enabled.map(&:name) + def disabled_formats = disabled.map(&:name) + def enabled_for_class_name(class_name) - enabled - .select { |format| format.for_class_name?(class_name) && !format.label.nil? } - .sort_by(&:order) + filter_for_class_name(enabled, class_name) end def available_for_class_name(class_name) - available - .select { |format| format.for_class_name?(class_name) && !format.label.nil? } - .sort_by(&:order) + filter_for_class_name(available, class_name) end - def disabled_formats - registered.select(&:disabled?).map(&:name) + private + + def filter_for_class_name(list, class_name) + list.select { |format| format.for_class_name?(class_name) } end end end diff --git a/spec/contracts/custom_fields/delete_contract_spec.rb b/spec/contracts/custom_fields/delete_contract_spec.rb index 65a5a92abd3..207fbc47a04 100644 --- a/spec/contracts/custom_fields/delete_contract_spec.rb +++ b/spec/contracts/custom_fields/delete_contract_spec.rb @@ -60,4 +60,11 @@ RSpec.describe CustomFields::DeleteContract do include_examples "contract is invalid", base: :referenced_in_other_fields end end + + describe "allows deleting a calculated_value field without an enterprise token" do + let(:current_user) { build_stubbed(:admin) } + let(:cf) { build_stubbed(:project_custom_field, field_format: "calculated_value") } + + include_examples "contract is valid" + end end diff --git a/spec/contracts/custom_fields/shared_contract_examples.rb b/spec/contracts/custom_fields/shared_contract_examples.rb index 8be282bf0ed..2018e80bc93 100644 --- a/spec/contracts/custom_fields/shared_contract_examples.rb +++ b/spec/contracts/custom_fields/shared_contract_examples.rb @@ -77,8 +77,7 @@ RSpec.shared_examples_for "custom_field contract" do end end - context "for a calculated field", with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "for a calculated field", with_ee: %i[calculated_values] do let(:custom_field_field_format) { "calculated_value" } let(:custom_field_is_required) { false } let(:custom_field_formula) { "1 + 1" } diff --git a/spec/contracts/custom_fields/update_contract_spec.rb b/spec/contracts/custom_fields/update_contract_spec.rb index f0640fc3b34..5ddda8c0a3e 100644 --- a/spec/contracts/custom_fields/update_contract_spec.rb +++ b/spec/contracts/custom_fields/update_contract_spec.rb @@ -58,8 +58,7 @@ RSpec.describe CustomFields::UpdateContract do subject(:contract) { described_class.new(custom_field, current_user) } - context "for a calculated field", with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "for a calculated field", with_ee: %i[calculated_values] do let(:custom_field_field_format) { "calculated_value" } let(:custom_field_formula) { "1 + 1" } diff --git a/spec/features/admin/custom_fields/projects/calculated_value_spec.rb b/spec/features/admin/custom_fields/projects/calculated_value_spec.rb index 61cc532108c..5b01a2b0e28 100644 --- a/spec/features/admin/custom_fields/projects/calculated_value_spec.rb +++ b/spec/features/admin/custom_fields/projects/calculated_value_spec.rb @@ -31,10 +31,7 @@ require "spec_helper" require_relative "shared_context" -RSpec.describe "Edit project custom field calculated value", - :js, - with_ee: %i[calculated_values weighted_item_lists], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe "Edit project custom field calculated value", :js, with_ee: %i[calculated_values weighted_item_lists] do include_context "with seeded project custom fields" shared_let(:weighted_item_list_project_custom_field) do diff --git a/spec/features/admin/custom_fields/projects/create_in_section_spec.rb b/spec/features/admin/custom_fields/projects/create_in_section_spec.rb index 0662dcf6c85..f0f69f07a46 100644 --- a/spec/features/admin/custom_fields/projects/create_in_section_spec.rb +++ b/spec/features/admin/custom_fields/projects/create_in_section_spec.rb @@ -128,40 +128,32 @@ RSpec.describe "Create project custom fields in sections", :js do end context "when trying to create calculated value field" do - context "without the feature flag", with_flag: { calculated_value_project_attribute: false } do - it "prevents creation" do - cf_index_page.expect_not_having_create_item "Calculated value" + before do + cf_index_page.click_to_create_new_custom_field "Calculated value" + end + + context "without calculated_values enterprise feature" do + it do + expect(page) + .to have_enterprise_banner(:premium) + .and have_no_field("custom_field_name") + .and have_no_button("Save") end end - context "with the feature flag", with_flag: { calculated_value_project_attribute: true } do - before do - cf_index_page.click_to_create_new_custom_field "Calculated value" - end + context "with calculated_values enterprise feature", with_ee: %i[calculated_values] do + it "allows creation" do + fill_in("custom_field_name", with: "New calculated value custom field") + select(section_for_select_fields.name, from: "custom_field_custom_field_section_id") + find_field(id: "custom_field_formula", type: :hidden).set("1 + 1") - context "without calculated_values enterprise feature" do - it do - expect(page) - .to have_enterprise_banner(:premium) - .and have_no_field("custom_field_name") - .and have_no_button("Save") - end - end + click_on("Save") - context "with calculated_values enterprise feature", with_ee: %i[calculated_values] do - it "allows creation" do - fill_in("custom_field_name", with: "New calculated value custom field") - select(section_for_select_fields.name, from: "custom_field_custom_field_section_id") - find_field(id: "custom_field_formula", type: :hidden).set("1 + 1") + expect(page).to have_text("Successful creation") - click_on("Save") - - expect(page).to have_text("Successful creation") - - created = ProjectCustomField.find_by_name("New calculated value custom field") - expect(page).to have_current_path(admin_settings_project_custom_field_path(created)) - expect(page).to have_text("New calculated value custom field") - end + created = ProjectCustomField.find_by_name("New calculated value custom field") + expect(page).to have_current_path(admin_settings_project_custom_field_path(created)) + expect(page).to have_text("New calculated value custom field") end end end diff --git a/spec/features/admin/custom_fields/projects/format_fields/calculated_value_spec.rb b/spec/features/admin/custom_fields/projects/format_fields/calculated_value_spec.rb index 92a01537392..864199f2b67 100644 --- a/spec/features/admin/custom_fields/projects/format_fields/calculated_value_spec.rb +++ b/spec/features/admin/custom_fields/projects/format_fields/calculated_value_spec.rb @@ -32,9 +32,7 @@ require "spec_helper" require_relative "../format_field_expectations" RSpec.describe "Project calculated value custom fields", :js do - context "with feature flag", with_flag: { calculated_value_project_attribute: true } do - context "with enterprise token", with_ee: %i[calculated_values] do - it_behaves_like "expected fields for the Project custom field's format", "Calculated value" - end + context "with enterprise token", with_ee: %i[calculated_values] do + it_behaves_like "expected fields for the Project custom field's format", "Calculated value" end end diff --git a/spec/features/admin/custom_fields/projects/index_spec.rb b/spec/features/admin/custom_fields/projects/index_spec.rb index 21d2b798da0..e184cc3647d 100644 --- a/spec/features/admin/custom_fields/projects/index_spec.rb +++ b/spec/features/admin/custom_fields/projects/index_spec.rb @@ -157,7 +157,7 @@ RSpec.describe "List project custom fields", :js do end describe "managing project custom fields" do - context "with calculated value feature flag active", with_flag: { calculated_value_project_attribute: true } do + context "with calculated value type" do it "offers the type for creation with enterprise icon" do cf_index_page.expect_having_create_item(I18n.t("label_calculated_value"), enterprise_icon: true) end @@ -188,28 +188,6 @@ RSpec.describe "List project custom fields", :js do expect(containers.last.text).to include(calculated_value_project_custom_field.name) end end - - it "lists calculated values even if the feature flag is deactivated later" do - # This spec tests that calculated values are still shown after the feature flag is deactivated. - # First, a custom field of type calculated value is created. This must be done while the feature flag is active, - # or else the model validation will fail. - # Next, we simulate that the feature flag is off: - allow(OpenProject::FeatureDecisions).to receive(:calculated_value_project_attribute_active?).and_return(false) - - # Revisit the page and check that the field is still listed: - cf_index_page.visit! - within_project_custom_field_section_container(section_for_input_fields) do - containers = page.all(".op-project-custom-field-container") - - expect(containers.last.text).to include(calculated_value_project_custom_field.name) - end - end - end - end - - context "without calculated value feature flag active" do - it "does not offer the type for creation" do - cf_index_page.expect_not_having_create_item("Calculated value") end end diff --git a/spec/features/admin/custom_fields/projects/weighted_item_lists_and_calculated_values_spec.rb b/spec/features/admin/custom_fields/projects/weighted_item_lists_and_calculated_values_spec.rb index 814b160ddb3..b056e6c2f7b 100644 --- a/spec/features/admin/custom_fields/projects/weighted_item_lists_and_calculated_values_spec.rb +++ b/spec/features/admin/custom_fields/projects/weighted_item_lists_and_calculated_values_spec.rb @@ -31,10 +31,7 @@ require "spec_helper" require_relative "shared_context" -RSpec.describe "Weighted item lists and calculated values", - :js, - with_ee: %i[calculated_values weighted_item_lists], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe "Weighted item lists and calculated values", :js, with_ee: %i[calculated_values weighted_item_lists] do current_user { create(:admin) } let!(:project) { create(:project) } diff --git a/spec/features/projects/lists/columns_spec.rb b/spec/features/projects/lists/columns_spec.rb index d18dbb12b91..048f0efe1ea 100644 --- a/spec/features/projects/lists/columns_spec.rb +++ b/spec/features/projects/lists/columns_spec.rb @@ -397,9 +397,7 @@ RSpec.describe "Projects lists columns", :js, with_settings: { login_required?: end end - context "with calculated value columns", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "with calculated value columns", with_ee: %i[calculated_values] do let!(:static_calculated_value) do create(:calculated_value_project_custom_field, name: "Calculated value field", diff --git a/spec/features/projects/lists/filters_spec.rb b/spec/features/projects/lists/filters_spec.rb index ba438f7a394..441356c85af 100644 --- a/spec/features/projects/lists/filters_spec.rb +++ b/spec/features/projects/lists/filters_spec.rb @@ -734,9 +734,7 @@ RSpec.describe "Projects list filters", :js, with_settings: { login_required?: f end end - context "when filtering via calculated values", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "when filtering via calculated values", with_ee: %i[calculated_values] do let(:projects_with_calculated_value) do [project, public_project] end diff --git a/spec/features/projects/lists/order_spec.rb b/spec/features/projects/lists/order_spec.rb index 882666128ae..c02827484bb 100644 --- a/spec/features/projects/lists/order_spec.rb +++ b/spec/features/projects/lists/order_spec.rb @@ -273,9 +273,7 @@ RSpec.describe "Projects lists ordering", :js, with_settings: { login_required?: projects_page.expect_project_at_place(project, 1) end - context "when sorting calculated value custom fields", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "when sorting calculated value custom fields", with_ee: %i[calculated_values] do let(:projects_with_calculated_value) do [project, development_project, public_project, child_project_m, child_project_a] end diff --git a/spec/features/projects/project_custom_fields/settings/mapping_spec.rb b/spec/features/projects/project_custom_fields/settings/mapping_spec.rb index 628fc538ee6..6042ee24405 100644 --- a/spec/features/projects/project_custom_fields/settings/mapping_spec.rb +++ b/spec/features/projects/project_custom_fields/settings/mapping_spec.rb @@ -521,9 +521,7 @@ RSpec.describe "Projects custom fields mapping via project settings", :js do end end - describe "calculated value fields", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated value fields", with_ee: %i[calculated_values] do let!(:admin) do create(:admin) end diff --git a/spec/forms/custom_fields/inputs/calculated_value_spec.rb b/spec/forms/custom_fields/inputs/calculated_value_spec.rb index febd07abbe5..a1d2d13f396 100644 --- a/spec/forms/custom_fields/inputs/calculated_value_spec.rb +++ b/spec/forms/custom_fields/inputs/calculated_value_spec.rb @@ -30,10 +30,7 @@ require "spec_helper" -RSpec.describe CustomFields::Inputs::CalculatedValue, - type: :forms, - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe CustomFields::Inputs::CalculatedValue, type: :forms, with_ee: %i[calculated_values] 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/forms/projects/settings/custom_fields_form_spec.rb b/spec/forms/projects/settings/custom_fields_form_spec.rb index eddd558ec48..669a3d9c86d 100644 --- a/spec/forms/projects/settings/custom_fields_form_spec.rb +++ b/spec/forms/projects/settings/custom_fields_form_spec.rb @@ -30,10 +30,7 @@ # require "spec_helper" -RSpec.describe Projects::Settings::CustomFieldsForm, - type: :forms, - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe Projects::Settings::CustomFieldsForm, type: :forms, with_ee: %i[calculated_values] do let(:string_project_custom_field) do create(:string_project_custom_field, name: "String field", is_required: true, is_for_all: true) end diff --git a/spec/lib/open_project/custom_field_format_spec.rb b/spec/lib/open_project/custom_field_format_spec.rb index 1c4954db301..074016678b1 100644 --- a/spec/lib/open_project/custom_field_format_spec.rb +++ b/spec/lib/open_project/custom_field_format_spec.rb @@ -36,23 +36,22 @@ RSpec.describe OpenProject::CustomFieldFormat do it "returns all custom field formats for the '#{class_name}' class", :aggregate_failures do formats = described_class.available_for_class_name(class_name) expect(formats).to all(be_a described_class) - expect(formats.map(&:name)).to match_array(expected_formats) + expect(formats.map(&:name)).to eq(expected_formats) end end context "for a 'Project' class" 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 + with_ee: %i[calculated_values weighted_item_lists custom_field_hierarchies] 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] + %w[string text link int float list date bool user version hierarchy weighted_item_list calculated_value] end context "without enterprise addons" do it_behaves_like "custom field formats", "Project", - %w[bool date float int link list string text user version] + %w[string text link int float list date bool user version] end end @@ -60,73 +59,38 @@ RSpec.describe OpenProject::CustomFieldFormat 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] + %w[string text link int float list date bool user version hierarchy weighted_item_list] end context "without enterprise addons" do it_behaves_like "custom field formats", "WorkPackage", - %w[bool date float int link list string text user version] + %w[string text link int float list date bool user version] end end context "for a 'Version' class" do it_behaves_like "custom field formats", "Version", - %w[bool date float int list string text user version] + %w[string text int float list date bool user version] end context "for a 'TimeEntry' class" do it_behaves_like "custom field formats", "TimeEntry", - %w[bool date float int list string text user version] + %w[string text int float list date bool user version] end context "for a 'User' class" do it_behaves_like "custom field formats", "User", - %w[bool date float int list string text] + %w[string text int float list date bool] end context "for a 'Group' class" do it_behaves_like "custom field formats", "Group", - %w[bool date float int list string text] - end - end - - describe ".available_formats" do - shared_examples_for "available custom field formats" do |suffix, expected_formats| - it "returns all custom field formats #{suffix}", :aggregate_failures do - formats = described_class.available_formats - expect(formats).to match_array(expected_formats) - end - end - - 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 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 string text user version empty] - - 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 string text user version empty] - end + %w[string text int float list date bool] end end @@ -135,36 +99,103 @@ RSpec.describe OpenProject::CustomFieldFormat do 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) + expect(formats.map(&:name)).to eq(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 + it_behaves_like "custom field formats", + "Project", + %w[string text link int float list date bool user version hierarchy weighted_item_list calculated_value] + 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] + context "for a 'WorkPackage' class" do + it_behaves_like "custom field formats", + "WorkPackage", + %w[string text link int float list date bool user version hierarchy weighted_item_list] + end + + context "for a 'Version' class" do + it_behaves_like "custom field formats", + "Version", + %w[string text int float list date bool user version] + end + + context "for a 'TimeEntry' class" do + it_behaves_like "custom field formats", + "TimeEntry", + %w[string text int float list date bool user version] + end + + context "for a 'User' class" do + it_behaves_like "custom field formats", + "User", + %w[string text int float list date bool] + end + + context "for a 'Group' class" do + it_behaves_like "custom field formats", + "Group", + %w[string text int float list date bool] + end + end + + describe ".registered_formats" do + it "returns all formats" do + expect(described_class.registered_formats) + .to eq(%w[string text link int float list date bool user version empty hierarchy weighted_item_list calculated_value]) + end + end + + describe ".available_formats" do + shared_examples_for "available custom field formats" do |suffix, expected_formats| + it "returns all custom field formats #{suffix}", :aggregate_failures do + expect(described_class.available_formats).to eq(expected_formats) end end + + context "without any ee" do + it_behaves_like "available custom field formats", + "not requiring an ee", + %w[string text link int float list date bool user version empty] + end + + context "with a custom_field_hierarchies ee", with_ee: [:custom_field_hierarchies] do + it_behaves_like "available custom field formats", + "including hierarchy", + %w[string text link int float list date bool user version empty hierarchy] + end + + context "with a weighted_item_lists ee", with_ee: [:weighted_item_lists] do + it_behaves_like "available custom field formats", + "including hierarchy", + %w[string text link int float list date bool user version empty weighted_item_list] + end + + context "with a calculated_values ee", with_ee: [:calculated_values] do + it_behaves_like "available custom field formats", + "including calculated values", + %w[string text link int float list date bool user version empty calculated_value] + end + + context "with all ees", with_ee: %i[custom_field_hierarchies weighted_item_lists calculated_values] do + it_behaves_like "available custom field formats", + "including hierarchy", + %w[string text link int float list date bool user version empty hierarchy weighted_item_list + calculated_value] + end + end + + describe ".enabled_formats" do + it "returns all formats" do + expect(described_class.enabled_formats) + .to eq(%w[string text link int float list date bool user version empty hierarchy weighted_item_list calculated_value]) + end end describe ".disabled_formats" do - it "returns disabled formats" do - formats = described_class.disabled_formats - expect(formats).to match_array(%w[calculated_value]) - end - - context "with feature flags enabled", with_flag: { calculated_value_project_attribute: true } do - it "returns no disabled formats" do - formats = described_class.disabled_formats - expect(formats).to be_empty - end + it "returns no disabled formats" do + expect(described_class.disabled_formats).to be_empty end end end diff --git a/spec/migrations/set_is_for_all_and_unset_required_spec.rb b/spec/migrations/set_is_for_all_and_unset_required_spec.rb index 61b874fe19d..cce86f05e4d 100644 --- a/spec/migrations/set_is_for_all_and_unset_required_spec.rb +++ b/spec/migrations/set_is_for_all_and_unset_required_spec.rb @@ -31,9 +31,7 @@ require "spec_helper" require Rails.root.join("db/migrate/20251211160744_set_is_for_all_and_unset_required") -RSpec.describe SetIsForAllAndUnsetRequired, type: :model, - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe SetIsForAllAndUnsetRequired, type: :model, with_ee: %i[calculated_values] do # Project custom fields to be migrated shared_let(:required_project_cf) { create(:project_custom_field, :integer, is_required: true, is_for_all: false) } shared_let(:optional_project_cf) { create(:project_custom_field, :integer, is_required: false, is_for_all: false) } diff --git a/spec/models/acts_as_customizable/calculated_value_spec.rb b/spec/models/acts_as_customizable/calculated_value_spec.rb index 5665de7ecd5..1ccf371be4b 100644 --- a/spec/models/acts_as_customizable/calculated_value_spec.rb +++ b/spec/models/acts_as_customizable/calculated_value_spec.rb @@ -30,9 +30,7 @@ require "spec_helper" -RSpec.describe ActsAsCustomizable::CalculatedValue, - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe ActsAsCustomizable::CalculatedValue, with_ee: %i[calculated_values] 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 d8b8ff133c4..3f0af57f080 100644 --- a/spec/models/custom_field/calculated_value_spec.rb +++ b/spec/models/custom_field/calculated_value_spec.rb @@ -30,9 +30,7 @@ require "spec_helper" -RSpec.describe CustomField::CalculatedValue, - with_ee: %i[calculated_values weighted_item_lists], - with_flag: { calculated_value_project_attribute: true } do +RSpec.describe CustomField::CalculatedValue, with_ee: %i[calculated_values weighted_item_lists] do using CustomFieldFormulaReferencing subject(:custom_field) { create(:calculated_value_project_custom_field, formula: "1 + 1") } diff --git a/spec/models/projects/customizable_spec.rb b/spec/models/projects/customizable_spec.rb index a83a690f2ce..bc3d53495d5 100644 --- a/spec/models/projects/customizable_spec.rb +++ b/spec/models/projects/customizable_spec.rb @@ -204,9 +204,7 @@ RSpec.describe Project, "customizable" do .to contain_exactly(text_custom_field, bool_custom_field) end - describe "#valid?", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "#valid?", with_ee: %i[calculated_values] do let(:another_section) { create(:project_custom_field_section) } let(:project) do build(:project, custom_field_values: { @@ -377,9 +375,7 @@ RSpec.describe Project, "customizable" do .to eq("bar") end - describe "#valid?", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "#valid?", with_ee: %i[calculated_values] do let!(:project) do create(:project, custom_field_values: { text_custom_field.id => "foo", diff --git a/spec/services/custom_fields/create_service_spec.rb b/spec/services/custom_fields/create_service_spec.rb index 97e468aa621..ae7af1e144b 100644 --- a/spec/services/custom_fields/create_service_spec.rb +++ b/spec/services/custom_fields/create_service_spec.rb @@ -62,9 +62,7 @@ RSpec.describe CustomFields::CreateService, type: :model do subject(:instance_call) { instance.call(attributes) } - describe "calculated value custom field", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated value custom field", with_ee: %i[calculated_values] 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 6f503384457..a54a1daaf87 100644 --- a/spec/services/custom_fields/hierarchy/hierarchical_item_service_spec.rb +++ b/spec/services/custom_fields/hierarchy/hierarchical_item_service_spec.rb @@ -430,9 +430,7 @@ RSpec.describe CustomFields::Hierarchy::HierarchicalItemService, with_ee: [:cust end end - context "with weighted item list and calculated values", - with_ee: %i[calculated_values weighted_item_lists], - with_flag: { calculated_value_project_attribute: true } do + context "with weighted item list and calculated values", with_ee: %i[calculated_values weighted_item_lists] 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 3be512e1964..53ed53d6ad9 100644 --- a/spec/services/custom_fields/update_service_spec.rb +++ b/spec/services/custom_fields/update_service_spec.rb @@ -65,9 +65,7 @@ RSpec.describe CustomFields::UpdateService, type: :model do end end - describe "calculated value custom field", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated value custom field", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing context "when updating not a calculated value" do diff --git a/spec/services/project_custom_field_project_mappings/bulk_create_service_spec.rb b/spec/services/project_custom_field_project_mappings/bulk_create_service_spec.rb index 280352dfe7c..fb0c1a3e628 100644 --- a/spec/services/project_custom_field_project_mappings/bulk_create_service_spec.rb +++ b/spec/services/project_custom_field_project_mappings/bulk_create_service_spec.rb @@ -41,9 +41,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::BulkCreateService do let(:required_permission) { :select_project_custom_fields } end - describe "calculated values", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated values", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing shared_let(:user) { create(:admin) } diff --git a/spec/services/project_custom_field_project_mappings/bulk_update_service_spec.rb b/spec/services/project_custom_field_project_mappings/bulk_update_service_spec.rb index 0387eeb7177..40d97dec742 100644 --- a/spec/services/project_custom_field_project_mappings/bulk_update_service_spec.rb +++ b/spec/services/project_custom_field_project_mappings/bulk_update_service_spec.rb @@ -190,9 +190,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::BulkUpdateService do end end - describe "calculated values", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated values", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing shared_let(:user) { create(:admin) } diff --git a/spec/services/project_custom_field_project_mappings/delete_service_spec.rb b/spec/services/project_custom_field_project_mappings/delete_service_spec.rb index 115fb30052c..c7540849e40 100644 --- a/spec/services/project_custom_field_project_mappings/delete_service_spec.rb +++ b/spec/services/project_custom_field_project_mappings/delete_service_spec.rb @@ -39,9 +39,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::DeleteService do end end - describe "calculated values", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated values", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing shared_let(:user) { create(:admin) } diff --git a/spec/services/project_custom_field_project_mappings/toggle_service_spec.rb b/spec/services/project_custom_field_project_mappings/toggle_service_spec.rb index cfe3745fda5..a817da0a990 100644 --- a/spec/services/project_custom_field_project_mappings/toggle_service_spec.rb +++ b/spec/services/project_custom_field_project_mappings/toggle_service_spec.rb @@ -246,9 +246,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::ToggleService do end end - describe "calculated values", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated values", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing shared_let(:user) { create(:admin) } diff --git a/spec/services/projects/copy_service_integration_spec.rb b/spec/services/projects/copy_service_integration_spec.rb index 49756ac0317..b352c75320d 100644 --- a/spec/services/projects/copy_service_integration_spec.rb +++ b/spec/services/projects/copy_service_integration_spec.rb @@ -267,9 +267,7 @@ RSpec.describe( end end - context "with calculated custom fields", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "with calculated custom fields", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing let(:integer_custom_field) { create(:integer_project_custom_field, projects: [source]) } let(:calculated_custom_field) do @@ -315,9 +313,7 @@ RSpec.describe( expect(calculated_cv.value).to eq "16" end - context "with calculation errors", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "with calculation errors", with_ee: %i[calculated_values] do let(:calculated_custom_field) do create(:calculated_value_project_custom_field, :skip_validations, projects: [source], diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 241f06a5574..eae61e8b7b0 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -169,9 +169,7 @@ RSpec.describe Projects::CreateService, type: :model do end end - context "with for_all custom fields", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + context "with for_all custom fields", with_ee: %i[calculated_values] do let!(:calculated_custom_field) do create(:calculated_value_project_custom_field, project_custom_field_section: section) @@ -230,9 +228,7 @@ RSpec.describe Projects::CreateService, type: :model do end end - describe "calculated custom fields", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated custom fields", with_ee: %i[calculated_values] do shared_let(:cf_static) { create(:integer_project_custom_field, is_for_all: true) } let(:project) { create(:project) } let!(:model_instance) { project } diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index f40b8c418ce..1d70bca3a9c 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -82,9 +82,7 @@ RSpec.describe Projects::UpdateService, type: :model do end end - describe "calculated custom fields", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "calculated custom fields", with_ee: %i[calculated_values] do let(:project) { create(:project) } let!(:model_instance) { project } # Remove the set_attributes_service mocking to use the real service. diff --git a/spec/support/flash/expectations.rb b/spec/support/flash/expectations.rb index 98f295b7cf3..5521c8ba189 100644 --- a/spec/support/flash/expectations.rb +++ b/spec/support/flash/expectations.rb @@ -24,7 +24,7 @@ module Flash def expect_no_flash(type: :success, message: nil, exact_message: nil, wait: 10) if type.nil? - expect(page).not_to have_test_selector("op-primer-flash-message") + expect(page).to have_no_test_selector("op-primer-flash-message") else expected_css = expected_flash_css(type) expect(page).to have_no_css(expected_css, wait:, **{ text: message, exact_text: exact_message }.compact) diff --git a/spec/workers/custom_fields/recalculate_values_job_spec.rb b/spec/workers/custom_fields/recalculate_values_job_spec.rb index d9672d6baa6..e8f1cb6a1ff 100644 --- a/spec/workers/custom_fields/recalculate_values_job_spec.rb +++ b/spec/workers/custom_fields/recalculate_values_job_spec.rb @@ -31,9 +31,7 @@ require "spec_helper" RSpec.describe CustomFields::RecalculateValuesJob, type: :model do - describe "#perform", - with_ee: %i[calculated_values], - with_flag: { calculated_value_project_attribute: true } do + describe "#perform", with_ee: %i[calculated_values] do using CustomFieldFormulaReferencing shared_let(:user) { create(:admin) }