Skip to content

Commit defada7

Browse files
committed
[DREAM-697] Migrate export templates
Ports the export-template selector and its accessible toggles. https://community.openproject.org/wp/DREAM-697
1 parent 908afdf commit defada7

9 files changed

Lines changed: 297 additions & 80 deletions

File tree

app/components/work_package_types/export_template_list_component.html.erb

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,54 +29,50 @@ See COPYRIGHT and LICENSE files for more details.
2929

3030
<%=
3131
component_wrapper(data: wrapper_data_attributes) do
32-
render(border_box_container(mb: 3, data: (readonly? ? {} : drag_and_drop_target_config))) do |component|
33-
component.with_header(font_weight: :bold, py: 2) do
34-
flex_layout(justify_content: :space_between, align_items: :center) do |section_header_container|
35-
section_header_container.with_column(py: 2) do
36-
render(Primer::Beta::Text.new(font_weight: :bold)) do
37-
I18n.t("types.edit.export_configuration.pdf_export_templates.label")
38-
end
32+
render(
33+
OpenProject::Common::BorderBoxListComponent.new(
34+
container: "pdf-export-templates",
35+
position: :relative,
36+
mb: 3,
37+
data: (readonly? ? {} : drag_and_drop_target_config)
38+
)
39+
) do |list|
40+
list.with_header(title: I18n.t("types.edit.export_configuration.pdf_export_templates.label")) do |header|
41+
unless readonly?
42+
header.with_action_button(
43+
tag: :a,
44+
href: enable_all_type_pdf_export_template_index_path(type_id: @type.id),
45+
scheme: :invisible,
46+
font_weight: :bold,
47+
color: :subtle,
48+
aria: { label: t("projects.settings.actions.label_enable_all") },
49+
test_selector: "enable-all-pdf-export-templates",
50+
data: { turbo_method: :put, turbo_stream: true }
51+
) do |button|
52+
button.with_leading_visual_icon(icon: "check-circle", color: :subtle)
53+
I18n.t("types.edit.export_configuration.pdf_export_templates.actions.label_enable_all")
3954
end
40-
unless readonly?
41-
section_header_container.with_column(flex_layout: true, justify_content: :flex_end) do |actions_container|
42-
actions_container.with_column do
43-
render(
44-
Primer::Beta::Button.new(
45-
tag: :a,
46-
href: enable_all_type_pdf_export_template_index_path(type_id: @type.id),
47-
scheme: :invisible,
48-
font_weight: :bold,
49-
color: :subtle,
50-
"aria-label": t("projects.settings.actions.label_enable_all"),
51-
data: { "turbo-method": :put, "turbo-stream": true, test_selector: "enable-all-pdf-export-templates" }
52-
)
53-
) do |button|
54-
button.with_leading_visual_icon(icon: "check-circle", color: :subtle)
55-
I18n.t("types.edit.export_configuration.pdf_export_templates.actions.label_enable_all")
56-
end
57-
end
58-
actions_container.with_column do
59-
render(
60-
Primer::Beta::Button.new(
61-
tag: :a,
62-
href: disable_all_type_pdf_export_template_index_path(type_id: @type.id),
63-
scheme: :invisible,
64-
font_weight: :bold,
65-
color: :subtle,
66-
"aria-label": t("projects.settings.actions.label_disable_all"),
67-
data: { "turbo-method": :put, "turbo-stream": true, test_selector: "disable-all-pdf-export-templates" }
68-
)
69-
) do |button|
70-
button.with_leading_visual_icon(icon: "x-circle", color: :subtle)
71-
I18n.t("types.edit.export_configuration.pdf_export_templates.actions.label_disable_all")
72-
end
73-
end
74-
end
55+
header.with_action_button(
56+
tag: :a,
57+
href: disable_all_type_pdf_export_template_index_path(type_id: @type.id),
58+
scheme: :invisible,
59+
font_weight: :bold,
60+
color: :subtle,
61+
aria: { label: t("projects.settings.actions.label_disable_all") },
62+
test_selector: "disable-all-pdf-export-templates",
63+
data: { turbo_method: :put, turbo_stream: true }
64+
) do |button|
65+
button.with_leading_visual_icon(icon: "x-circle", color: :subtle)
66+
I18n.t("types.edit.export_configuration.pdf_export_templates.actions.label_disable_all")
7567
end
7668
end
7769
end
70+
7871
@type.pdf_export_templates.list.each do |template|
79-
component.with_row(data: (readonly? ? {} : draggable_item_config(template))) do
72+
list.with_item(
73+
test_selector: "pdf-export-template-row-#{template.id}",
74+
data: (readonly? ? {} : draggable_item_config(template))
75+
) do
8076
render(
8177
WorkPackageTypes::ExportTemplateRowComponent.new(
8278
type: @type,

app/components/work_package_types/export_template_list_component.rb

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,16 @@ def wrapper_data_attributes
5454
def drag_and_drop_target_config
5555
{
5656
generic_drag_and_drop_target: "container",
57-
"target-container-accessor": ":scope > ul",
58-
"target-allowed-drag-type": "template",
59-
test_selector: "pdf-export-template-rows"
57+
target_container_accessor: ":scope > ul",
58+
target_allowed_drag_type: "template"
6059
}
6160
end
6261

6362
def draggable_item_config(template)
6463
{
65-
"draggable-id": template.id,
66-
"draggable-type": "template",
67-
"drop-url": drop_type_pdf_export_template_path(type_id: @type.id, id: template.id),
68-
test_selector: "pdf-export-template-row-#{template.id}"
64+
draggable_id: template.id,
65+
draggable_type: "template",
66+
drop_url: drop_type_pdf_export_template_path(type_id: @type.id, id: template.id)
6967
}
7068
end
7169
end

app/components/work_package_types/export_template_row_component.html.erb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,15 @@ See COPYRIGHT and LICENSE files for more details.
5252
enabled: !readonly?,
5353
size: :small,
5454
status_label_position: :start,
55+
aria: { label: toggle_label },
5556
test_selector: "toggle-pdf-export-template-row-#{@template.id}"
5657
}
5758
# A read-only toggle is disabled, so it never posts; omit the mutation wiring entirely.
5859
unless readonly?
5960
toggle_options.merge!(
6061
src: toggle_type_pdf_export_template_path(type_id: @type.id, id: @template.id),
6162
csrf_token: form_authenticity_token,
62-
data: { "turbo-method": :post, "turbo-stream": true },
63+
data: { turbo_method: :post, turbo_stream: true },
6364
classes: "op-primer-adjustments__toggle-switch--hidden-loading-indicator"
6465
)
6566
end

app/components/work_package_types/export_template_row_component.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,18 @@ def initialize(type:, template:, readonly: false)
4343
end
4444

4545
def readonly? = @readonly
46+
47+
def wrapper_uniq_by
48+
@template.id
49+
end
50+
51+
private
52+
53+
def toggle_label
54+
I18n.t(
55+
"types.edit.export_configuration.pdf_export_templates.actions.label_toggle_template",
56+
template: @template.label
57+
)
58+
end
4659
end
4760
end

config/locales/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6148,6 +6148,7 @@ en:
61486148
actions:
61496149
label_disable_all: "Disable all"
61506150
label_enable_all: "Enable all"
6151+
label_toggle_template: "Toggle %{template}"
61516152
label: "PDF Export templates"
61526153
tab: "Generate PDF"
61536154
templates:
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
require "rails_helper"
32+
33+
RSpec.describe WorkPackageTypes::ExportTemplateListComponent, type: :component do
34+
include Rails.application.routes.url_helpers
35+
36+
let(:type) { create(:type) }
37+
let(:draggable_records) { type.pdf_export_templates.list }
38+
39+
subject(:rendered_component) { render_inline(described_class.new(type:)) }
40+
41+
def drop_url_for(template)
42+
drop_type_pdf_export_template_path(type_id: type.id, id: template.id)
43+
end
44+
45+
it_behaves_like "rendering Box", row_count: 3
46+
it_behaves_like "a reorderable Border Box List", drag_type: "template"
47+
48+
it "renders the enable-all and disable-all header actions", :aggregate_failures do
49+
expect(rendered_component).to have_link(accessible_name: I18n.t("projects.settings.actions.label_enable_all"))
50+
expect(rendered_component).to have_link(accessible_name: I18n.t("projects.settings.actions.label_disable_all"))
51+
end
52+
53+
it "renders a unique wrapper for each template row" do
54+
draggable_records.each do |template|
55+
expect(rendered_component)
56+
.to have_css("#work-package-types-export-template-row-component-#{template.id}", count: 1)
57+
end
58+
end
59+
60+
it "labels each template toggle button with its template" do
61+
draggable_records.each do |template|
62+
expect(rendered_component).to have_button(
63+
accessible_name: I18n.t(
64+
"types.edit.export_configuration.pdf_export_templates.actions.label_toggle_template",
65+
template: template.label
66+
),
67+
aria: { pressed: template.enabled }
68+
)
69+
end
70+
end
71+
72+
context "when readonly" do
73+
subject(:rendered_component) { render_inline(described_class.new(type:, readonly: true)) }
74+
75+
it "renders no drag-and-drop wiring", :aggregate_failures do
76+
expect(rendered_component).to have_no_css('[data-controller~="generic-drag-and-drop"]')
77+
expect(rendered_component).to have_no_css("[data-generic-drag-and-drop-target]")
78+
expect(rendered_component).to have_no_css("[data-draggable-id]")
79+
expect(rendered_component).to have_no_css(".op-draggable-list-item--drag-handle")
80+
end
81+
82+
it "renders no header actions", :aggregate_failures do
83+
expect(rendered_component).to have_no_link(accessible_name: I18n.t("projects.settings.actions.label_enable_all"))
84+
expect(rendered_component).to have_no_link(accessible_name: I18n.t("projects.settings.actions.label_disable_all"))
85+
end
86+
end
87+
end

spec/components/work_package_types/export_template_row_component_spec.rb

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
require "rails_helper"
3232

3333
RSpec.describe WorkPackageTypes::ExportTemplateRowComponent, type: :component do
34+
include Rails.application.routes.url_helpers
35+
3436
let(:type) { create(:type) }
3537
let(:template) { Type::PdfExportTemplates::Template.new(id: 1, label: "Full", caption: "A4", enabled: true) }
3638

@@ -45,11 +47,31 @@
4547
end
4648

4749
context "when editable (default)" do
50+
subject(:rendered_component) { render_inline(described_class.new(type:, template:)) }
51+
4852
it "renders an interactive toggle switch", :aggregate_failures do
49-
render_inline(described_class.new(type:, template:))
53+
expect(rendered_component).to have_css("[data-test-selector='toggle-pdf-export-template-row-1']")
54+
expect(rendered_component).to have_no_css(".ToggleSwitch--disabled")
55+
end
5056

51-
expect(page).to have_css("[data-test-selector='toggle-pdf-export-template-row-1']")
52-
expect(page).to have_no_css(".ToggleSwitch--disabled")
57+
it "renders a unique wrapper derived from the template id" do
58+
expect(rendered_component)
59+
.to have_css("#work-package-types-export-template-row-component-#{template.id}", count: 1)
60+
end
61+
62+
it "renders the template label and caption" do
63+
expect(rendered_component).to have_text(template.label)
64+
expect(rendered_component).to have_text(template.caption)
65+
end
66+
67+
it "labels the toggle button with its template and reflects the enabled state" do
68+
expect(rendered_component).to have_button(
69+
accessible_name: I18n.t(
70+
"types.edit.export_configuration.pdf_export_templates.actions.label_toggle_template",
71+
template: template.label
72+
),
73+
aria: { pressed: template.enabled }
74+
)
5375
end
5476
end
5577
end

spec/features/types/export_configuration_spec.rb

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,46 +41,57 @@
4141
visit edit_type_pdf_export_template_index_path(type)
4242
end
4343

44-
def within_pdf_export_template_container(template_id, &)
45-
within("[data-test-selector='pdf-export-template-row-#{template_id}']", &)
44+
def within_pdf_export_template_container(template, &)
45+
within_test_selector("pdf-export-template-row-#{template.id}", &)
4646
end
4747

48-
def toggle_pdf_export_template(template_id)
49-
page
50-
.find("[data-test-selector='toggle-pdf-export-template-row-#{template_id}'] > button")
51-
.click
48+
def toggle_pdf_export_template(template)
49+
find(:button, accessible_name: toggle_pdf_export_template_label(template)).click
5250
end
5351

54-
def expect_checked_state
55-
expect(page).to have_css(".ToggleSwitch-statusOn")
52+
def expect_checked_state(template)
53+
expect(page).to have_button(
54+
accessible_name: toggle_pdf_export_template_label(template),
55+
aria: { pressed: true }
56+
)
5657
end
5758

58-
def expect_unchecked_state
59-
expect(page).to have_css(".ToggleSwitch-statusOff")
59+
def expect_unchecked_state(template)
60+
expect(page).to have_button(
61+
accessible_name: toggle_pdf_export_template_label(template),
62+
aria: { pressed: false }
63+
)
64+
end
65+
66+
def toggle_pdf_export_template_label(template)
67+
I18n.t(
68+
"types.edit.export_configuration.pdf_export_templates.actions.label_toggle_template",
69+
template: template.label
70+
)
6071
end
6172

6273
it "disables/enables all" do
63-
page.find("[data-test-selector='disable-all-pdf-export-templates']").click
74+
click_link(I18n.t("types.edit.export_configuration.pdf_export_templates.actions.label_disable_all"))
6475
wait_for_reload
6576
type.reload
6677
expect(type.pdf_export_templates.list_enabled.length).to eq(0)
67-
page.find("[data-test-selector='enable-all-pdf-export-templates']").click
78+
click_link(I18n.t("types.edit.export_configuration.pdf_export_templates.actions.label_enable_all"))
6879
wait_for_reload
6980
type.reload
7081
expect(type.pdf_export_templates.list_enabled.length).to eq(type.pdf_export_templates.list.length)
7182
end
7283

7384
it "disables/enables one" do
7485
first = type.pdf_export_templates.list_enabled.first
75-
within_pdf_export_template_container(first.id) do
76-
expect_checked_state
77-
toggle_pdf_export_template(first.id)
78-
expect_unchecked_state
86+
within_pdf_export_template_container(first) do
87+
expect_checked_state(first)
88+
toggle_pdf_export_template(first)
89+
expect_unchecked_state(first)
7990
wait_for_reload
8091
type.reload
8192
expect(type.pdf_export_templates.list.first.enabled).to be(false)
82-
toggle_pdf_export_template(first.id)
83-
expect_checked_state
93+
toggle_pdf_export_template(first)
94+
expect_checked_state(first)
8495
wait_for_reload
8596
type.reload
8697
expect(type.pdf_export_templates.list.first.enabled).to be(true)
@@ -90,10 +101,13 @@ def expect_unchecked_state
90101
it "reorders by drag and drop" do
91102
first_id = type.pdf_export_templates.list_enabled.first.id
92103
second_id = type.pdf_export_templates.list_enabled[1].id
93-
source = page.find("[data-test-selector='pdf-export-template-row-#{first_id}'] .DragHandle")
94-
target = page.find("[data-test-selector='pdf-export-template-row-#{second_id}'] .DragHandle")
95-
source.native.drag_to(target.native, delay: 0.1)
96-
sleep 1
104+
Pages::Page.new.drag_and_drop_list(
105+
from: 0,
106+
to: 1,
107+
elements: "[data-test-selector^='pdf-export-template-row-']",
108+
handler: ".DragHandle"
109+
)
110+
wait_for_network_idle
97111

98112
type.reload
99113
expect(type.pdf_export_templates.list[1].id).to eq(first_id)

0 commit comments

Comments
 (0)