[#73352] added create wiki page dialog

- https://community.openproject.org/work_packages/73352
- add new create wiki page dialog and form
- add concept of two step dialog
- consolidated search and create wiki pages into a single controller
This commit is contained in:
Eric Schubert
2026-06-05 13:50:27 +02:00
parent e9157b89f0
commit f1c6776255
11 changed files with 319 additions and 6 deletions
+1
View File
@@ -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
@@ -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 %>
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
+4
View File
@@ -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
+7 -1
View File
@@ -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
@@ -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],