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 index 9d5062a95a62..57b71441e3c4 100644 --- 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 @@ -28,11 +28,14 @@ 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)) + <% + dialog.with_body(classes: "Overlay-body_autocomplete_height") do + primer_form_with(**form_options) do |form| + render(Wikis::LinkExistingWikiPageForm.new(form)) + end 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") } %> 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 dd48dd4a471e..c4d07d0371bd 100644 --- a/modules/wikis/app/controllers/wikis/relation_page_links_controller.rb +++ b/modules/wikis/app/controllers/wikis/relation_page_links_controller.rb @@ -72,8 +72,17 @@ def find_page_link 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) + params.expect(wikis_relation_page_link: %i[provider_id linkable_type linkable_id]) + .merge(author_id: current_user.id, identifier: parse_identifier(params[:wiki_page_selection])) + end + + def parse_identifier(wiki_page_selection) + case wiki_page_selection + in [selected_page] + MultiJson.load(selected_page, symbolize_keys: true)[:value] + else + nil + end end def turbo_redirect_for_linkable(linkable) diff --git a/modules/wikis/app/controllers/wikis/search_pages_controller.rb b/modules/wikis/app/controllers/wikis/search_pages_controller.rb new file mode 100644 index 000000000000..636d2f1338bc --- /dev/null +++ b/modules/wikis/app/controllers/wikis/search_pages_controller.rb @@ -0,0 +1,61 @@ +# 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 SearchPagesController < ApplicationController + include Dry::Monads[:result] + + # The search is project independent and thus permission independent. The user will see results according to + # the permissions set in each wiki. + no_authorization_required! :show + + def show + provider = Provider.visible.find(params.expect(:provider_id)) + query = params[:query] + form_name = params[:name] + builder = ActionView::Helpers::FormBuilder.new("", nil, view_context, {}) + search_result = search_pages(query, provider) + + render layout: false, locals: { search_result:, builder:, name: form_name } + end + + private + + def search_pages(query, provider) + return Success([]) if query.blank? + + Adapters::Input::SearchPages.build(query:).bind do |input_data| + provider.auth_strategy_for(current_user).bind do |auth_strategy| + provider.resolve("queries.search_pages").call(input_data:, auth_strategy:) + end + end + end + end +end 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 index 23b852f2cc8a..acb68eaf2365 100644 --- a/modules/wikis/app/forms/wikis/link_existing_wiki_page_form.rb +++ b/modules/wikis/app/forms/wikis/link_existing_wiki_page_form.rb @@ -35,12 +35,37 @@ class LinkExistingWikiPageForm < ApplicationForm 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 - ) + f.html_content do + render( + Primer::OpenProject::FilterableTreeView.new( + src: helpers.search_wiki_pages_path(provider_id: model.provider_id, name: "wiki_page_selection"), + form_arguments: { builder: rails_builder(f), name: "wiki_page_selection" }, + filter_mode_control_arguments: { hidden: true }, + filter_input_arguments: { + placeholder: I18n.t("wikis.link_existing_wiki_page_form.placeholder"), + # every other property is just refilling the default values, + # as those are not merged into custom arguments + name: :filter, + label: I18n.t(:button_filter), + type: :search, + leading_visual: { icon: :search }, + visually_hide_label: true, + show_clear_button: true + }, + include_sub_items_check_box_arguments: { hidden: true }, + no_results_node_arguments: { label: I18n.t("wikis.link_existing_wiki_page_form.no_results") } + ) + ) + end + end + + private + + # Primer's FormObject stores the underlying ActionView/Primer form builder + # as @builder. FilterableTreeView requires an ActionView::FormBuilder to + # generate its hidden form inputs via hidden_field. + def rails_builder(form) + form.instance_variable_get(:@builder) end end end diff --git a/modules/wikis/app/views/wikis/search_pages/show.html.erb b/modules/wikis/app/views/wikis/search_pages/show.html.erb new file mode 100644 index 000000000000..97d51a63a15c --- /dev/null +++ b/modules/wikis/app/views/wikis/search_pages/show.html.erb @@ -0,0 +1,52 @@ +<%#-- 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. + +++#%> + +<%= + search_result.either( + ->(pages) do + render( + Primer::Alpha::TreeView.new( + form_arguments: { builder:, name: }, + data: { target: "filterable-tree-view.treeViewList" } + ) + ) do |tree_view| + pages.each do |page| + tree_view.with_leaf(select_variant: :single, label: page.title, value: page.identifier) do |item| + item.with_leading_visual_icon(icon: :"op-file-doc") + end + end + end + end, + ->(_failure) do + render(Primer::Alpha::TreeView.new(data: { target: "filterable-tree-view.treeViewList" })) do |tree_view| + tree_view.with_leaf(select_variant: :none, label: t("wikis.link_existing_wiki_page_dialog.no_results")) + end + end + ) +%> diff --git a/modules/wikis/config/locales/en.yml b/modules/wikis/config/locales/en.yml index 3f2d66317e40..34bd78b1bbb9 100644 --- a/modules/wikis/config/locales/en.yml +++ b/modules/wikis/config/locales/en.yml @@ -64,11 +64,14 @@ en: xwiki_oauth_request_error: An unexpected error occured when trying to communicate with the XWiki instance. xwiki_oauth_token_missing: OpenProject cannot test the user-level communication with XWiki as the user did not yet connect their XWiki account. xwiki_oauth_unauthorized: The user token was not recognized by XWiki. + link_existing_wiki_page_dialog: + title: Add existing wiki page + link_existing_wiki_page_form: + no_results: No wiki pages found + placeholder: Search for a wiki page 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 diff --git a/modules/wikis/config/routes.rb b/modules/wikis/config/routes.rb index 963162be7298..242e3c634586 100644 --- a/modules/wikis/config/routes.rb +++ b/modules/wikis/config/routes.rb @@ -72,4 +72,6 @@ resource :wiki_page_link_macro, controller: "wikis/page_link_macro", only: [] do get :load end + + resource :search_wiki_pages, controller: "wikis/search_pages", only: %i[show] end