From e328641aec1118c62b04d358097dba7ea79e8fed Mon Sep 17 00:00:00 2001 From: Aaron Contreras Date: Tue, 18 Jun 2024 10:14:05 -0500 Subject: [PATCH 1/3] Warn user that the type is not available in target project Displays a warning toast letting the user know to activate the current types of the work packages under move in the target project and making the "auto-reassign" behavior known to them so they can better take a decision when performing moves. --- .../work_packages/moves_controller.rb | 6 +- app/views/work_packages/moves/new.html.erb | 243 +++++++++--------- config/locales/en.yml | 8 + 3 files changed, 140 insertions(+), 117 deletions(-) diff --git a/app/controllers/work_packages/moves_controller.rb b/app/controllers/work_packages/moves_controller.rb index 42c65161fafa..4b49e75895bd 100644 --- a/app/controllers/work_packages/moves_controller.rb +++ b/app/controllers/work_packages/moves_controller.rb @@ -60,7 +60,7 @@ def within_frontend_treshold? # rubocop:disable Metrics/AbcSize def perform_in_frontend call = job_class - .perform_now(**job_args) + .perform_now(**job_args) if call.success? && @work_packages.any? flash[:notice] = call.message @@ -70,6 +70,7 @@ def perform_in_frontend redirect_back_or_default(project_work_packages_path(@project)) end end + # rubocop:enable Metrics/AbcSize def perform_in_background @@ -114,8 +115,9 @@ def prepare_for_work_package_move @allowed_projects = WorkPackage.allowed_target_projects_on_move(current_user) @target_project = @allowed_projects.detect { |p| p.id.to_s == params[:new_project_id].to_s } if params[:new_project_id] @target_project ||= @project - @types = @target_project.types + @types = @target_project.types.order(:position) @target_type = @types.find { |t| t.id.to_s == params[:new_type_id].to_s } + @unavailable_type_in_target_project = @types.exclude?(@target_type) @available_versions = @target_project.assignable_versions @available_statuses = Workflow.available_statuses(@project) @notes = params[:notes] || "" diff --git a/app/views/work_packages/moves/new.html.erb b/app/views/work_packages/moves/new.html.erb index f1edbadcd240..f46a4af1b4f5 100644 --- a/app/views/work_packages/moves/new.html.erb +++ b/app/views/work_packages/moves/new.html.erb @@ -42,7 +42,7 @@ See COPYRIGHT and LICENSE files for more details. <% end -%> -<%= styled_form_tag({action: 'create'}, +<%= styled_form_tag({ action: 'create' }, id: 'move_form', data: { 'controller': 'refresh-on-form-changes', @@ -54,134 +54,147 @@ See COPYRIGHT and LICENSE files for more details. <%= hidden_field_tag 'ids[]', wp.id %> <% end %> <%= back_url_hidden_field_tag %> -
-
- <%= t(:label_change_properties) %> -
-
-
- -
- <%= angular_component_tag 'opce-project-autocompleter', - inputs: { - filters: [{ name: 'user_action', operator: '=', values: ['work_packages/move'] }], - inputName: 'new_project_id', - model: @target_project, - appendTo: 'body', - hiddenFieldAction: 'change->refresh-on-form-changes#triggerReload', - clearable: false, - }, - id: 'new_project_id', - class: 'remote-field--input', - data: { - 'test-selector': 'new_project_id' - } - %> -
-
-
- -
- <%= styled_select_tag("new_type_id", - content_tag('option', t(:label_no_change_option), value: '') + - options_from_collection_for_select(@types, "id", "name", @target_type&.id), - data: { - 'action': 'change->refresh-on-form-changes#triggerReload' - }) %> -
+
+
+ <%= t(:label_change_properties) %> +
+
+
+ +
+ <%= angular_component_tag 'opce-project-autocompleter', + inputs: { + filters: [{ name: 'user_action', operator: '=', values: ['work_packages/move'] }], + inputName: 'new_project_id', + model: @target_project, + appendTo: 'body', + hiddenFieldAction: 'change->refresh-on-form-changes#triggerReload', + clearable: false, + }, + id: 'new_project_id', + class: 'remote-field--input', + data: { + 'test-selector': 'new_project_id' + } + %>
-
- -
- <%= styled_select_tag('status_id', - content_tag('option', t(:label_no_change_option), value: '') + - options_from_collection_for_select(@available_statuses, :id, :name)) %> -
+
+
+ +
+ <%= styled_select_tag("new_type_id", + content_tag('option', t(:label_no_change_option), value: '') + + options_from_collection_for_select(@types, "id", "name", @target_type&.id), + data: { + 'action': 'change->refresh-on-form-changes#triggerReload' + }) %>
-
- -
- <%= styled_select_tag('version_id', - content_tag('option', t(:label_no_change_option), value: '') + - version_options_for_select(@available_versions)) %> + <% if @unavailable_type_in_target_project %> +
+
+

+ <% if @work_packages.size > 1 %> + <%= t("work_packages.move.bulk_current_type_not_available_in_target_project") %> + <% else %> + <%= t("work_packages.move.current_type_not_available_in_target_project") %> + <% end %> +

+
+ <% end %> +
+
+ +
+ <%= styled_select_tag('status_id', + content_tag('option', t(:label_no_change_option), value: '') + + options_from_collection_for_select(@available_statuses, :id, :name)) %>
-
- -
- <%= styled_select_tag('priority_id', - content_tag('option', t(:label_no_change_option), value: '') + - options_from_collection_for_select(IssuePriority.active, :id, :name)) %> -
+
+
+ +
+ <%= styled_select_tag('version_id', + content_tag('option', t(:label_no_change_option), value: '') + + version_options_for_select(@available_versions)) %>
-
- -
- <%= styled_select_tag('assigned_to_id', - content_tag('option', t(:label_no_change_option), value: '') + - content_tag('option', t(:label_nobody), value: 'none') + - options_from_collection_for_select(Principal.possible_assignee(@target_project), :id, :name)) %> -
+
+
+ +
+ <%= styled_select_tag('priority_id', + content_tag('option', t(:label_no_change_option), value: '') + + options_from_collection_for_select(IssuePriority.active, :id, :name)) %>
-
- -
- <%= styled_select_tag('responsible_id', - content_tag('option', t(:label_no_change_option), value: '') + - content_tag('option', t(:label_nobody), value: 'none') + - options_from_collection_for_select(Principal.possible_assignee(@target_project), :id, :name)) %> -
+
+
+ +
+ <%= styled_select_tag('assigned_to_id', + content_tag('option', t(:label_no_change_option), value: '') + + content_tag('option', t(:label_nobody), value: 'none') + + options_from_collection_for_select(Principal.possible_assignee(@target_project), :id, :name)) %>
-
- <%= styled_label_tag :budget_id, Budget.model_name.human %> - <%= styled_select_tag('budget_id', (@target_project == @project ? content_tag('option', t(:label_no_change_option), :value => '') : "") + - content_tag('option', t(:label_none), :value => 'none') + - options_from_collection_for_select(@target_project.budgets, :id, :subject)) %> +
+
+ +
+ <%= styled_select_tag('responsible_id', + content_tag('option', t(:label_no_change_option), value: '') + + content_tag('option', t(:label_nobody), value: 'none') + + options_from_collection_for_select(Principal.possible_assignee(@target_project), :id, :name)) %>
-
-
- -
- <%= angular_component_tag 'op-basic-single-date-picker', - inputs: { - id: "start_date", - name: "start_date" - } - %> -
+
+ <%= styled_label_tag :budget_id, Budget.model_name.human %> + <%= styled_select_tag('budget_id', (@target_project == @project ? content_tag('option', t(:label_no_change_option), :value => '') : "") + + content_tag('option', t(:label_none), :value => 'none') + + options_from_collection_for_select(@target_project.budgets, :id, :subject)) %> +
+
+
+
+ +
+ <%= angular_component_tag 'op-basic-single-date-picker', + inputs: { + id: "start_date", + name: "start_date" + } + %>
-
- -
- <%= angular_component_tag 'op-basic-single-date-picker', - inputs: { - id: "due_date", - name: "due_date" - } - %> -
+
+
+ +
+ <%= angular_component_tag 'op-basic-single-date-picker', + inputs: { + id: "due_date", + name: "due_date" + } + %>
- <% if @target_type %> - <% @target_type.custom_fields.required.each do |custom_field| %> -
- <%= blank_custom_field_label_tag('', custom_field) %> -
- <%= custom_field_tag_for_bulk_edit('', custom_field, @project) %> -
+
+ <% if @target_type %> + <% @target_type.custom_fields.required.each do |custom_field| %> +
+ <%= blank_custom_field_label_tag('', custom_field) %> +
+ <%= custom_field_tag_for_bulk_edit('', custom_field, @project) %>
- <% end %> +
<% end %> -
+ <% end %>
-
-
- <%= Journal.human_attribute_name(:notes) %> - <%= label_tag 'notes', Journal.human_attribute_name(:notes), class: 'hidden-for-sighted' %> - <%= styled_text_area_tag 'notes', @notes, cols: 60, rows: 10, class: 'wiki-edit', with_text_formatting: true %> -
- <%= call_hook(:view_work_packages_move_bottom, work_packages: @work_packages, target_project: @target_project, copy: !!@copy) %> -
+
+
+
+ <%= Journal.human_attribute_name(:notes) %> + <%= label_tag 'notes', Journal.human_attribute_name(:notes), class: 'hidden-for-sighted' %> + <%= styled_text_area_tag 'notes', @notes, cols: 60, rows: 10, class: 'wiki-edit', with_text_formatting: true %> +
+ <%= call_hook(:view_work_packages_move_bottom, work_packages: @work_packages, target_project: @target_project, copy: !!@copy) %> +
<% if @copy %> <%= hidden_field_tag("copy") %> <%= styled_submit_tag t(:button_copy), class: '-primary' %> diff --git a/config/locales/en.yml b/config/locales/en.yml index bd92d124be41..7bd8db3d9728 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -578,6 +578,14 @@ Project attributes and sections are defined in the + The current type of the work package is not enabled in the target project. + Please enable the type in the target project if you'd like them to remain unchanged. + Otherwise, the work package's type will be automatically re-assigned leading to potential data loss. + bulk_current_type_not_available_in_target_project: > + The current types of the work packages aren't enabled in the target project. + Please enable the types in the target project if you'd like them to remain unchanged. + Otherwise, the work packages' types will be automatically re-assigned leading to potential data loss. sharing: missing_workflow_warning: From c247323345cda784c3228fd4633e51894f60c031 Mon Sep 17 00:00:00 2001 From: Aaron Contreras Date: Thu, 20 Jun 2024 13:47:45 -0500 Subject: [PATCH 2/3] Fix logic for determining whether the warning should be displayed --- .../work_packages/moves_controller.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/app/controllers/work_packages/moves_controller.rb b/app/controllers/work_packages/moves_controller.rb index 4b49e75895bd..13d21f49c474 100644 --- a/app/controllers/work_packages/moves_controller.rb +++ b/app/controllers/work_packages/moves_controller.rb @@ -117,12 +117,26 @@ def prepare_for_work_package_move @target_project ||= @project @types = @target_project.types.order(:position) @target_type = @types.find { |t| t.id.to_s == params[:new_type_id].to_s } - @unavailable_type_in_target_project = @types.exclude?(@target_type) + @unavailable_type_in_target_project = set_unavailable_type_in_target_project @available_versions = @target_project.assignable_versions @available_statuses = Workflow.available_statuses(@project) @notes = params[:notes] || "" end + def set_unavailable_type_in_target_project + if @target_project == @project + false + elsif @target_type.nil? + Type.where(id: @work_packages.select(:type_id)) + .select("distinct id") + .pluck(:id) + .difference(@types.pluck(:id)) + .any? + else + @types.exclude?(@target_type) + end + end + def attributes_for_create permitted_params .move_work_package From c1a98ed48807dc0e734e910b681988b8e342d568 Mon Sep 17 00:00:00 2001 From: Aaron Contreras Date: Fri, 21 Jun 2024 10:26:53 -0500 Subject: [PATCH 3/3] Account for children work packages when warning project moves --- app/controllers/work_packages/moves_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/work_packages/moves_controller.rb b/app/controllers/work_packages/moves_controller.rb index 13d21f49c474..0ffb7779eb9f 100644 --- a/app/controllers/work_packages/moves_controller.rb +++ b/app/controllers/work_packages/moves_controller.rb @@ -127,7 +127,8 @@ def set_unavailable_type_in_target_project if @target_project == @project false elsif @target_type.nil? - Type.where(id: @work_packages.select(:type_id)) + work_packages_and_descendants = WorkPackageHierarchy.where(ancestor_id: @work_packages.select(:id)) + Type.where(id: work_packages_and_descendants.select(:id)) .select("distinct id") .pluck(:id) .difference(@types.pluck(:id))