mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Merge pull request #23181 from opf/code-maintenance/74768-remove-calculated_value_project_attribute-feature-flag
[#74768] Remove calculated_value_project_attribute feature flag
This commit is contained in:
@@ -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?
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+1
-4
@@ -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) }
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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") }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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") }
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) }
|
||||
|
||||
Reference in New Issue
Block a user