Skip to content

Commit

Permalink
Merge branch 'dev' into implementation/58520-api-add-endpoint-for-fet…
Browse files Browse the repository at this point in the history
…ching-the-tree
  • Loading branch information
apfohl committed Nov 4, 2024
2 parents 06d22cf + 63b49cf commit 435d1c3
Show file tree
Hide file tree
Showing 131 changed files with 2,383 additions and 805 deletions.
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ gem "appsignal", "~> 3.10.0", require: false

gem "view_component"
# Lookbook
gem "lookbook", "~> 2.3.3"
gem "lookbook", "~> 2.3.4"

# Require factory_bot for usage with openproject plugins testing
gem "factory_bot", "~> 6.5.0", require: false
Expand Down Expand Up @@ -322,6 +322,7 @@ group :development, :test do
gem "rack-mini-profiler", require: false
gem "ruby-prof", require: false
gem "stackprof", require: false
gem "vernier", require: false

# Output a stack trace anytime, useful when a process is stuck
gem "rbtrace"
Expand Down
8 changes: 5 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ GEM
bigdecimal
rexml
crass (1.0.6)
css_parser (1.19.0)
css_parser (1.19.1)
addressable
csv (3.3.0)
cuprite (0.15.1)
Expand Down Expand Up @@ -727,7 +727,7 @@ GEM
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
lookbook (2.3.3)
lookbook (2.3.4)
activemodel
css_parser
htmlbeautifier (~> 1.3)
Expand Down Expand Up @@ -1147,6 +1147,7 @@ GEM
public_suffix
vcr (6.3.1)
base64
vernier (1.2.1)
view_component (3.19.0)
activesupport (>= 5.2.0, < 8.1)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -1272,7 +1273,7 @@ DEPENDENCIES
letter_opener_web
listen (~> 3.9.0)
lograge (~> 0.14.0)
lookbook (~> 2.3.3)
lookbook (~> 2.3.4)
mail (= 2.8.1)
markly (~> 0.10)
matrix (~> 0.4.2)
Expand Down Expand Up @@ -1395,6 +1396,7 @@ DEPENDENCIES
tzinfo-data (~> 1.2024.1)
validate_url
vcr
vernier
view_component
warden (~> 1.2)
warden-basic_auth (~> 0.2.1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ See COPYRIGHT and LICENSE files for more details.
++#%>

<%=
render(Primer::Alpha::Dialog.new(id: DIALOG_ID,
title: "Delete item",
data: { test_selector: TEST_SELECTOR })) do |dialog|
render(Primer::Alpha::Dialog.new(id: DIALOG_ID, title: "Delete item", test_selector: TEST_SELECTOR)) do |dialog|
dialog.with_header(variant: :large)
dialog.with_body do
"Are you sure you want to delete this item from the current hierarchy level?"
Expand All @@ -42,14 +40,12 @@ See COPYRIGHT and LICENSE files for more details.
end)

concat(primer_form_with(
model: @custom_field,
url: custom_field_item_path(custom_field_id: @custom_field.id, id: @hierarchy_item.id),
method: :delete,
data: { turbo: true }
) do
render(Primer::ButtonComponent.new(scheme: :danger,
type: :submit,
data: { "close-dialog-id": DIALOG_ID })) do
model: @custom_field,
url: custom_field_item_path(custom_field_id: @custom_field.id, id: @hierarchy_item.id),
method: :delete,
data: { turbo: true }
) do
render(Primer::ButtonComponent.new(scheme: :danger, type: :submit, data: { "close-dialog-id": DIALOG_ID })) do
I18n.t(:button_delete)
end
end)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,42 @@ See COPYRIGHT and LICENSE files for more details.
++#%>

<%=
component_wrapper(data: { test_selector: "op-custom-fields--hierarchy-item" }) do
if show_edit_form?
render Admin::CustomFields::Hierarchy::ItemFormComponent.new(
custom_field: @custom_field,
hierarchy_item: @hierarchy_item,
url: custom_field_item_path(@custom_field, @hierarchy_item),
method: :put,
label: @edit_item_form_data.fetch(:label, nil),
short: @edit_item_form_data.fetch(:short, nil)
)
component_wrapper(tag: "turbo-frame", refresh: :morph) do
if show_form?
render Admin::CustomFields::Hierarchy::ItemFormComponent.new(model)
else
flex_layout(align_items: :center, justify_content: :space_between) do |item_container|
flex_layout(align_items: :center, justify_content: :space_between, test_selector: "op-custom-fields--hierarchy-item") do |item_container|
item_container.with_column(flex_layout: true) do |item_information|
item_information.with_column(mr: 2) do
render(Primer::Beta::Text.new(font_weight: :bold)) do
@hierarchy_item.label
render(Primer::OpenProject::DragHandle.new)
end
item_information.with_column(mr: 2) do
render(Primer::Beta::Link.new(href: custom_field_item_path(@root.custom_field_id, model), underline: false)) do
render(Primer::Beta::Text.new(font_weight: :bold)) { model.label }
end
end

unless @hierarchy_item.short.nil?
if model.short.present?
item_information.with_column(mr: 2) do
render(Primer::Beta::Text.new(color: :subtle)) { short_text }
end
end

# Actions
item_container.with_column do
render(Primer::Alpha::ActionMenu.new(data: { test_selector: "op-hierarchy-item--action-menu" })) do |menu|
menu.with_show_button(icon: "kebab-horizontal",
scheme: :invisible,
"aria-label": I18n.t("custom_fields.admin.items.actions"))
edit_action_item(menu)
deletion_action_item(menu)
if model.children.any?
item_information.with_column(mr: 2) do
render(Primer::Beta::Text.new) { children_count }
end
end
end

item_container.with_column do
render(Primer::Alpha::ActionMenu.new(test_selector: "op-hierarchy-item--action-menu")) do |menu|
menu.with_show_button(icon: "kebab-horizontal",
scheme: :invisible,
"aria-label": I18n.t("custom_fields.admin.items.actions"))
menu_items(menu)
end
end
end
end
end
Expand Down
115 changes: 94 additions & 21 deletions app/components/admin/custom_fields/hierarchy/item_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,44 +35,117 @@ class ItemComponent < ApplicationComponent
include OpTurbo::Streamable
include OpPrimer::ComponentHelpers

def initialize(custom_field:, hierarchy_item:, edit_item_form_data: { show: false })
super
@custom_field = custom_field
@hierarchy_item = hierarchy_item
@edit_item_form_data = edit_item_form_data
def initialize(item:, show_edit_form: false)
super(item)
@show_edit_form = show_edit_form
@root = item.root || item.parent.root
end

def wrapper_uniq_by
model.id
end

def short_text
"(#{@hierarchy_item.short})"
"(#{model.short})"
end

def wrapper_uniq_by
@hierarchy_item.id
def show_form? = @show_edit_form || model.new_record?

def children_count
I18n.t("custom_fields.admin.hierarchy.subitems", count: model.children.count)
end

def show_edit_form?
@edit_item_form_data.fetch(:show, false)
def first_item?
model.sort_order == 0
end

def deletion_action_item(menu)
menu.with_item(label: I18n.t(:button_delete),
scheme: :danger,
tag: :a,
href: deletion_dialog_custom_field_item_path(custom_field_id: @custom_field.id,
id: @hierarchy_item.id),
content_arguments: { data: { controller: "async-dialog" } }) do |item|
item.with_leading_visual_icon(icon: :trash)
end
def last_item?
model.sort_order == model.parent.children.length - 1
end

def menu_items(menu)
edit_action_item(menu)
menu.with_divider
add_above_action_item(menu)
add_below_action_item(menu)
add_sub_item_action_item(menu)
menu.with_divider
move_up_action_item(menu) unless first_item?
move_down_action_item(menu) unless last_item?
menu.with_divider
deletion_action_item(menu)
end

private

def edit_action_item(menu)
menu.with_item(label: I18n.t(:button_edit),
tag: :a,
content_arguments: { data: { turbo_stream: true } },
href: edit_custom_field_item_path(@custom_field, @hierarchy_item)) do |item|
href: edit_custom_field_item_path(@root.custom_field_id, model)) do |item|
item.with_leading_visual_icon(icon: :pencil)
end
end

def add_above_action_item(menu)
menu.with_item(
label: I18n.t(:button_add_item_above),
tag: :a,
content_arguments: { data: { turbo_frame: ItemsComponent.wrapper_key } },
href: new_child_custom_field_item_path(@root.custom_field_id, model.parent, position: model.sort_order)
) { _1.with_leading_visual_icon(icon: "fold-up") }
end

def add_below_action_item(menu)
menu.with_item(
label: I18n.t(:button_add_item_below),
tag: :a,
content_arguments: { data: { turbo_frame: ItemsComponent.wrapper_key } },
href: new_child_custom_field_item_path(@root.custom_field_id, model.parent, position: model.sort_order + 1)
) { _1.with_leading_visual_icon(icon: "fold-down") }
end

def add_sub_item_action_item(menu)
menu.with_item(
label: I18n.t(:button_add_sub_item),
tag: :a,
content_arguments: { data: { turbo_frame: ItemsComponent.wrapper_key } },
href: new_child_custom_field_item_path(@root.custom_field_id, model)
) { _1.with_leading_visual_icon(icon: "op-arrow-in") }
end

def move_up_action_item(menu)
form_inputs = [{ name: "new_sort_order", value: model.sort_order - 1 }]

menu.with_item(label: I18n.t(:label_sort_higher),
tag: :button,
href: move_custom_field_item_path(@root.custom_field_id, model),
content_arguments: { data: { turbo_frame: ItemsComponent.wrapper_key } },
form_arguments: { method: :post, inputs: form_inputs }) do |item|
item.with_leading_visual_icon(icon: "chevron-up")
end
end

def move_down_action_item(menu)
form_inputs = [{ name: "new_sort_order", value: model.sort_order + 2 }]

menu.with_item(label: I18n.t(:label_sort_lower),
tag: :button,
href: move_custom_field_item_path(@root.custom_field_id, model),
content_arguments: { data: { turbo_frame: ItemsComponent.wrapper_key } },
form_arguments: { method: :post, inputs: form_inputs }) do |item|
item.with_leading_visual_icon(icon: "chevron-down")
end
end

def deletion_action_item(menu)
menu.with_item(label: I18n.t(:button_delete),
scheme: :danger,
tag: :a,
href: deletion_dialog_custom_field_item_path(custom_field_id: @root.custom_field_id, id: model.id),
content_arguments: { data: { controller: "async-dialog" } }) do |item|
item.with_leading_visual_icon(icon: :trash)
end
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,7 @@ See COPYRIGHT and LICENSE files for more details.
++#%>

<%=
primer_form_with(url: @url, method: @method, data: { test_selector: "op-custom-fields--new-item-form" }) do |f|
render(CustomFields::Hierarchy::ItemForm.new(
f,
custom_field: @custom_field,
hierarchy_item: @hierarchy_item,
label: @label,
short: @short
))
primer_form_with(**item_options) do |f|
render(CustomFields::Hierarchy::ItemForm.new(f, target_item: model))
end
%>
33 changes: 23 additions & 10 deletions app/components/admin/custom_fields/hierarchy/item_form_component.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
Expand Down Expand Up @@ -32,18 +34,29 @@ module Hierarchy
class ItemFormComponent < ApplicationComponent
include OpTurbo::Streamable

def initialize(custom_field:, hierarchy_item:, url:, method:, label: nil, short: nil)
super
@custom_field = custom_field
@hierarchy_item = hierarchy_item
@url = url
@method = method
@label = label || @hierarchy_item.label
@short = short || @hierarchy_item.short
def item_options
options = { url:, method: http_verb, data: { test_selector: "op-custom-fields--new-item-form" } }
options[:data][:turbo_frame] = ItemsComponent.wrapper_key if model.new_record?

options
end

def http_verb
model.new_record? ? :post : :put
end

def items_path
custom_field_items_path(@custom_field)
def url
if model.new_record?
new_child_custom_field_item_path(root.custom_field_id, model.parent)
else
custom_field_item_path(root.custom_field_id, model)
end
end

private

def root
@root ||= model.new_record? ? model.parent.root : model.root
end
end
end
Expand Down
Loading

0 comments on commit 435d1c3

Please sign in to comment.