diff --git a/app/components/work_package_relations_tab/index_component.html.erb b/app/components/work_package_relations_tab/index_component.html.erb index bebeff3d9c13..3e2f69ef992f 100644 --- a/app/components/work_package_relations_tab/index_component.html.erb +++ b/app/components/work_package_relations_tab/index_component.html.erb @@ -37,7 +37,9 @@ items: relations_of_type ) do |relation| related_work_package = relation.from == work_package ? relation.to : relation.from - render(WorkPackageRelationsTab::RelationComponent.new(work_package: related_work_package)) + render(WorkPackageRelationsTab::RelationComponent.new(work_package:, + relation:, + related_work_package:)) end end end @@ -51,7 +53,9 @@ title: t("#{base_key}_plural").capitalize, items: children ) do |child| - render(WorkPackageRelationsTab::RelationComponent.new(work_package: child)) + render(WorkPackageRelationsTab::RelationComponent.new(work_package:, + relation: nil, + related_work_package: child)) end end end diff --git a/app/components/work_package_relations_tab/relation_component.html.erb b/app/components/work_package_relations_tab/relation_component.html.erb index 96d92cb67124..250ea3d119ec 100644 --- a/app/components/work_package_relations_tab/relation_component.html.erb +++ b/app/components/work_package_relations_tab/relation_component.html.erb @@ -4,24 +4,24 @@ align_items: :center, style: "gap: 0.5rem;") do |meta_information_row| meta_information_row.with_column do - render(WorkPackages::HighlightedTypeComponent.new(work_package: @work_package, font_size: :small)) + render(WorkPackages::HighlightedTypeComponent.new(work_package: related_work_package, font_size: :small)) end meta_information_row.with_column do - render(Primer::Beta::Text.new(font_size: :small,color: :muted)) { "##{work_package.id}" } + render(Primer::Beta::Text.new(font_size: :small,color: :muted)) { "##{related_work_package.id}" } end meta_information_row.with_column do - render WorkPackages::StatusBadgeComponent.new(status: work_package.status) + render WorkPackages::StatusBadgeComponent.new(status: related_work_package.status) end end flex.with_row(flex_layout: true, justify_content: :space_between, align_items: :center) do |subject_line_row| subject_line_row.with_column do - render(Primer::Beta::Link.new(href: work_package_path(work_package), + render(Primer::Beta::Link.new(href: work_package_path(related_work_package), color: :default, underline: false, font_size: :normal, font_weight: :bold, - target: "_blank")) { work_package.subject } + target: "_blank")) { related_work_package.subject } end subject_line_row.with_column do @@ -40,9 +40,13 @@ end menu.with_item(label: "Delete relation", scheme: :danger, - href: "#", + href: destroy_path, form_arguments: { - method: :delete, data: { confirm: t("text_are_you_sure"), "turbo-stream": true } + method: :delete, + data: { + confirm: t("text_are_you_sure"), + turbo_stream: true + } }) do |item| item.with_leading_visual_icon(icon: :trash) end @@ -50,12 +54,12 @@ end end - if work_package.description.present? + if related_work_package.description.present? flex.with_row(flex_layout: true, justify_content: :flex_start) do |description_row| description_row.with_column do render(Primer::Beta::Text.new(font_size: :small, color: :muted)) do - format_text(work_package, :description) + format_text(related_work_package, :description) end end end diff --git a/app/components/work_package_relations_tab/relation_component.rb b/app/components/work_package_relations_tab/relation_component.rb index 0a71843dab45..e1e3237425b1 100644 --- a/app/components/work_package_relations_tab/relation_component.rb +++ b/app/components/work_package_relations_tab/relation_component.rb @@ -2,11 +2,28 @@ class WorkPackageRelationsTab::RelationComponent < ApplicationComponent include ApplicationHelper include OpPrimer::ComponentHelpers - attr_reader :work_package + attr_reader :work_package, :relation, :related_work_package - def initialize(work_package:) + def initialize(work_package:, + relation:, + related_work_package:) super() @work_package = work_package + @relation = relation + @related_work_package = related_work_package + @child = @related_work_package if parent_child_relationship? + end + + private + + def parent_child_relationship? = @related_work_package.parent == @work_package + + def destroy_path + if parent_child_relationship? + work_package_child_path(@child) + else + work_package_relation_path(@work_package, @relation) + end end end diff --git a/app/controllers/work_package_children_controller.rb b/app/controllers/work_package_children_controller.rb new file mode 100644 index 000000000000..f5e80be75a1a --- /dev/null +++ b/app/controllers/work_package_children_controller.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +class WorkPackageChildrenController < ApplicationController + include OpTurbo::ComponentStream + + before_action :set_child + before_action :set_work_package + + before_action :authorize # Short-circuit early if not authorized + + before_action :set_relations + + def destroy + @child.parent = nil + + if @child.save + @children = @work_package.children.visible + component = WorkPackageRelationsTab::IndexComponent.new( + work_package: @work_package, + relations: @relations, + children: @children + ) + replace_via_turbo_stream(component:) + + respond_with_turbo_streams + end + end + + private + + def set_child + @child = WorkPackage.find(params[:id]) + end + + def set_work_package + @work_package = @child.parent + end + + def set_relations + @relations = @work_package.relations.visible + end +end diff --git a/app/controllers/work_package_relations_controller.rb b/app/controllers/work_package_relations_controller.rb new file mode 100644 index 000000000000..1e49d6d9a6e7 --- /dev/null +++ b/app/controllers/work_package_relations_controller.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +class WorkPackageRelationsController < ApplicationController + include OpTurbo::ComponentStream + + before_action :set_work_package + before_action :set_relation + before_action :authorize + + def destroy + service_result = Relations::DeleteService.new(user: current_user, model: @relation).call + + if service_result.success? + @children = WorkPackage.where(parent_id: @work_package.id) + @relations = @work_package + .relations + .includes(:to, :from) + + component = WorkPackageRelationsTab::IndexComponent.new(work_package: @work_package, + relations: @relations, + children: @children) + replace_via_turbo_stream(component:) + respond_with_turbo_streams + else + respond_with_turbo_streams(status: :unprocessable_entity) + end + end + + private + + def set_work_package + @work_package = WorkPackage.find(params[:work_package_id]) + end + + def set_relation + @relation = @work_package.relations.find(params[:id]) + end +end diff --git a/config/initializers/permissions.rb b/config/initializers/permissions.rb index 12b91490e4a2..d408130f7d91 100644 --- a/config/initializers/permissions.rb +++ b/config/initializers/permissions.rb @@ -323,7 +323,9 @@ dependencies: :view_work_packages wpt.permission :manage_subtasks, - {}, + { + work_package_children: %i[destroy] + }, permissible_on: :project, dependencies: :view_work_packages # Queries diff --git a/config/routes.rb b/config/routes.rb index 669b99a5525f..747e6948c969 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -600,6 +600,7 @@ as: :work_package_progress end resources :relations_tab, only: %i[index], controller: "work_package_relations_tab" + resources :relations, only: %i[destroy], controller: "work_package_relations" get "/export_dialog" => "work_packages#export_dialog", on: :collection, as: "export_dialog" get "/split_view/update_counter" => "work_packages/split_view#update_counter", @@ -615,6 +616,8 @@ get "/edit" => "work_packages#show", on: :member, as: "edit" end + resources :work_package_children, only: %i[destroy] + resources :versions, only: %i[show edit update destroy] do member do get :status_by