diff --git a/app/components/settings/project_life_cycle_step_definitions/index_component.html.erb b/app/components/settings/project_life_cycle_step_definitions/index_component.html.erb index 2b1e06ea49e9..3da4d4ceb4f5 100644 --- a/app/components/settings/project_life_cycle_step_definitions/index_component.html.erb +++ b/app/components/settings/project_life_cycle_step_definitions/index_component.html.erb @@ -50,7 +50,7 @@ See COPYRIGHT and LICENSE files for more details. end flex.with_row do - render(border_box_container(mb: 3)) do |component| + render(border_box_container(mb: 3, data: drop_target_config)) do |component| component.with_header(font_weight: :bold, py: 2) do flex_layout(justify_content: :space_between, align_items: :center) do |header_container| header_container.with_column do @@ -66,7 +66,7 @@ See COPYRIGHT and LICENSE files for more details. end else definitions.each do |definition| - component.with_row(data: { "projects--settings--border-box-filter-target": "searchItem" }) do + component.with_row(data: { "projects--settings--border-box-filter-target": "searchItem", **draggable_item_config(definition) }) do render(Settings::ProjectLifeCycleStepDefinitions::RowComponent.new( definition, first?: definition == definitions.first, diff --git a/app/components/settings/project_life_cycle_step_definitions/index_component.rb b/app/components/settings/project_life_cycle_step_definitions/index_component.rb index 107f81e0aeda..f34bf7f8a911 100644 --- a/app/components/settings/project_life_cycle_step_definitions/index_component.rb +++ b/app/components/settings/project_life_cycle_step_definitions/index_component.rb @@ -37,10 +37,25 @@ class IndexComponent < ApplicationComponent def wrapper_data_attributes { - controller: "projects--settings--border-box-filter", + controller: "projects--settings--border-box-filter generic-drag-and-drop", "application-target": "dynamic" } end + + def drop_target_config + { + "is-drag-and-drop-target": true, + "target-container-accessor": "& > ul", + "target-allowed-drag-type": "life-cycle-step-definition" + } + end + + def draggable_item_config(definition) + { + "draggable-type": "life-cycle-step-definition", + "drop-url": drop_admin_settings_project_life_cycle_step_definition_path(definition) + } + end end end end diff --git a/app/components/settings/project_life_cycle_step_definitions/row_component.html.erb b/app/components/settings/project_life_cycle_step_definitions/row_component.html.erb index 2c02f43f8f10..91c3064f4c4e 100644 --- a/app/components/settings/project_life_cycle_step_definitions/row_component.html.erb +++ b/app/components/settings/project_life_cycle_step_definitions/row_component.html.erb @@ -30,6 +30,9 @@ See COPYRIGHT and LICENSE files for more details. <%= flex_layout(align_items: :center, justify_content: :space_between) do |row_container| row_container.with_column(flex_layout: true, classes: "gap-2") do |title_container| + title_container.with_column do + render(Primer::OpenProject::DragHandle.new) + end title_container.with_column do render(Primer::Beta::Link.new( classes: 'filter-target-visible-text', diff --git a/app/controllers/admin/settings/project_life_cycle_step_definitions_controller.rb b/app/controllers/admin/settings/project_life_cycle_step_definitions_controller.rb index 30c5f31f37b4..402101a25870 100644 --- a/app/controllers/admin/settings/project_life_cycle_step_definitions_controller.rb +++ b/app/controllers/admin/settings/project_life_cycle_step_definitions_controller.rb @@ -33,7 +33,7 @@ class ProjectLifeCycleStepDefinitionsController < ::Admin::SettingsController before_action :check_feature_flag before_action :find_definitions, only: %i[index] - before_action :find_definition, only: %i[edit update destroy move] + before_action :find_definition, only: %i[edit update destroy move drop] def index; end @@ -58,7 +58,7 @@ def create if @definition.save flash[:notice] = I18n.t(:notice_successful_create) - redirect_to action: :index + redirect_to action: :index, status: :see_other else render :form, status: :unprocessable_entity end @@ -67,7 +67,7 @@ def create def update if @definition.update(definition_params) flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: :index + redirect_to action: :index, status: :see_other else render :form, status: :unprocessable_entity end @@ -81,7 +81,7 @@ def destroy flash[:error] = I18n.t(:notice_bad_request) end - redirect_to action: :index + redirect_to action: :index, status: :see_other end def move @@ -92,7 +92,18 @@ def move flash[:error] = I18n.t(:notice_bad_request) end - redirect_to action: :index + redirect_to action: :index, status: :see_other + end + + def drop + if @definition.update(params.permit(:position)) + flash[:notice] = I18n.t(:notice_successful_update) + else + # TODO: handle better + flash[:error] = I18n.t(:notice_bad_request) + end + + redirect_to action: :index, status: :see_other end private diff --git a/config/routes.rb b/config/routes.rb index a6255585518c..466ff9690dc5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -522,6 +522,7 @@ end member do patch :move + put :drop # should be patch, but requires passing method to generic-drag-and-drop controller end end resources :project_custom_fields, controller: "/admin/settings/project_custom_fields" do