diff --git a/config/locales/en.yml b/config/locales/en.yml index 28ed13fa8a2..7f8da22ec0d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2944,6 +2944,7 @@ en: button_login: "Sign in" button_move: "Move" button_move_and_follow: "Move and follow" + button_next: "Next" button_print: "Print" button_quote: "Quote" button_remove: Remove diff --git a/modules/wikis/app/components/wikis/create_new_wiki_page_dialog.html.erb b/modules/wikis/app/components/wikis/create_new_wiki_page_dialog.html.erb new file mode 100644 index 00000000000..90556381cc1 --- /dev/null +++ b/modules/wikis/app/components/wikis/create_new_wiki_page_dialog.html.erb @@ -0,0 +1,47 @@ +<%#-- 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(classes: "Overlay-body_autocomplete_height") do + primer_form_with(**form_options) do |form| + render(::Wikis::CreateNewWikiPageForm.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)) do + show_first_step? ? t(:button_next) : t(:button_add) + end + %> + <% end %> +<% end %> diff --git a/modules/wikis/app/components/wikis/create_new_wiki_page_dialog.rb b/modules/wikis/app/components/wikis/create_new_wiki_page_dialog.rb new file mode 100644 index 00000000000..bbe6ad20015 --- /dev/null +++ b/modules/wikis/app/components/wikis/create_new_wiki_page_dialog.rb @@ -0,0 +1,78 @@ +# 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 CreateNewWikiPageDialog < ApplicationComponent + include OpTurbo::Streamable + + attr_reader :linkable, :provider, :title + + def initialize(linkable:, provider:, title:, **) + super(nil, **) + + @linkable = linkable + @provider = provider + @title = title + end + + def id = "create-new-wiki-page-dialog" + + def form_id = "#{id}-form" + + def show_first_step? + title.blank? + end + + def form_options + { + id: form_id, + model: Forms::CreateNewWikiPageFormModel.new(linkable:, provider:, title:), + url: form_url, + data: { + turbo_frame: WorkPackageWikisTabComponent::TURBO_FRAME_ID + } + } + end + + def system_arguments + options + end + + private + + def form_url + if show_first_step? + continue_create_new_page_dialog_wiki_pages_path + else + create_and_link_wiki_pages_path + end + 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 bdbb740acae..9dcea1dc8d6 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 @@ -52,7 +52,9 @@ See COPYRIGHT and LICENSE files for more details. ) menu.with_item( label: t(".link_new"), - disabled: true # work in progress + tag: :a, + href: create_new_page_dialog_wiki_pages_path(linkable: work_package, provider:), + content_arguments: { data: { controller: "async-dialog" } } ) end end diff --git a/modules/wikis/app/controllers/wikis/search_pages_controller.rb b/modules/wikis/app/controllers/wikis/pages_controller.rb similarity index 58% rename from modules/wikis/app/controllers/wikis/search_pages_controller.rb rename to modules/wikis/app/controllers/wikis/pages_controller.rb index 636d2f1338b..27b2fed99ae 100644 --- a/modules/wikis/app/controllers/wikis/search_pages_controller.rb +++ b/modules/wikis/app/controllers/wikis/pages_controller.rb @@ -29,14 +29,38 @@ #++ module Wikis - class SearchPagesController < ApplicationController + class PagesController < ApplicationController + include OpTurbo::ComponentStream include Dry::Monads[:result] + before_action :authorize, except: %i[search] + # 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 + no_authorization_required! :search - def show + def create_and_link + # TODO: implement service to create page and link + render_error_flash_message_via_turbo_stream( + message: "Not implemented yet. Trying to create a new page with #{create_new_page_params.to_h}" + ) + respond_to_with_turbo_streams + end + + def create_new_page_dialog + linkable = WorkPackage.visible.find(params.expect(:linkable)) + provider = Provider.visible.find(params.expect(:provider)) + respond_with_dialog Wikis::CreateNewWikiPageDialog.new(linkable:, provider:, title: nil) + end + + def continue_create_new_page_dialog + params = create_new_page_params + linkable = WorkPackage.visible.find(params[:linkable_id]) + provider = Provider.visible.find(params[:provider_id]) + respond_with_dialog Wikis::CreateNewWikiPageDialog.new(linkable:, provider:, title: params[:title]) + end + + def search provider = Provider.visible.find(params.expect(:provider_id)) query = params[:query] form_name = params[:name] @@ -57,5 +81,19 @@ module Wikis end end end + + def create_new_page_params + params.expect(wikis_forms_create_new_wiki_page_form_model: %i[provider_id linkable_type linkable_id title]) + .merge(parent_page_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 end end diff --git a/modules/wikis/app/forms/wikis/create_new_wiki_page_form.rb b/modules/wikis/app/forms/wikis/create_new_wiki_page_form.rb new file mode 100644 index 00000000000..7429568bfb9 --- /dev/null +++ b/modules/wikis/app/forms/wikis/create_new_wiki_page_form.rb @@ -0,0 +1,85 @@ +# 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 CreateNewWikiPageForm < ApplicationForm + form do |f| + f.hidden(name: :provider_id) + f.hidden(name: :linkable_type) + f.hidden(name: :linkable_id) + + if first_step? + f.text_field(name: :title, label: I18n.t("wikis.create_new_wiki_page_dialog.page_title"), required: true) + else + f.hidden(name: :title) + + f.html_content do + render(Primer::Beta::Text.new) { I18n.t("wikis.create_new_wiki_page_dialog.parent_help_text") } + end + + 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 + 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 + + def first_step? + model.title.blank? + end + end +end diff --git a/modules/wikis/app/models/wikis/forms/create_new_wiki_page_form_model.rb b/modules/wikis/app/models/wikis/forms/create_new_wiki_page_form_model.rb new file mode 100644 index 00000000000..ea44329e029 --- /dev/null +++ b/modules/wikis/app/models/wikis/forms/create_new_wiki_page_form_model.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 + module Forms + class CreateNewWikiPageFormModel + extend ActiveModel::Naming + + attr_reader :linkable_id, :linkable_type, :provider_id, :title + + def initialize(linkable:, provider:, title:) + @linkable_id = linkable.id + @linkable_type = linkable.class.name + @provider_id = provider.id + @title = title + end + end + end +end diff --git a/modules/wikis/app/views/wikis/search_pages/show.html.erb b/modules/wikis/app/views/wikis/pages/search.html.erb similarity index 100% rename from modules/wikis/app/views/wikis/search_pages/show.html.erb rename to modules/wikis/app/views/wikis/pages/search.html.erb diff --git a/modules/wikis/config/locales/en.yml b/modules/wikis/config/locales/en.yml index 34bd78b1bbb..413b0063f32 100644 --- a/modules/wikis/config/locales/en.yml +++ b/modules/wikis/config/locales/en.yml @@ -50,6 +50,10 @@ en: delete_relation_page_link_confirmation_dialog: title: Delete related wiki page link heading: Delete related wiki page link? + create_new_wiki_page_dialog: + title: Create new wiki page + page_title: Title + parent_help_text: Select a parent for this new wiki page. health_checks: authentication: existing_token: User token diff --git a/modules/wikis/config/routes.rb b/modules/wikis/config/routes.rb index 242e3c63458..767a6d72acc 100644 --- a/modules/wikis/config/routes.rb +++ b/modules/wikis/config/routes.rb @@ -62,6 +62,7 @@ Rails.application.routes.draw do resources :relation_wiki_page_links, only: %i[create destroy], controller: "wikis/relation_page_links" do collection do get :link_existing_dialog + post :create_and_link_new_wiki_page end member do @@ -73,5 +74,10 @@ Rails.application.routes.draw do get :load end - resource :search_wiki_pages, controller: "wikis/search_pages", only: %i[show] + resource :wiki_pages, controller: "wikis/pages", only: [] do + get :search + get :create_new_page_dialog + post :continue_create_new_page_dialog + post :create_and_link + end end diff --git a/modules/wikis/lib/open_project/wikis/engine.rb b/modules/wikis/lib/open_project/wikis/engine.rb index a8ce614c2cb..cb7ff2a78b1 100644 --- a/modules/wikis/lib/open_project/wikis/engine.rb +++ b/modules/wikis/lib/open_project/wikis/engine.rb @@ -73,7 +73,13 @@ module OpenProject::Wikis project_module :work_package_tracking do permission :manage_wiki_page_links, { - "wikis/relation_page_links": %i[create destroy confirm_delete_dialog link_existing_dialog] + "wikis/pages": %i[create_and_link + create_new_page_dialog + continue_create_new_page_dialog], + "wikis/relation_page_links": %i[create + destroy + confirm_delete_dialog + link_existing_dialog] }, permissible_on: :project, dependencies: %i[edit_work_packages],