Merge pull request #20347 from opf/implementation/67462-add-filterable-tree-view-component-to-dialog

[#67462] Add filterable tree view for parent selection
This commit is contained in:
Eric Schubert
2025-09-22 16:29:09 +02:00
committed by GitHub
3 changed files with 93 additions and 11 deletions
@@ -28,18 +28,25 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
<%=
render Primer::Alpha::Dialog.new(id: dialog_id, title: I18n.t(:label_change_parent)) do |dialog|
render(
Primer::Alpha::Dialog.new(
id: dialog_id,
title: I18n.t(:label_change_parent),
size: :medium_portrait
)
) do |dialog|
dialog.with_body do
primer_form_with(**form_arguments) do |f|
helpers.render_inline_form(f) do |form|
form.text_field(name: :new_parent, label: "New Parent")
primer_form_with(**form_arguments) do |form|
render(
Primer::OpenProject::FilterableTreeView.new(form_arguments: { builder: form, name: :new_parent })
) do |tree_view|
add_sub_tree(tree_view, hierarchy_items)
end
end
end
dialog.with_footer(show_divider: true) do
concat(render(Primer::Beta::Button.new(data: { close_dialog_id: dialog_id })) { I18n.t(:button_cancel) })
concat(
render(
Primer::Beta::Button.new(
@@ -48,17 +48,50 @@ module Admin
def form_arguments
{
form_id:,
id: form_id,
url: change_parent_custom_field_item_path(custom_field_id: @custom_field.id, id: @hierarchy_item.id),
model: form_model,
method: :post
}
end
def hierarchy_items
hashed_hierarchy = @custom_field.hierarchy_root.hash_tree
hashed_hierarchy.keys.first.label = @custom_field.name
hashed_hierarchy
end
def add_sub_tree(tree, hierarchy_hash)
hierarchy_hash.each do |item, child_hash|
if child_hash.empty?
tree.with_leaf(**item_options(item))
else
expanded = current?(item) || child_hash.any? { |child, _| current?(child) }
tree.with_sub_tree(expanded:, **item_options(item)) do |sub_tree|
add_sub_tree(sub_tree, child_hash)
end
end
end
end
private
def form_model
CustomField::Hierarchy::Forms::NewParentFormModel.new(new_parent: nil)
CustomField::Hierarchy::Forms::NewParentFormModel.new(new_parent: [])
end
def item_options(item)
{
label: item.label,
current: current?(item),
value: item.id
}
end
def current?(item)
item.id == @hierarchy_item.id
end
end
end
@@ -33,6 +33,7 @@ module Admin
module Hierarchy
class ItemsController < ApplicationController
include OpTurbo::ComponentStream
include Dry::Monads[:result]
layout :admin_or_frame_layout
model_object CustomField
@@ -103,11 +104,25 @@ module Admin
end
def change_parent
permitted = params.expect(custom_field_hierarchy_forms_new_parent_form_model: [:new_parent])
new_parent = CustomField::Hierarchy::Item.including_children.find(permitted[:new_parent])
item_service.move_item(item: @active_item, new_parent:)
result = parse_parent_input(new_parent_params).bind do |new_parent|
validate_new_parent(new_parent).bind do
item_service.move_item(item: @active_item, new_parent:)
end
end
redirect_to(custom_field_item_path(@custom_field, new_parent), status: :see_other)
result.either(
->(result) do
redirect_to(
custom_field_item_path(@custom_field, result.parent),
status: :see_other,
notice: I18n.t(:notice_successful_update)
)
end,
->(error) do
render_error_flash_message_via_turbo_stream(message: error)
respond_with_turbo_streams(&:html)
end
)
end
def destroy
@@ -147,6 +162,10 @@ module Admin
input
end
def new_parent_params
params.require(:custom_field_hierarchy_forms_new_parent_form_model).require(:new_parent)
end
def create_contract
case @custom_field.field_format
when "hierarchy"
@@ -184,6 +203,29 @@ module Admin
end
end
def parse_parent_input(new_parent_input)
case new_parent_input
in [new_parent]
input = MultiJson.load(new_parent, symbolize_keys: true)[:value]
new_parent = CustomField::Hierarchy::Item.including_children.find_by(id: input)
if new_parent.present?
Success(new_parent)
else
Failure("Cannot find parent with id: #{input}")
end
else
Failure("Invalid input: #{new_parent_input}")
end
end
def validate_new_parent(new_parent)
return Failure("Parent must not be the same as before.") if @active_item.parent.id == new_parent.id
return Failure("Parent must not be the current item.") if @active_item.id == new_parent.id
Success()
end
def find_model_object
@object = CustomField.hierarchy_root_and_children.find(params[:custom_field_id])
@custom_field = @object