From 9c139c4a5f6d9c36aab1eb3ca073889499eef0a0 Mon Sep 17 00:00:00 2001 From: Jan Sandbrink Date: Wed, 20 May 2026 15:42:16 +0200 Subject: [PATCH 1/4] Add more generic translations Moving a few XWiki translations to the base class translations and adding more attribute names. --- modules/wikis/app/forms/wikis/admin/name_input_form.rb | 2 +- modules/wikis/config/locales/en.yml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/wikis/app/forms/wikis/admin/name_input_form.rb b/modules/wikis/app/forms/wikis/admin/name_input_form.rb index b54b9408062..10af132c9cc 100644 --- a/modules/wikis/app/forms/wikis/admin/name_input_form.rb +++ b/modules/wikis/app/forms/wikis/admin/name_input_form.rb @@ -33,7 +33,7 @@ module Wikis::Admin form do |f| f.text_field( name: :name, - label: I18n.t("activerecord.attributes.wikis/xwiki_provider.name"), + label: model.class.human_attribute_name(:name), required: true, caption: I18n.t("wikis.admin.wiki_providers.name_caption"), placeholder: I18n.t("wikis.admin.wiki_providers.name_placeholder"), diff --git a/modules/wikis/config/locales/en.yml b/modules/wikis/config/locales/en.yml index 9e8ca1b996a..931754a912a 100644 --- a/modules/wikis/config/locales/en.yml +++ b/modules/wikis/config/locales/en.yml @@ -3,15 +3,17 @@ en: activerecord: attributes: wikis/page_link: + identifier: Identifier provider: Wiki Provider + wikis/provider: + name: Name + universal_identifier: Universal identifier wikis/xwiki_provider: authentication_method: Authentication method authentication_methods: oauth2_sso: Single-Sign-On through OpenID Connect Identity Provider two_way_oauth2: Two-way OAuth 2.0 authorization code flow - name: Name token_exchange_scope: XWiki Scope - universal_identifier: Universal identifier url: Instance URL wiki_audience: XWiki Audience errors: { } From 08fab3ac55d12df0304b61232db3d547561b1bc0 Mon Sep 17 00:00:00 2001 From: Jan Sandbrink Date: Thu, 21 May 2026 09:21:25 +0200 Subject: [PATCH 2/4] Add comment to guide developers The exception is already intended to nudge devs towards defining a permission. However, first time developers might not realize in which way permissions are defined, even though they can see the location where the exception was raised. This comment is intended to help them find their way. --- app/services/authorization.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/authorization.rb b/app/services/authorization.rb index 0aafb9acb30..95d73cef537 100644 --- a/app/services/authorization.rb +++ b/app/services/authorization.rb @@ -85,6 +85,8 @@ module Authorization if perms.blank? if !OpenProject::AccessControl.disabled_permission?(action) + # See https://www.openproject.org/docs/development/concepts/permissions/#definition-of-permissions + # if you are wondering where to define permissions Rails.logger.debug { "Used permission \"#{action}\" that is not defined. It will never return true." } raise UnknownPermissionError.new(action) if raise_on_unknown end From 1bb503a1d49f57966cf56f85651adc67c3d99c21 Mon Sep 17 00:00:00 2001 From: Jan Sandbrink Date: Tue, 26 May 2026 16:01:16 +0200 Subject: [PATCH 3/4] Move create service to RelationPageLinks::CreateService This allows to use more of the automagic pieces of our BaseServices::Create: * recognition of the created class without passing it explicitly * automatic recognition of the correct contract Furthermore the contract has been adapted, so that it also properly works when a new page link is created just through params this way. Notably: * even if type is indicated in `changed`, it doesn't crash and burn * linkable can be passed in as `linkable_id` + `linkable_type`, instead of only working if already passed in as a whole --- .../create_contract.rb} | 12 ++++++++---- .../create_service.rb | 5 +---- .../set_attributes_service.rb | 2 +- .../create_contract_spec.rb} | 4 ++-- .../create_service_spec.rb | 9 +-------- .../set_attributes_service_spec.rb | 6 +++--- 6 files changed, 16 insertions(+), 22 deletions(-) rename modules/wikis/app/contracts/wikis/{page_links/relation_page_link_create_contract.rb => relation_page_links/create_contract.rb} (86%) rename modules/wikis/app/services/wikis/{page_links => relation_page_links}/create_service.rb (92%) rename modules/wikis/app/services/wikis/{page_links => relation_page_links}/set_attributes_service.rb (98%) rename modules/wikis/spec/contracts/wikis/{page_links/relation_page_link_create_contract_spec.rb => relation_page_links/create_contract_spec.rb} (97%) rename modules/wikis/spec/services/wikis/{page_links => relation_page_links}/create_service_spec.rb (84%) rename modules/wikis/spec/services/wikis/{page_links => relation_page_links}/set_attributes_service_spec.rb (92%) diff --git a/modules/wikis/app/contracts/wikis/page_links/relation_page_link_create_contract.rb b/modules/wikis/app/contracts/wikis/relation_page_links/create_contract.rb similarity index 86% rename from modules/wikis/app/contracts/wikis/page_links/relation_page_link_create_contract.rb rename to modules/wikis/app/contracts/wikis/relation_page_links/create_contract.rb index a15c5ff5a07..d1697737f41 100644 --- a/modules/wikis/app/contracts/wikis/page_links/relation_page_link_create_contract.rb +++ b/modules/wikis/app/contracts/wikis/relation_page_links/create_contract.rb @@ -29,16 +29,20 @@ #++ module Wikis - module PageLinks - class RelationPageLinkCreateContract < ::ModelContract + module RelationPageLinks + class CreateContract < ::ModelContract attribute :author attribute :identifier - attribute :linkable + attribute :linkable_type + attribute :linkable_id attribute :provider + attribute :type validates :identifier, presence: true - validates :linkable, presence: true + validates :linkable_type, presence: true + validates :linkable_id, presence: true validates :provider, presence: true + validates :type, inclusion: { in: [RelationPageLink.name] } validate :provider_exists? validate :author_must_be_user diff --git a/modules/wikis/app/services/wikis/page_links/create_service.rb b/modules/wikis/app/services/wikis/relation_page_links/create_service.rb similarity index 92% rename from modules/wikis/app/services/wikis/page_links/create_service.rb rename to modules/wikis/app/services/wikis/relation_page_links/create_service.rb index eb9371246f6..d50dfd4a1b8 100644 --- a/modules/wikis/app/services/wikis/page_links/create_service.rb +++ b/modules/wikis/app/services/wikis/relation_page_links/create_service.rb @@ -29,11 +29,8 @@ #++ module Wikis - module PageLinks + module RelationPageLinks class CreateService < ::BaseServices::Create - private - - def default_contract_class = RelationPageLinkCreateContract end end end diff --git a/modules/wikis/app/services/wikis/page_links/set_attributes_service.rb b/modules/wikis/app/services/wikis/relation_page_links/set_attributes_service.rb similarity index 98% rename from modules/wikis/app/services/wikis/page_links/set_attributes_service.rb rename to modules/wikis/app/services/wikis/relation_page_links/set_attributes_service.rb index 1e3b0d5e045..bac99ed69f6 100644 --- a/modules/wikis/app/services/wikis/page_links/set_attributes_service.rb +++ b/modules/wikis/app/services/wikis/relation_page_links/set_attributes_service.rb @@ -29,7 +29,7 @@ #++ module Wikis - module PageLinks + module RelationPageLinks class SetAttributesService < ::BaseServices::SetAttributes end end diff --git a/modules/wikis/spec/contracts/wikis/page_links/relation_page_link_create_contract_spec.rb b/modules/wikis/spec/contracts/wikis/relation_page_links/create_contract_spec.rb similarity index 97% rename from modules/wikis/spec/contracts/wikis/page_links/relation_page_link_create_contract_spec.rb rename to modules/wikis/spec/contracts/wikis/relation_page_links/create_contract_spec.rb index 09c6107b63c..7a25438cfc0 100644 --- a/modules/wikis/spec/contracts/wikis/page_links/relation_page_link_create_contract_spec.rb +++ b/modules/wikis/spec/contracts/wikis/relation_page_links/create_contract_spec.rb @@ -33,8 +33,8 @@ require "contracts/shared/model_contract_shared_context" require_module_spec_helper module Wikis - module PageLinks - RSpec.describe RelationPageLinkCreateContract do + module RelationPageLinks + RSpec.describe CreateContract do include_context "ModelContract shared context" let(:linkable) { create(:work_package) } let(:project) { linkable.project } diff --git a/modules/wikis/spec/services/wikis/page_links/create_service_spec.rb b/modules/wikis/spec/services/wikis/relation_page_links/create_service_spec.rb similarity index 84% rename from modules/wikis/spec/services/wikis/page_links/create_service_spec.rb rename to modules/wikis/spec/services/wikis/relation_page_links/create_service_spec.rb index 91ac63bc390..4030cc0b331 100644 --- a/modules/wikis/spec/services/wikis/page_links/create_service_spec.rb +++ b/modules/wikis/spec/services/wikis/relation_page_links/create_service_spec.rb @@ -34,18 +34,11 @@ require "services/base_services/behaves_like_create_service" require_module_spec_helper module Wikis - module PageLinks + module RelationPageLinks RSpec.describe CreateService do it_behaves_like "BaseServices create service" do - let(:contract_class) { RelationPageLinkCreateContract } let(:factory) { :relation_wiki_page_link } end - - it "defaults to the RelationPageLinkCreateContract" do - service = described_class.new(user: nil) - - expect(service.contract_class).to eq(RelationPageLinkCreateContract) - end end end end diff --git a/modules/wikis/spec/services/wikis/page_links/set_attributes_service_spec.rb b/modules/wikis/spec/services/wikis/relation_page_links/set_attributes_service_spec.rb similarity index 92% rename from modules/wikis/spec/services/wikis/page_links/set_attributes_service_spec.rb rename to modules/wikis/spec/services/wikis/relation_page_links/set_attributes_service_spec.rb index 201aed78e69..70edc90826a 100644 --- a/modules/wikis/spec/services/wikis/page_links/set_attributes_service_spec.rb +++ b/modules/wikis/spec/services/wikis/relation_page_links/set_attributes_service_spec.rb @@ -32,15 +32,15 @@ require "spec_helper" require_module_spec_helper module Wikis - module PageLinks + module RelationPageLinks RSpec.describe SetAttributesService do let(:model_instance) { RelationPageLink.new } let(:contract_instance) do - instance_double(RelationPageLinkCreateContract, validate: contract_valid, errors: contract_errors) + instance_double(CreateContract, validate: contract_valid, errors: contract_errors) end let(:contract_class) do - class_double(RelationPageLinkCreateContract, new: contract_instance) + class_double(CreateContract, new: contract_instance) end let(:contract_errors) { instance_double(ActiveModel::Errors) } From c264fb5a114f58a7cda105ed9f0592d4c896a8e6 Mon Sep 17 00:00:00 2001 From: Jan Sandbrink Date: Wed, 20 May 2026 15:43:06 +0200 Subject: [PATCH 4/4] Allow creating relation page links through UI This change is mostly wiring up things, but leaves some things open: * we still need to use a proper create service (to be built) * the modal needs to use a treeview to select the identifier (requires fetching of a list of available wiki pages) --- .../link_existing_wiki_page_dialog.html.erb | 40 ++++++++++++ .../wikis/link_existing_wiki_page_dialog.rb | 63 +++++++++++++++++++ .../relation_page_links_component.html.erb | 17 +++-- .../wikis/relation_page_links_component.rb | 8 ++- .../work_package_wikis_tab_component.html.erb | 2 +- .../wikis/work_package_wikis_tab_component.rb | 2 + .../wikis/relation_page_links_controller.rb | 49 +++++++++++++-- .../work_package_wikis_tab_controller.rb | 9 ++- .../wikis/link_existing_wiki_page_form.rb | 46 ++++++++++++++ modules/wikis/config/locales/en.yml | 4 ++ modules/wikis/config/routes.rb | 24 ++++--- .../wikis/lib/open_project/wikis/engine.rb | 4 +- 12 files changed, 246 insertions(+), 22 deletions(-) create mode 100644 modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.html.erb create mode 100644 modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.rb create mode 100644 modules/wikis/app/forms/wikis/link_existing_wiki_page_form.rb diff --git a/modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.html.erb b/modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.html.erb new file mode 100644 index 00000000000..9d5062a95a6 --- /dev/null +++ b/modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.html.erb @@ -0,0 +1,40 @@ +<%#-- 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. + +++#%> + +<%= render(Primer::Alpha::Dialog.new(id:, title: t(".title"), size: :large, **system_arguments)) do |dialog| %> + <% dialog.with_body do + primer_form_with(**form_options) do |form| + render(Wikis::LinkExistingWikiPageForm.new(form)) + end + end %> + <% dialog.with_footer do %> + <%= render(Primer::Beta::Button.new(data: { "close-dialog-id": id })) { t("button_cancel") } %> + <%= render(Primer::Beta::Button.new(scheme: :primary, form: form_id, type: :submit)) { t("button_add") } %> + <% end %> +<% end %> diff --git a/modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.rb b/modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.rb new file mode 100644 index 00000000000..ba450e76f35 --- /dev/null +++ b/modules/wikis/app/components/wikis/link_existing_wiki_page_dialog.rb @@ -0,0 +1,63 @@ +# 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. +#++ + +module Wikis + class LinkExistingWikiPageDialog < ApplicationComponent + include OpTurbo::Streamable + + attr_reader :linkable, :provider + + def initialize(linkable:, provider:, **) + super(nil, **) + + @linkable = linkable + @provider = provider + end + + def id = "link-existing-wiki-page-dialog" + + def form_id = "#{id}-form" + + def form_options + { + id: form_id, + model: RelationPageLink.new(provider:, linkable:), + url: relation_wiki_page_links_path, + data: { + turbo_frame: WorkPackageWikisTabComponent::TURBO_FRAME_ID + } + } + end + + def system_arguments + options + end + end +end diff --git a/modules/wikis/app/components/wikis/relation_page_links_component.html.erb b/modules/wikis/app/components/wikis/relation_page_links_component.html.erb index 60fb4d2480b..bdbb740acae 100644 --- a/modules/wikis/app/components/wikis/relation_page_links_component.html.erb +++ b/modules/wikis/app/components/wikis/relation_page_links_component.html.erb @@ -37,14 +37,23 @@ See COPYRIGHT and LICENSE files for more details. end header.with_column do render(Primer::Alpha::ActionMenu.new) do |menu| - menu.with_show_button(disabled: true) do |button| + menu.with_show_button(disabled: !can_manage_links?) do |button| button.with_leading_visual_icon(icon: :plus) button.with_trailing_action_icon(icon: :"triangle-down") t("wikis.buttons.wiki_page") end - menu.with_item(label: "placeholder item") + menu.with_item( + label: t(".link_existing"), + tag: :a, + href: link_existing_dialog_relation_wiki_page_links_path(work_package:, provider:), + content_arguments: { data: { controller: "async-dialog" } } + ) + menu.with_item( + label: t(".link_new"), + disabled: true # work in progress + ) end end end @@ -52,7 +61,7 @@ See COPYRIGHT and LICENSE files for more details. if !user_connected? box.with_row do - render(Wikis::OAuthLoginComponent.new(provider, return_url: work_package_url(@work_package, tab: :wikis))) + render(Wikis::OAuthLoginComponent.new(provider, return_url: work_package_url(work_package, tab: :wikis))) end elsif page_links.empty? box.with_row do @@ -62,7 +71,7 @@ See COPYRIGHT and LICENSE files for more details. blankslate.with_description { t(".empty_text") } end else - render(Wikis::OAuthLoginComponent.new(provider, return_url: work_package_url(@work_package, tab: :wikis))) + render(Wikis::OAuthLoginComponent.new(provider, return_url: work_package_url(work_package, tab: :wikis))) end end else diff --git a/modules/wikis/app/components/wikis/relation_page_links_component.rb b/modules/wikis/app/components/wikis/relation_page_links_component.rb index 02686e72414..bd9fe9f2cd3 100644 --- a/modules/wikis/app/components/wikis/relation_page_links_component.rb +++ b/modules/wikis/app/components/wikis/relation_page_links_component.rb @@ -35,13 +35,15 @@ module Wikis alias_method :provider, :model + attr_reader :work_package + def initialize(model = nil, work_package: nil, **) @work_package = work_package super(model, **) end def page_links - @page_links ||= page_link_service.relation_page_links_for(provider:, linkable: @work_package) + @page_links ||= page_link_service.relation_page_links_for(provider:, linkable: work_package) end def user_connected? @@ -53,5 +55,9 @@ module Wikis def page_link_service @page_link_service ||= PageLinkService.new end + + def can_manage_links? + helpers.current_user.allowed_in_project?(:manage_wiki_page_links, work_package.project) + end end end diff --git a/modules/wikis/app/components/wikis/work_package_wikis_tab_component.html.erb b/modules/wikis/app/components/wikis/work_package_wikis_tab_component.html.erb index 22939ef4b85..aae5c4a9193 100644 --- a/modules/wikis/app/components/wikis/work_package_wikis_tab_component.html.erb +++ b/modules/wikis/app/components/wikis/work_package_wikis_tab_component.html.erb @@ -28,7 +28,7 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <%= - content_tag("turbo-frame", id: "work-package-wikis-tab-content") do + content_tag("turbo-frame", id: TURBO_FRAME_ID) do component_wrapper do flex_layout(test_selector: "op-work-package-wikis-tab-container") do |container| providers.each do |provider| diff --git a/modules/wikis/app/components/wikis/work_package_wikis_tab_component.rb b/modules/wikis/app/components/wikis/work_package_wikis_tab_component.rb index ac729e92864..5c0471b593b 100644 --- a/modules/wikis/app/components/wikis/work_package_wikis_tab_component.rb +++ b/modules/wikis/app/components/wikis/work_package_wikis_tab_component.rb @@ -34,6 +34,8 @@ module Wikis include OpPrimer::ComponentHelpers include OpTurbo::Streamable + TURBO_FRAME_ID = "work-package-wikis-tab-content" + alias_method :work_package, :model def providers diff --git a/modules/wikis/app/controllers/wikis/relation_page_links_controller.rb b/modules/wikis/app/controllers/wikis/relation_page_links_controller.rb index 895499df76a..dd48dd4a471 100644 --- a/modules/wikis/app/controllers/wikis/relation_page_links_controller.rb +++ b/modules/wikis/app/controllers/wikis/relation_page_links_controller.rb @@ -32,21 +32,62 @@ module Wikis class RelationPageLinksController < ApplicationController include OpTurbo::ComponentStream - before_action :find_page_link before_action :authorize + def create + service_result = RelationPageLinks::CreateService.new(user: current_user).call(relation_page_link_params) + if service_result.success? + page_link = service_result.result + turbo_redirect_for_linkable(page_link.linkable) + else + message = service_result.errors.full_messages.join(" ") + render_error_flash_message_via_turbo_stream(message:) + respond_to_with_turbo_streams + end + end + def destroy - # TODO: implement delete service + # TODO: Wikis::PageLinks::DeleteService + page_link = find_page_link + page_link.destroy! + + turbo_redirect_for_linkable(page_link.linkable) end def confirm_delete_dialog - respond_with_dialog(DeleteRelationPageLinkConfirmationDialog.new(page_link: @page_link)) + page_link = find_page_link + respond_with_dialog(DeleteRelationPageLinkConfirmationDialog.new(page_link:)) + end + + def link_existing_dialog + linkable = WorkPackage.visible.find(params.expect(:work_package)) + provider = Provider.visible.find(params.expect(:provider)) + respond_with_dialog Wikis::LinkExistingWikiPageDialog.new(linkable:, provider:) end private def find_page_link - @page_link = RelationPageLink.find(params.expect(:id)) + RelationPageLink.find(params.expect(:id)) + end + + def relation_page_link_params + params.expect(wikis_relation_page_link: %i[identifier provider_id linkable_type linkable_id]) + .merge(author_id: current_user.id) + end + + def turbo_redirect_for_linkable(linkable) + path = derive_path_from_linkable(linkable) + return redirect_to path, status: :see_other if path + + head :no_content + end + + def derive_path_from_linkable(linkable) + case linkable + when WorkPackage + project_work_package_wikis_tab_index_path(work_package_id: linkable.id, project_id: linkable.project_id) + end end end end diff --git a/modules/wikis/app/controllers/work_package_wikis_tab_controller.rb b/modules/wikis/app/controllers/work_package_wikis_tab_controller.rb index bb9f14139b9..96483db8526 100644 --- a/modules/wikis/app/controllers/work_package_wikis_tab_controller.rb +++ b/modules/wikis/app/controllers/work_package_wikis_tab_controller.rb @@ -36,7 +36,14 @@ class WorkPackageWikisTabController < ApplicationController before_action :set_work_package def index - render(Wikis::WorkPackageWikisTabComponent.new(@work_package), layout: false) + tab_component = Wikis::WorkPackageWikisTabComponent.new(@work_package) + replace_via_turbo_stream(component: tab_component) + + respond_to_with_turbo_streams do |format| + format.html do + render(tab_component, layout: false) + end + end end private diff --git a/modules/wikis/app/forms/wikis/link_existing_wiki_page_form.rb b/modules/wikis/app/forms/wikis/link_existing_wiki_page_form.rb new file mode 100644 index 00000000000..23b852f2cc8 --- /dev/null +++ b/modules/wikis/app/forms/wikis/link_existing_wiki_page_form.rb @@ -0,0 +1,46 @@ +# 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. +#++ + +module Wikis + class LinkExistingWikiPageForm < ApplicationForm + form do |f| + f.hidden(name: :provider_id) + f.hidden(name: :linkable_type) + f.hidden(name: :linkable_id) + + f.text_field( + name: :identifier, + label: RelationPageLink.human_attribute_name(:identifier), + required: true, + input_width: :large + ) + end + end +end diff --git a/modules/wikis/config/locales/en.yml b/modules/wikis/config/locales/en.yml index 931754a912a..e1f6141a186 100644 --- a/modules/wikis/config/locales/en.yml +++ b/modules/wikis/config/locales/en.yml @@ -59,6 +59,8 @@ en: work_package_wikis_tab_component: inline_page_links: Inline page links referencing_pages: Referenced in + link_existing_wiki_page_dialog: + title: Add existing wiki page page_links: errors: page_not_found: Linked wiki page no longer available @@ -67,6 +69,8 @@ en: page_link_component: remove: Remove page link relation_page_links_component: + link_existing: Existing wiki page + link_new: New wiki page empty_heading: No related pages empty_text: Manually add links to other related wiki pages. oauth_login_component: diff --git a/modules/wikis/config/routes.rb b/modules/wikis/config/routes.rb index 4a8ac57407f..963162be729 100644 --- a/modules/wikis/config/routes.rb +++ b/modules/wikis/config/routes.rb @@ -49,16 +49,6 @@ Rails.application.routes.draw do end end - resource :wiki_page_link_macro, controller: "wikis/page_link_macro", only: [] do - get :load - end - - resources :relation_wiki_page_links, only: %i[destroy], controller: "wikis/relation_page_links" do - member do - get :confirm_delete_dialog - end - end - resources :projects, only: %i[] do resources :work_packages, only: %i[] do resources :wikis, only: %i[] do @@ -68,4 +58,18 @@ Rails.application.routes.draw do end end end + + resources :relation_wiki_page_links, only: %i[create destroy], controller: "wikis/relation_page_links" do + collection do + get :link_existing_dialog + end + + member do + get :confirm_delete_dialog + end + end + + resource :wiki_page_link_macro, controller: "wikis/page_link_macro", only: [] do + get :load + end end diff --git a/modules/wikis/lib/open_project/wikis/engine.rb b/modules/wikis/lib/open_project/wikis/engine.rb index 5d70952d9aa..a8ce614c2cb 100644 --- a/modules/wikis/lib/open_project/wikis/engine.rb +++ b/modules/wikis/lib/open_project/wikis/engine.rb @@ -72,7 +72,9 @@ module OpenProject::Wikis register "openproject-wikis", author_url: "https://openproject.org" do project_module :work_package_tracking do permission :manage_wiki_page_links, - { "wikis/relation_page_links": %i[destroy confirm_delete_dialog] }, + { + "wikis/relation_page_links": %i[create destroy confirm_delete_dialog link_existing_dialog] + }, permissible_on: :project, dependencies: %i[edit_work_packages], contract_actions: { wiki_page_links: %i[manage] }