diff --git a/app/services/grids/copy/widgets_dependent_service.rb b/app/services/grids/copy/widgets_dependent_service.rb index cad66938e846..23245e435d60 100644 --- a/app/services/grids/copy/widgets_dependent_service.rb +++ b/app/services/grids/copy/widgets_dependent_service.rb @@ -108,11 +108,11 @@ def map_query_id(query_id, params) end def map_query_filters(filters, _params) - ::Queries::Copy::FiltersMapper - .new(state, filters) - .map_filters! + result = ::Queries::Copy::FiltersMapper + .new(state) + .map_filters(filters) - ServiceResult.success result: filters + ServiceResult.success(result:) end def duplicate_query(query_id, params) diff --git a/app/services/queries/copy/filters_mapper.rb b/app/services/queries/copy/filters_mapper.rb index e8134b402634..b783122aba30 100644 --- a/app/services/queries/copy/filters_mapper.rb +++ b/app/services/queries/copy/filters_mapper.rb @@ -28,26 +28,28 @@ module Queries::Copy class FiltersMapper - attr_reader :state, :filters, :mappers + attr_reader :state, :mappers - def initialize(state, filters) + def initialize(state) @state = state - @filters = filters @mappers = build_filter_mappers end ## - # Returns the mapped filter array for either - # hash-based APIv3 filters or filter clasess - def map_filters! + # Returns the mapped filter array for + # an array of hash-based APIv3 filters + def map_filters(filters) filters.map do |input| - if input.is_a?(Hash) - filter = input.dup.with_indifferent_access - filter.tap(&method(:map_api_filter_hash)) - else - map_filter_class(input) - input - end + filter = input.dup.with_indifferent_access + map_api_filter_hash(filter) + end + end + + ## + # Maps the given query instance + def map_query!(query) + query.filters.each do |filter| + filter.values = mapped_values(filter.name, filter.values) end end @@ -63,10 +65,8 @@ def map_api_filter_hash(filter) ar_name = ::API::Utilities::QueryFiltersNameConverter.to_ar_name(name, refer_to_ids: true) subhash["values"] = mapped_values(ar_name, subhash["values"]) - end - def map_filter_class(filter) - filter.values = mapped_values(filter.name, filter.values) + filter end def mapped_values(ar_name, values) diff --git a/app/services/queries/copy_service.rb b/app/services/queries/copy_service.rb index 7006aca75f90..49e821a3c2cc 100644 --- a/app/services/queries/copy_service.rb +++ b/app/services/queries/copy_service.rb @@ -42,8 +42,8 @@ def set_attributes(_params) new_query.sort_criteria = source.sort_criteria if source.sort_criteria ::Queries::Copy::FiltersMapper - .new(state, new_query.filters) - .map_filters! + .new(state) + .map_query!(new_query) ServiceResult.new(success: new_query.valid?, result: new_query) end diff --git a/modules/boards/app/services/boards/copy_service.rb b/modules/boards/app/services/boards/copy_service.rb index 956d9e982dcd..ae180cb02e97 100644 --- a/modules/boards/app/services/boards/copy_service.rb +++ b/modules/boards/app/services/boards/copy_service.rb @@ -31,8 +31,23 @@ class CopyService < ::Grids::CopyService protected def set_attributes_params(params) - super - .merge(project: state.project || model.project) + super.deep_symbolize_keys.tap do |hash| + hash[:project] = state.project || model.project + + hash[:options] = mapped_options(hash[:options]) if hash.key?(:options) + end + end + + def mapped_options(options) + options[:filters] = mapped_filters(options[:filters]) if options.key?(:filters) + + options + end + + def mapped_filters(filters) + ::Queries::Copy::FiltersMapper + .new(state) + .map_filters(filters) end end end diff --git a/modules/boards/spec/factories/board_factory.rb b/modules/boards/spec/factories/board_factory.rb index a01ac756fa1c..849e94c64dee 100644 --- a/modules/boards/spec/factories/board_factory.rb +++ b/modules/boards/spec/factories/board_factory.rb @@ -100,4 +100,38 @@ board.save! end end + + factory :version_board, class: "Boards::Grid" do + project + name { "My version board" } + row_count { 1 } + column_count { 4 } + + transient do + version_columns { [create(:version, project:)] } + end + + callback(:after_create) do |board, evaluator| + evaluator.version_columns.each do |version| + query = build(:public_query, name: version.name, project: board.project).tap do |q| + q.sort_criteria = [[:manual_sorting, "asc"]] + q.save! + end + + filters = [{ "version_id" => { "operator" => "=", "values" => [version.id.to_s] } }] + + board.widgets << create(:grid_widget, + identifier: "work_package_query", + start_row: 1, + end_row: 2, + start_column: 1, + end_column: 1, + options: { "queryId" => query.id, + "filters" => filters }) + end + + board.options = { "type" => "action", "attribute" => "version" } + board.save! + end + end end diff --git a/modules/boards/spec/services/copy_service_integration_spec.rb b/modules/boards/spec/services/copy_service_integration_spec.rb index 51ce28eecff9..e2f387b90313 100644 --- a/modules/boards/spec/services/copy_service_integration_spec.rb +++ b/modules/boards/spec/services/copy_service_integration_spec.rb @@ -90,6 +90,68 @@ end end + describe "for a version board" do + let(:current_user) do + create(:user, member_with_roles: { source => role }) + end + let!(:version) { create(:version, project: source) } + let!(:board_view) do + create(:version_board, project: source, version_columns: [version]) + end + let(:only_args) { %w[work_packages boards versions] } + + before do + login_as current_user + end + + it "succeeds to copy the version column" do + expect(subject).to be_success + expect(board_copies.count).to eq 1 + + expect(board_view.widgets.count).to eq(1) + expect(board_copy.widgets.count).to eq(1) + + widget_source = board_view.widgets.first.options + widget_copy = board_copy.widgets.first.options + + filter_source = widget_source["filters"].first["version_id"] + filter_copy = widget_copy["filters"].first["version_id"] + + expect(widget_source["queryId"]).not_to eq(widget_copy["queryId"]) + expect(filter_source["values"]).to eq [version.id.to_s] + + copied_version = project_copy.versions.first + expect(filter_copy["values"]).to eq [copied_version.id.to_s] + end + end + + describe "for a board filtered by version" do + let(:current_user) do + create(:user, member_with_roles: { source => role }) + end + let!(:version) { create(:version, project: source) } + let!(:board_view) do + create(:board_grid, project: source) + end + let(:only_args) { %w[work_packages boards versions] } + + before do + board_view.update! options: { + filters: [{ version: { operator: "=", values: [version.id.to_s] } }] + } + login_as current_user + end + + it "maps the filters in the board options" do + expect(subject).to be_success + expect(board_copies.count).to eq 1 + + version_filter = board_copy.options[:filters].first[:version] + copied_version = project_copy.versions.first + expect(version_filter[:values]).to eq [copied_version.id.to_s] + end + end + describe "for ordered work packages" do let!(:board_view) { create(:board_grid_with_query, project: source, name: "My Board") } let!(:wp_1) { create(:work_package, project: source, subject: "Second") } diff --git a/spec/services/queries/filter_mappper_spec.rb b/spec/services/queries/filters_mapper_spec.rb similarity index 95% rename from spec/services/queries/filter_mappper_spec.rb rename to spec/services/queries/filters_mapper_spec.rb index dfa6e75dd7a0..1033a44e5f0e 100644 --- a/spec/services/queries/filter_mappper_spec.rb +++ b/spec/services/queries/filters_mapper_spec.rb @@ -30,9 +30,8 @@ RSpec.describe Queries::Copy::FiltersMapper do let(:state) { Shared::ServiceState.new } - let(:instance) { described_class.new(state, filters) } + let(:instance) { described_class.new(state) } - subject { instance.map_filters! } describe "with a query filters array" do let(:query) do @@ -43,7 +42,8 @@ query end - let(:filters) { query.filters } + + subject { instance.map_query!(query) } context "when mapping state exists" do before do @@ -77,6 +77,8 @@ ] end + subject { instance.map_filters(filters) } + context "when mapping state exists" do before do state.work_package_id_lookup = { 1 => 11 } @@ -107,6 +109,8 @@ ] end + subject { instance.map_filters(filters) } + context "when mapping state exists" do before do state.work_package_id_lookup = { 1 => 11 }