From 12c3fd3160e191b15ee9a042bec1e5b7bde1cb34 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 27 Mar 2024 09:50:17 +0100 Subject: [PATCH 01/39] update core with new primer view components and update page header component in members page --- Gemfile | 2 +- .../index_page_header_component.html.erb | 54 +++++++------------ .../members/index_page_header_component.rb | 8 ++- frontend/package.json | 4 +- .../openproject/_primer-adjustments.sass | 2 +- 5 files changed, 30 insertions(+), 40 deletions(-) diff --git a/Gemfile b/Gemfile index 057eea92f93d..25643486cbc6 100644 --- a/Gemfile +++ b/Gemfile @@ -383,4 +383,4 @@ end gem "openproject-octicons", "~>19.8.0" gem "openproject-octicons_helper", "~>19.8.0" -gem "openproject-primer_view_components", "~>0.23.0" +gem "openproject-primer_view_components", "~>0.25.0" diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index bcafd0374962..3d3c7ee665d9 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -1,39 +1,25 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| header.with_title { t(:label_member_plural) } - - header.with_actions do - flex_layout do |actions| - if User.current.allowed_in_project?(:manage_members, @project) - actions.with_column(mr: BUTTON_MARGIN_RIGHT) do - render( - Primer::Beta::Button.new( - scheme: :primary, - size: :medium, - aria: { label: I18n.t(:button_add_member) }, - title: I18n.t(:button_add_member), - id: 'add-member-button', - data: add_button_data_attributes - ) - ) do |button| - button.with_leading_visual_icon(icon: :plus) - t('activerecord.models.member') - end - end - end - - actions.with_column do - render( - Primer::Beta::IconButton.new( - icon: 'filter', - id: 'filter-member-button', - aria: { label: I18n.t(:description_filter) }, - class: 'toggle-member-filter-link', - data: filter_button_data_attributes - ) - ) - end - end + header.with_breadcrumbs(breadcrumbs_items) + header.with_action_button(scheme: :primary, + mobile_icon: :plus, + mobile_label: t('activerecord.models.member'), + size: :medium, + aria: { label: I18n.t(:button_add_member) }, + title: I18n.t(:button_add_member), + id: 'add-member-button', + data: add_button_data_attributes) do |button| + button.with_leading_visual_icon(icon: :plus) + t('activerecord.models.member') + end + header.with_action_icon_button(mobile_icon: "filter", + scheme: :default, + icon: 'filter', + label: I18n.t(:description_filter), + id: 'filter-member-button', + aria: { label: I18n.t(:description_filter) }, + class: 'toggle-member-filter-link', + data: filter_button_data_attributes) end - end %> diff --git a/app/components/members/index_page_header_component.rb b/app/components/members/index_page_header_component.rb index 485aa1e1b6a4..79f07835a19d 100644 --- a/app/components/members/index_page_header_component.rb +++ b/app/components/members/index_page_header_component.rb @@ -32,8 +32,6 @@ class Members::IndexPageHeaderComponent < ApplicationComponent include OpPrimer::ComponentHelpers include ApplicationHelper - BUTTON_MARGIN_RIGHT = 2 - def initialize(project: nil) super @project = project @@ -57,4 +55,10 @@ def filter_button_data_attributes action: "members-form#toggleMemberFilter" } end + + def breadcrumbs_items + [{ href: project_overview_path(@project.id), text: @project.name }, + { href: project_members_path(@project), text: t(:label_member_plural) }, + "test"] + end end diff --git a/frontend/package.json b/frontend/package.json index 7728be97533a..cd8a13ded2e5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -98,7 +98,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.23.0", + "@openproject/primer-view-components": "^0.25.0", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -176,6 +176,6 @@ "generate-typings": "tsc -d -p src/tsconfig.app.json" }, "overrides": { - "@primer/view-components": "npm:@openproject/primer-view-components@^0.23.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.25.0" } } diff --git a/frontend/src/global_styles/openproject/_primer-adjustments.sass b/frontend/src/global_styles/openproject/_primer-adjustments.sass index c764da5e6f64..aa4fee7f6263 100644 --- a/frontend/src/global_styles/openproject/_primer-adjustments.sass +++ b/frontend/src/global_styles/openproject/_primer-adjustments.sass @@ -49,7 +49,7 @@ ul.tabnav-tabs margin-left: 0 /* Remove margin-left: 2rem from Breadcrumbs */ -#breadcrumb +#breadcrumb,page-header ol margin-left: 0 .breadcrumb-item.breadcrumb-item-selected From 24d9a42bf8f8252b54abc5f6298efca677c4c2a8 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 27 Mar 2024 12:37:59 +0100 Subject: [PATCH 02/39] update page header in project attributes page --- app/views/projects/settings/project_custom_fields/show.html.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/projects/settings/project_custom_fields/show.html.erb b/app/views/projects/settings/project_custom_fields/show.html.erb index c6fae909ca8f..748bf6e70c7e 100644 --- a/app/views/projects/settings/project_custom_fields/show.html.erb +++ b/app/views/projects/settings/project_custom_fields/show.html.erb @@ -33,6 +33,7 @@ See COPYRIGHT and LICENSE files for more details. overview_url: project_path(@project), admin_settings_url: admin_settings_project_custom_fields_path ).html_safe } %> + <%= header.with_breadcrumbs([{ href: project_overview_path(@project.id), text: @project.name }, t('settings.project_attributes.heading')]) %> <% end %> <%= render(Projects::Settings::ProjectCustomFieldSections::IndexComponent.new( project: @project, From 8f2b9f266e1470d41d10b7c1f7151644a43089b1 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 27 Mar 2024 14:19:09 +0100 Subject: [PATCH 03/39] update page header in projects index page --- .../index_page_header_component.html.erb | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/app/components/projects/index_page_header_component.html.erb b/app/components/projects/index_page_header_component.html.erb index a6df042494ce..43a7786cdbc6 100644 --- a/app/components/projects/index_page_header_component.html.erb +++ b/app/components/projects/index_page_header_component.html.erb @@ -1,38 +1,33 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| %> <% if show_state? %> <% header.with_title(data: { 'test-selector': 'project-query-name'}) { page_title } %> + <% header.with_breadcrumbs([{href: projects_path, text: t('en.types.edit.projects')}, page_title])%> - <% header.with_actions do %> - <% if query_saveable? %> - <%= render( - Primer::Beta::Text.new(tag: :span, - mr: BUTTON_MARGIN_RIGHT, - color: :muted)) do - t('lists.can_be_saved_as') - end - %> - <%= render( - Primer::Beta::Button.new(scheme: :invisible, - size: :medium, - mr: BUTTON_MARGIN_RIGHT, - tag: :a, - href: new_projects_query_path, - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - }, - classes: 'Button--invisibleOP')) do |button| - button.with_leading_visual_icon(icon: :'op-save') + <% if query_saveable? %> + <% header.with_action_text(tag: :span, + mr: BUTTON_MARGIN_RIGHT, + color: :muted) { t('lists.can_be_saved_as') } %> + <% header.with_action_button(mobile_icon: "op-save", mobile_label: t('button_save_as'), + scheme: :invisible, + size: :medium, + mr: BUTTON_MARGIN_RIGHT, + tag: :a, + href: new_projects_query_path, + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + }, + classes: 'Button--invisibleOP') do |button|%> + <% button.with_leading_visual_icon(icon: "op-save") %> t('button_save_as') - end %> - <% end %> + <% end %> - <%= render(Primer::Alpha::ActionMenu.new) do |menu| - menu.with_show_button(icon: 'op-kebab-vertical', 'aria-label': t(:label_more), data: { 'test-selector': 'project-more-dropdown-menu' }) + <% end %> + <%= header.with_action_menu(menu_arguments: { anchor_align: :end }, button_arguments: { icon: "op-kebab-vertical", "aria-label": t(:label_more), data: { 'test-selector': 'project-more-dropdown-menu' } }) do |menu, button| if gantt_portfolio_project_ids.any? menu.with_item( tag: :a, @@ -94,7 +89,6 @@ end end %> - <% end %> <% else %> <% header.with_title(mt: 2, mb: 2, data: { 'test-selector': 'project-query-name'}) do From 2b21ffe5ca45fec2913a1c67ab3225c4b2b0c04e Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 27 Mar 2024 16:04:01 +0100 Subject: [PATCH 04/39] update page header in virus scanning page --- app/views/admin/settings/virus_scanning_settings/show.html.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/admin/settings/virus_scanning_settings/show.html.erb b/app/views/admin/settings/virus_scanning_settings/show.html.erb index 15a4fc77c6be..72e2e1c1e2ac 100644 --- a/app/views/admin/settings/virus_scanning_settings/show.html.erb +++ b/app/views/admin/settings/virus_scanning_settings/show.html.erb @@ -32,6 +32,9 @@ See COPYRIGHT and LICENSE files for more details. <% header.with_title do %> <%= t('settings.antivirus.title') %> <% end %> + <% header.with_breadcrumbs([{href: admin_index_path, text: t('label_administration')}, + {href: admin_settings_attachments_path, text: t('attributes.attachments')}, + t('settings.antivirus.title')])%> <% end %> <%= styled_form_tag( From 9ad93c75172a75222be1236f8f407e92e783f916 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 27 Mar 2024 16:20:43 +0100 Subject: [PATCH 05/39] update page header in Quarantined attachments page --- .../admin/attachments/quarantined_attachments/index.html.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/admin/attachments/quarantined_attachments/index.html.erb b/app/views/admin/attachments/quarantined_attachments/index.html.erb index 65c0cdd75795..e6d642c268be 100644 --- a/app/views/admin/attachments/quarantined_attachments/index.html.erb +++ b/app/views/admin/attachments/quarantined_attachments/index.html.erb @@ -3,6 +3,9 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| header.with_title(variant: :large) { t('antivirus_scan.quarantined_attachments.title') } + header.with_breadcrumbs([{href: admin_index_path, text: t('label_administration')}, + {href: admin_settings_attachments_path, text: t('attributes.attachments')}, + t('antivirus_scan.quarantined_attachments.title')]) end %> From 108490dd49a191eafcf50854dc9db001877d8076 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 12:35:36 +0100 Subject: [PATCH 06/39] use one breadcrumb in virus scanning page --- .../settings/virus_scanning_settings_controller.rb | 12 +++++++++--- .../settings/virus_scanning_settings/show.html.erb | 4 +--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/controllers/admin/settings/virus_scanning_settings_controller.rb b/app/controllers/admin/settings/virus_scanning_settings_controller.rb index 842990f4a726..841464c503e9 100644 --- a/app/controllers/admin/settings/virus_scanning_settings_controller.rb +++ b/app/controllers/admin/settings/virus_scanning_settings_controller.rb @@ -33,10 +33,9 @@ class VirusScanningSettingsController < ::Admin::SettingsController before_action :require_ee before_action :check_clamav, only: %i[update], if: -> { scan_enabled? } - def default_breadcrumb - t("settings.antivirus.title") + def show_local_breadcrumb + false end - def av_form selected = params.dig(:settings, :antivirus_scan_mode)&.to_sym || :disabled @@ -102,5 +101,12 @@ def remaining_quarantine_warning file_count: t(:label_x_files, count: Attachment.status_quarantined.count)) redirect_to action: :show end + + def breadcrumb_items + [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_attachments_path, text: t("attributes.attachments") }, + t("settings.antivirus.title")] + end + helper_method :breadcrumb_items end end diff --git a/app/views/admin/settings/virus_scanning_settings/show.html.erb b/app/views/admin/settings/virus_scanning_settings/show.html.erb index 72e2e1c1e2ac..1550ba9bba95 100644 --- a/app/views/admin/settings/virus_scanning_settings/show.html.erb +++ b/app/views/admin/settings/virus_scanning_settings/show.html.erb @@ -32,9 +32,7 @@ See COPYRIGHT and LICENSE files for more details. <% header.with_title do %> <%= t('settings.antivirus.title') %> <% end %> - <% header.with_breadcrumbs([{href: admin_index_path, text: t('label_administration')}, - {href: admin_settings_attachments_path, text: t('attributes.attachments')}, - t('settings.antivirus.title')])%> + <% header.with_breadcrumbs(breadcrumb_items)%> <% end %> <%= styled_form_tag( From 6a91890e7e84fef11f38753bc11b24e50e0d9cc0 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 12:48:51 +0100 Subject: [PATCH 07/39] use one breadcrumb in quarantined attachments page --- .../quarantined_attachments_controller.rb | 13 ++++++++----- .../quarantined_attachments/index.html.erb | 4 +--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/controllers/admin/attachments/quarantined_attachments_controller.rb b/app/controllers/admin/attachments/quarantined_attachments_controller.rb index 8856adcce0c9..6df31b1b4e8d 100644 --- a/app/controllers/admin/attachments/quarantined_attachments_controller.rb +++ b/app/controllers/admin/attachments/quarantined_attachments_controller.rb @@ -51,12 +51,8 @@ def destroy redirect_to action: :index end - def default_breadcrumb - t("antivirus_scan.quarantined_attachments.title") - end - def show_local_breadcrumb - true + false end private @@ -78,6 +74,13 @@ def find_attachment rescue ActiveRecord::RecordNotFound render_404 end + + def breadcrumb_items + [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_attachments_path, text: t("attributes.attachments") }, + t("antivirus_scan.quarantined_attachments.title")] + end + helper_method :breadcrumb_items end end end diff --git a/app/views/admin/attachments/quarantined_attachments/index.html.erb b/app/views/admin/attachments/quarantined_attachments/index.html.erb index e6d642c268be..1a8524e0dcc4 100644 --- a/app/views/admin/attachments/quarantined_attachments/index.html.erb +++ b/app/views/admin/attachments/quarantined_attachments/index.html.erb @@ -3,9 +3,7 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| header.with_title(variant: :large) { t('antivirus_scan.quarantined_attachments.title') } - header.with_breadcrumbs([{href: admin_index_path, text: t('label_administration')}, - {href: admin_settings_attachments_path, text: t('attributes.attachments')}, - t('antivirus_scan.quarantined_attachments.title')]) + header.with_breadcrumbs(breadcrumb_items) end %> From 555b1418fed0fe8d7c181dac5022f8b9b784c2ec Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 12:50:52 +0100 Subject: [PATCH 08/39] show breadcrumb in project attributes page --- .../projects/settings/project_custom_fields_controller.rb | 6 ++++++ .../projects/settings/project_custom_fields/show.html.erb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects/settings/project_custom_fields_controller.rb b/app/controllers/projects/settings/project_custom_fields_controller.rb index 9dbcb329fe5a..b6bd57987504 100644 --- a/app/controllers/projects/settings/project_custom_fields_controller.rb +++ b/app/controllers/projects/settings/project_custom_fields_controller.rb @@ -106,4 +106,10 @@ def bulk_edit_service project_custom_field_section: @project_custom_field_section ) end + + def breadcrumb_items + [{ href: project_overview_path(@project.id), text: @project.name }, + t("settings.project_attributes.heading")] + end + helper_method :breadcrumb_items end diff --git a/app/views/projects/settings/project_custom_fields/show.html.erb b/app/views/projects/settings/project_custom_fields/show.html.erb index 748bf6e70c7e..d0e42b6b05a1 100644 --- a/app/views/projects/settings/project_custom_fields/show.html.erb +++ b/app/views/projects/settings/project_custom_fields/show.html.erb @@ -33,7 +33,7 @@ See COPYRIGHT and LICENSE files for more details. overview_url: project_path(@project), admin_settings_url: admin_settings_project_custom_fields_path ).html_safe } %> - <%= header.with_breadcrumbs([{ href: project_overview_path(@project.id), text: @project.name }, t('settings.project_attributes.heading')]) %> + <%= header.with_breadcrumbs(breadcrumb_items) %> <% end %> <%= render(Projects::Settings::ProjectCustomFieldSections::IndexComponent.new( project: @project, From cf7bf7c83e237c41aaa9509e96b4d66efed051b5 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 12:53:10 +0100 Subject: [PATCH 09/39] show breadcrumb in project attributes edit page --- .../edit_form_header_component.html.erb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.html.erb b/app/components/settings/project_custom_fields/edit_form_header_component.html.erb index 4009432e3974..0510a87b407e 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.html.erb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.html.erb @@ -27,12 +27,9 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <%= - render(Primer::OpenProject::PageHeader.new) do |header| + render(Primer::Ï.new) do |header| header.with_title(variant: :medium) { @custom_field.name } header.with_description { t('settings.project_attributes.edit.description') } - header.with_parent_link(href: admin_settings_project_custom_fields_path, 'aria-label': I18n.t("button_back")) do - t('settings.project_attributes.heading') - end - header.with_back_button(href: admin_settings_project_custom_fields_path, 'aria-label': t('button_back')) + header.with_breadcrumbs(breadcrumbs_items) end -%> \ No newline at end of file +%> From e1529563e7bc98bb119e47fd86817d5646bf2eab Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 12:55:09 +0100 Subject: [PATCH 10/39] show breadcrumb in header component of project attributes page --- .../edit_form_header_component.rb | 5 +++ .../header_component.html.erb | 43 +++++++++---------- .../project_custom_fields/header_component.rb | 4 ++ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.rb b/app/components/settings/project_custom_fields/edit_form_header_component.rb index 932bd6d5c121..85aad8e8457b 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.rb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.rb @@ -34,6 +34,11 @@ def initialize(custom_field:) @custom_field = custom_field end + + def breadcrumbs_items + [{ href: project_overview_path(@project.id), text: @project.name }, + t("settings.project_attributes.heading")] + end end end end diff --git a/app/components/settings/project_custom_fields/header_component.html.erb b/app/components/settings/project_custom_fields/header_component.html.erb index 0b1d0169aa7c..fdf0ceee9143 100644 --- a/app/components/settings/project_custom_fields/header_component.html.erb +++ b/app/components/settings/project_custom_fields/header_component.html.erb @@ -4,30 +4,29 @@ render Primer::OpenProject::PageHeader.new do |header| header.with_title(variant: :default) { t('settings.project_attributes.heading') } header.with_description { t('settings.project_attributes.heading_description') } - header.with_actions do - flex_layout(justify_content: :space_between, align_items: :center) do |action_buttons_container| - action_buttons_container.with_column(mr: 2) do - render(Primer::Beta::Button.new( - tag: :a, - href: new_admin_settings_project_custom_field_path(type: "ProjectCustomField"), - scheme: :primary, - data: { turbo: "false", qa_selector: "new-project-custom-field-button" } - )) do |button| - button.with_leading_visual_icon(icon: :plus) - t('settings.project_attributes.label_new_attribute') - end + header.with_breadcrumbs(breadcrumbs_items) + flex_layout(justify_content: :space_between, align_items: :center) do |action_buttons_container| + action_buttons_container.with_column(mr: 2) do + header.with_action_button(tag: :a, + href: new_admin_settings_project_custom_field_path(type: "ProjectCustomField"), + scheme: :primary, + data: { turbo: "false", qa_selector: "new-project-custom-field-button" }, + mobile_icon: 'plus', + mobile_label: t('settings.project_attributes.label_new_attribute')) do |button| + button.with_leading_visual_icon(icon: :plus) + t('settings.project_attributes.label_new_attribute') end - action_buttons_container.with_column do - render(Primer::Alpha::Dialog.new( - id: "project-custom-field-section-dialog", title: t('settings.project_attributes.label_new_section'), - size: :medium_portrait - )) do |dialog| - dialog.with_show_button('aria-label': t('settings.project_attributes.label_new_section'), scheme: :default) do |button| - button.with_leading_visual_icon(icon: :plus) - t('settings.project_attributes.label_new_section') - end - render(Settings::ProjectCustomFieldSections::DialogBodyFormComponent.new()) + end + action_buttons_container.with_column do + render(Primer::Alpha::Dialog.new( + id: "project-custom-field-section-dialog", title: t('settings.project_attributes.label_new_section'), + size: :medium_portrait + )) do |dialog| + dialog.with_show_button('aria-label': t('settings.project_attributes.label_new_section'), scheme: :default) do |button| + button.with_leading_visual_icon(icon: :plus) + t('settings.project_attributes.label_new_section') end + render(Settings::ProjectCustomFieldSections::DialogBodyFormComponent.new()) end end end diff --git a/app/components/settings/project_custom_fields/header_component.rb b/app/components/settings/project_custom_fields/header_component.rb index 5970978e5329..cf0b3e54cce7 100644 --- a/app/components/settings/project_custom_fields/header_component.rb +++ b/app/components/settings/project_custom_fields/header_component.rb @@ -32,6 +32,10 @@ class HeaderComponent < ApplicationComponent include ApplicationHelper include OpPrimer::ComponentHelpers include OpTurbo::Streamable + def breadcrumbs_items + [{ href: admin_index_path, text: t("label_administration") }, + t("settings.project_attributes.heading")] + end end end end From 0c6ae6ff0e4342fafbad6b7739936368a92f4362 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 13:01:23 +0100 Subject: [PATCH 11/39] show correct breadcrumb in members and projects pages --- .../index_page_header_component.html.erb | 2 +- .../members/index_page_header_component.rb | 6 +- .../index_page_header_component.html.erb | 163 +++++++++--------- .../projects/index_page_header_component.rb | 5 +- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index 3d3c7ee665d9..361f836a100f 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -1,7 +1,7 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| header.with_title { t(:label_member_plural) } - header.with_breadcrumbs(breadcrumbs_items) + header.with_breadcrumbs(breadcrumb_items) header.with_action_button(scheme: :primary, mobile_icon: :plus, mobile_label: t('activerecord.models.member'), diff --git a/app/components/members/index_page_header_component.rb b/app/components/members/index_page_header_component.rb index 79f07835a19d..91fc6881983c 100644 --- a/app/components/members/index_page_header_component.rb +++ b/app/components/members/index_page_header_component.rb @@ -56,9 +56,7 @@ def filter_button_data_attributes } end - def breadcrumbs_items - [{ href: project_overview_path(@project.id), text: @project.name }, - { href: project_members_path(@project), text: t(:label_member_plural) }, - "test"] + def breadcrumb_items + [{ href: project_overview_path(@project.id), text: @project.name }, t(:label_member_plural)] end end diff --git a/app/components/projects/index_page_header_component.html.erb b/app/components/projects/index_page_header_component.html.erb index 43a7786cdbc6..31ee66a1c959 100644 --- a/app/components/projects/index_page_header_component.html.erb +++ b/app/components/projects/index_page_header_component.html.erb @@ -1,109 +1,108 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| %> <% if show_state? %> <% header.with_title(data: { 'test-selector': 'project-query-name'}) { page_title } %> - <% header.with_breadcrumbs([{href: projects_path, text: t('en.types.edit.projects')}, page_title])%> + <% header.with_breadcrumbs(breadcrumb_items)%> + <% if query_saveable? %> + <% header.with_action_text(tag: :span, + mr: BUTTON_MARGIN_RIGHT, + color: :muted) { t('lists.can_be_saved_as') } %> - <% if query_saveable? %> - <% header.with_action_text(tag: :span, - mr: BUTTON_MARGIN_RIGHT, - color: :muted) { t('lists.can_be_saved_as') } %> - - <% header.with_action_button(mobile_icon: "op-save", mobile_label: t('button_save_as'), - scheme: :invisible, - size: :medium, - mr: BUTTON_MARGIN_RIGHT, - tag: :a, - href: new_projects_query_path, - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - }, - classes: 'Button--invisibleOP') do |button|%> - <% button.with_leading_visual_icon(icon: "op-save") %> - t('button_save_as') - <% end %> - + <% header.with_action_button(mobile_icon: "op-save", mobile_label: t('button_save_as'), + scheme: :invisible, + size: :medium, + mr: BUTTON_MARGIN_RIGHT, + tag: :a, + href: new_projects_query_path, + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + }, + classes: 'Button--invisibleOP') do |button|%> + <% button.with_leading_visual_icon(icon: "op-save") %> + t('button_save_as') <% end %> - <%= header.with_action_menu(menu_arguments: { anchor_align: :end }, button_arguments: { icon: "op-kebab-vertical", "aria-label": t(:label_more), data: { 'test-selector': 'project-more-dropdown-menu' } }) do |menu, button| - if gantt_portfolio_project_ids.any? - menu.with_item( - tag: :a, - label: t('projects.index.open_as_gantt'), - href: gantt_portfolio_query_link, - id: 'projects-index-open-as-gantt', - content_arguments: { target: '_blank' } - ) do |item| - item.with_leading_visual_icon(icon: 'op-view-timeline') - end - end + <% end %> + <%= header.with_action_menu(menu_arguments: { anchor_align: :end }, button_arguments: { icon: "op-kebab-vertical", "aria-label": t(:label_more), data: { 'test-selector': 'project-more-dropdown-menu' } }) do |menu, button| + if gantt_portfolio_project_ids.any? menu.with_item( tag: :a, - label: t(:label_overall_activity), - href: activities_path + label: t('projects.index.open_as_gantt'), + href: gantt_portfolio_query_link, + id: 'projects-index-open-as-gantt', + content_arguments: { target: '_blank' } ) do |item| - item.with_leading_visual_icon(icon: 'tasklist') + item.with_leading_visual_icon(icon: 'op-view-timeline') end + end - if query_saveable? - menu.with_item( - label: t('button_save_as'), - href: new_projects_query_path, - content_arguments: { - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - } - } - ) do |item| - item.with_leading_visual_icon(icon: :'op-save') - end - end + menu.with_item( + tag: :a, + label: t(:label_overall_activity), + href: activities_path + ) do |item| + item.with_leading_visual_icon(icon: 'tasklist') + end + if query_saveable? menu.with_item( - label: t('js.label_export'), - content_arguments: { 'data-show-dialog-id': Projects::ExportListModalComponent::MODAL_ID } + label: t('button_save_as'), + href: new_projects_query_path, + content_arguments: { + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + } + } ) do |item| - item.with_leading_visual_icon(icon: 'sign-out') + item.with_leading_visual_icon(icon: :'op-save') end + end + menu.with_item( + label: t('js.label_export'), + content_arguments: { 'data-show-dialog-id': Projects::ExportListModalComponent::MODAL_ID } + ) do |item| + item.with_leading_visual_icon(icon: 'sign-out') + end + + menu.with_item( + label: t(:'queries.configure_view.heading'), + content_arguments: { 'data-show-dialog-id': Projects::ConfigureViewModalComponent::MODAL_ID } + ) do |item| + item.with_leading_visual_icon(icon: :gear) + end + + if query.persisted? menu.with_item( - label: t(:'queries.configure_view.heading'), - content_arguments: { 'data-show-dialog-id': Projects::ConfigureViewModalComponent::MODAL_ID } + label: t(:button_delete), + scheme: :danger, + content_arguments: { 'data-show-dialog-id': Projects::DeleteListModalComponent::MODAL_ID } ) do |item| - item.with_leading_visual_icon(icon: :gear) - end - - if query.persisted? - menu.with_item( - label: t(:button_delete), - scheme: :danger, - content_arguments: { 'data-show-dialog-id': Projects::DeleteListModalComponent::MODAL_ID } - ) do |item| - item.with_leading_visual_icon(icon: 'trash') - end + item.with_leading_visual_icon(icon: 'trash') end end - %> + end + %> <% else %> - <% header.with_title(mt: 2, mb: 2, data: { 'test-selector': 'project-query-name'}) do - primer_form_with(model: query, - url: projects_queries_path, - scope: 'query', - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - }, - id: 'project-save-form') do |f| - render(Queries::Projects::Create.new(f)) - end - end %> + <% header.with_title(mt: 2, mb: 2, data: { 'test-selector': 'project-query-name'}) do + primer_form_with(model: query, + url: projects_queries_path, + scope: 'query', + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + }, + id: 'project-save-form') do |f| + render(Queries::Projects::Create.new(f)) + end + end %> <% end %> <% end %> diff --git a/app/components/projects/index_page_header_component.rb b/app/components/projects/index_page_header_component.rb index 16af84647089..739d76ff5098 100644 --- a/app/components/projects/index_page_header_component.rb +++ b/app/components/projects/index_page_header_component.rb @@ -69,7 +69,6 @@ def gantt_portfolio_project_ids def page_title query.name || t(:label_project_plural) end - def query_saveable? current_user.logged? && query.name.blank? end @@ -77,4 +76,8 @@ def query_saveable? def show_state? state == :show end + + def breadcrumb_items + [{ href: projects_path, text: t("en.types.edit.projects") }, page_title] + end end From 82364e15471c86ceacc4023eee576789a3ce14a6 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 13:05:58 +0100 Subject: [PATCH 12/39] show correct breadcrumb in form header component of projects custom fields --- .../new_form_header_component.html.erb | 5 +---- .../project_custom_fields/new_form_header_component.rb | 5 +++++ .../admin/settings/project_custom_fields_controller.rb | 10 +--------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/app/components/settings/project_custom_fields/new_form_header_component.html.erb b/app/components/settings/project_custom_fields/new_form_header_component.html.erb index 1913a74db2a0..a6051351a869 100644 --- a/app/components/settings/project_custom_fields/new_form_header_component.html.erb +++ b/app/components/settings/project_custom_fields/new_form_header_component.html.erb @@ -31,9 +31,6 @@ See COPYRIGHT and LICENSE files for more details. render(Primer::OpenProject::PageHeader.new) do |header| header.with_title(variant: :medium) { t('settings.project_attributes.new.heading') } header.with_description { t('settings.project_attributes.new.description') } - header.with_parent_link(href: admin_settings_project_custom_fields_path, 'aria-label': I18n.t("button_back")) do - t('settings.project_attributes.heading') - end - header.with_back_button(href: admin_settings_project_custom_fields_path, 'aria-label': t('button_back')) + header.with_breadcrumbs(breadcrumb_items) end %> diff --git a/app/components/settings/project_custom_fields/new_form_header_component.rb b/app/components/settings/project_custom_fields/new_form_header_component.rb index 8c9f07076f8e..29bb2748b729 100644 --- a/app/components/settings/project_custom_fields/new_form_header_component.rb +++ b/app/components/settings/project_custom_fields/new_form_header_component.rb @@ -29,6 +29,11 @@ module Settings module ProjectCustomFields class NewFormHeaderComponent < ApplicationComponent + def breadcrumb_items + [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_project_custom_fields_path, text: t("settings.project_attributes.heading") }, + t("settings.project_attributes.new.heading")] + end end end end diff --git a/app/controllers/admin/settings/project_custom_fields_controller.rb b/app/controllers/admin/settings/project_custom_fields_controller.rb index f25cca6013da..4c58e07632a7 100644 --- a/app/controllers/admin/settings/project_custom_fields_controller.rb +++ b/app/controllers/admin/settings/project_custom_fields_controller.rb @@ -39,16 +39,8 @@ class ProjectCustomFieldsController < ::Admin::SettingsController before_action :prepare_custom_option_position, only: %i(update create) before_action :find_custom_option, only: :delete_option - def default_breadcrumb - if action_name == "index" - t("label_project_attribute_plural") - else - ActionController::Base.helpers.link_to(t("label_project_attribute_plural"), admin_settings_project_custom_fields_path) - end - end - def show_local_breadcrumb - true + false end def index From c662b50ec7d790d47514fc63994a94a56e133053 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 13:38:00 +0100 Subject: [PATCH 13/39] show correct breadcrumb in create a new storage page --- .../app/controllers/storages/admin/storages_controller.rb | 2 +- .../app/views/storages/admin/storages/new.html.erb | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/storages/app/controllers/storages/admin/storages_controller.rb b/modules/storages/app/controllers/storages/admin/storages_controller.rb index 7491bd2c6bd7..5c600ebd01eb 100644 --- a/modules/storages/app/controllers/storages/admin/storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/storages_controller.rb @@ -208,7 +208,7 @@ def default_breadcrumb # See: default_breadcrum above # Defines whether to show breadcrumbs on the page or not. def show_local_breadcrumb - true + false end private diff --git a/modules/storages/app/views/storages/admin/storages/new.html.erb b/modules/storages/app/views/storages/admin/storages/new.html.erb index 1cee2eedb9f7..6c592bb337f6 100644 --- a/modules/storages/app/views/storages/admin/storages/new.html.erb +++ b/modules/storages/app/views/storages/admin/storages/new.html.erb @@ -12,11 +12,9 @@ <%= label_new_file_storage %> <% end %> - <% header.with_back_button(href: admin_settings_storages_path, 'aria-label': I18n.t("button_back")) %> - - <% header.with_parent_link(href: admin_settings_storages_path, 'aria-label': I18n.t("button_back")) do %> - <%= t(:project_module_storages) %> - <% end %> + <% header.with_breadcrumbs([{ href: admin_index_path, text: t("label_administration")}, + { href: admin_settings_storages_path, text: t(:project_module_storages) }, + label_new_file_storage]) %> <% header.with_description(test_selector: 'storage-new-page-header--description') do %> <%= From fb3c6a780cb1b3c2b9209450965fff7ae51c48f6 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 19:46:48 +0100 Subject: [PATCH 14/39] (not complete we should discuss) there is no action type for rendering component or form as an action in page-header component --- .../storages/admin/storages/edit.html.erb | 37 +++++++------------ .../storages/admin/storages/index.html.erb | 6 ++- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/modules/storages/app/views/storages/admin/storages/edit.html.erb b/modules/storages/app/views/storages/admin/storages/edit.html.erb index c0035698bf10..32c51675ad41 100644 --- a/modules/storages/app/views/storages/admin/storages/edit.html.erb +++ b/modules/storages/app/views/storages/admin/storages/edit.html.erb @@ -44,33 +44,22 @@ See COPYRIGHT and LICENSE files for more details. <% end %> <% end %> - <% header.with_back_button(href: admin_settings_storages_path, 'aria-label': I18n.t("button_back")) %> - - <% header.with_parent_link(href: admin_settings_storages_path, 'aria-label': I18n.t("button_back")) do %> - <%= t(:project_module_storages) %> - <% end %> - - <% header.with_actions(test_selector: 'page-header-actions') do %> - <%= - primer_form_with( + <% header.with_breadcrumbs([{href: admin_index_path, text: t("label_administration")}, + {href: admin_settings_storages_path, text: t("project_module_storages")}, + @storage.name]) %> + <%= primer_form_with( model: @storage, url: confirm_destroy_admin_settings_storage_path(@storage), method: :get - ) do |_form| - render( - Primer::Beta::Button.new( - scheme: :danger, - size: :medium, - type: :submit, - aria: { label: I18n.t("storages.label_delete_storage") }, - test_selector: 'storage-delete-button' - ) - ) do |button| - button.with_leading_visual_icon(icon: :trash) - I18n.t('button_delete') - end - end - %> + ) do %> + <% header.with_action_button(mt: 2, mb: 2, data: { 'test-selector': "project-query-name"}, scheme: :danger,mobile_icon: "trash", mobile_label: I18n.t('button_delete'), + size: :medium, + type: :submit, + aria: { label: I18n.t("storages.label_delete_storage") }, + test_selector: "storage-delete-button") do |button| + button.with_leading_visual_icon(icon: :trash) + I18n.t("button_delete") + end %> <% end %> <% end %> diff --git a/modules/storages/app/views/storages/admin/storages/index.html.erb b/modules/storages/app/views/storages/admin/storages/index.html.erb index c435a0ba87ea..4601b5a0d68d 100644 --- a/modules/storages/app/views/storages/admin/storages/index.html.erb +++ b/modules/storages/app/views/storages/admin/storages/index.html.erb @@ -10,7 +10,11 @@ <%= t("storages.page_titles.file_storages.subtitle") %> <% end %> - <% header.with_actions do %> + <% header.with_breadcrumbs(breadcrumb_paths( + link_to(t(:label_administration), admin_index_path), + default_breadcrumb + )) %> + <% header.with_action_button(mobile_icon: "star", mobile_label: "Star") do %> <%= render(Storages::Admin::NewStorageButtonComponent.new) %> <% end %> <% end %> From 051a53f98e2a32a468a7b5c70926016c162c7c47 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 20:22:05 +0100 Subject: [PATCH 15/39] project attribute edit header update with new breadcrumb --- .../project_custom_fields/edit_form_header_component.html.erb | 4 ++-- .../project_custom_fields/edit_form_header_component.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.html.erb b/app/components/settings/project_custom_fields/edit_form_header_component.html.erb index 0510a87b407e..17cda2a8a7c2 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.html.erb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.html.erb @@ -27,9 +27,9 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <%= - render(Primer::Ï.new) do |header| + render(Primer::OpenProject::PageHeader.new) do |header| header.with_title(variant: :medium) { @custom_field.name } - header.with_description { t('settings.project_attributes.edit.description') } + header.with_description { t("settings.project_attributes.edit.description") } header.with_breadcrumbs(breadcrumbs_items) end %> diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.rb b/app/components/settings/project_custom_fields/edit_form_header_component.rb index 85aad8e8457b..62a47fc69377 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.rb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.rb @@ -36,7 +36,7 @@ def initialize(custom_field:) end def breadcrumbs_items - [{ href: project_overview_path(@project.id), text: @project.name }, + [{ href: admin_settings_project_custom_fields_path, text: t("label_administration") }, t("settings.project_attributes.heading")] end end From eecae54939e1f92b9b035446bdc0bbad2ee1ed4c Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Thu, 28 Mar 2024 20:43:58 +0100 Subject: [PATCH 16/39] change order of buttons in members page header --- .../index_page_header_component.html.erb | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index 361f836a100f..4735a527a34d 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -2,6 +2,16 @@ render(Primer::OpenProject::PageHeader.new) do |header| header.with_title { t(:label_member_plural) } header.with_breadcrumbs(breadcrumb_items) + + header.with_action_icon_button(mobile_icon: "filter", + scheme: :default, + icon: 'filter', + label: I18n.t(:description_filter), + id: 'filter-member-button', + aria: { label: I18n.t(:description_filter) }, + class: 'toggle-member-filter-link', + data: filter_button_data_attributes) + header.with_action_button(scheme: :primary, mobile_icon: :plus, mobile_label: t('activerecord.models.member'), @@ -13,13 +23,5 @@ button.with_leading_visual_icon(icon: :plus) t('activerecord.models.member') end - header.with_action_icon_button(mobile_icon: "filter", - scheme: :default, - icon: 'filter', - label: I18n.t(:description_filter), - id: 'filter-member-button', - aria: { label: I18n.t(:description_filter) }, - class: 'toggle-member-filter-link', - data: filter_button_data_attributes) - end + end %> From 522ab3f01bfd9482d35c428525de12e6a3912813 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 08:23:18 +0200 Subject: [PATCH 17/39] commit gemfile.lock and package-lock.json --- Gemfile.lock | 4 ++-- frontend/package-lock.json | 48 +++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2c893312d7d5..903488a44cb9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -774,7 +774,7 @@ GEM actionview openproject-octicons (= 19.8.0) railties - openproject-primer_view_components (0.23.0) + openproject-primer_view_components (0.25.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) openproject-octicons (>= 19.8.0) @@ -1266,7 +1266,7 @@ DEPENDENCIES openproject-octicons (~> 19.8.0) openproject-octicons_helper (~> 19.8.0) openproject-openid_connect! - openproject-primer_view_components (~> 0.23.0) + openproject-primer_view_components (~> 0.25.0) openproject-recaptcha! openproject-reporting! openproject-storages! diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 01e991f3e60a..64366855d5ae 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,7 +47,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.23.0", + "@openproject/primer-view-components": "^0.25.0", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -3681,9 +3681,9 @@ } }, "node_modules/@github/auto-complete-element": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@github/auto-complete-element/-/auto-complete-element-3.6.0.tgz", - "integrity": "sha512-u8fG8nCosSFv2wlKMsGga+FaFu/jkexZVFIDxLiCyLVTB8zRRu/RJyufzNnmbOZHYBezCMNBgJ0quuEBoyRh9Q==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@github/auto-complete-element/-/auto-complete-element-3.6.2.tgz", + "integrity": "sha512-AgkrawNa2Focapn05yc/mNVTlAOqPFlMPhqkkMygPtOddms6NYxlCuVx8OM6aCTzBeEJlYur+/CS56hk4mvwmA==", "dependencies": { "@github/combobox-nav": "^2.1.7" } @@ -4519,12 +4519,12 @@ } }, "node_modules/@openproject/primer-view-components": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.23.0.tgz", - "integrity": "sha512-fdsP4UzOVqSEDWREk4F7W+N3VQjhUJIR3m8kebalnhVuC4yP4izeXDertjCjem0k5KP3Wq6F+TmQMSo1Fnbtcg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", + "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", "dependencies": { "@github/auto-check-element": "^5.2.0", - "@github/auto-complete-element": "^3.6.0", + "@github/auto-complete-element": "^3.6.2", "@github/catalyst": "^1.6.0", "@github/clipboard-copy-element": "^1.3.0", "@github/details-menu-element": "^1.0.12", @@ -4604,12 +4604,12 @@ }, "node_modules/@primer/view-components": { "name": "@openproject/primer-view-components", - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.23.0.tgz", - "integrity": "sha512-fdsP4UzOVqSEDWREk4F7W+N3VQjhUJIR3m8kebalnhVuC4yP4izeXDertjCjem0k5KP3Wq6F+TmQMSo1Fnbtcg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", + "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", "dependencies": { "@github/auto-check-element": "^5.2.0", - "@github/auto-complete-element": "^3.6.0", + "@github/auto-complete-element": "^3.6.2", "@github/catalyst": "^1.6.0", "@github/clipboard-copy-element": "^1.3.0", "@github/details-menu-element": "^1.0.12", @@ -23272,9 +23272,9 @@ } }, "@github/auto-complete-element": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@github/auto-complete-element/-/auto-complete-element-3.6.0.tgz", - "integrity": "sha512-u8fG8nCosSFv2wlKMsGga+FaFu/jkexZVFIDxLiCyLVTB8zRRu/RJyufzNnmbOZHYBezCMNBgJ0quuEBoyRh9Q==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@github/auto-complete-element/-/auto-complete-element-3.6.2.tgz", + "integrity": "sha512-AgkrawNa2Focapn05yc/mNVTlAOqPFlMPhqkkMygPtOddms6NYxlCuVx8OM6aCTzBeEJlYur+/CS56hk4mvwmA==", "requires": { "@github/combobox-nav": "^2.1.7" } @@ -23846,12 +23846,12 @@ } }, "@openproject/primer-view-components": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.23.0.tgz", - "integrity": "sha512-fdsP4UzOVqSEDWREk4F7W+N3VQjhUJIR3m8kebalnhVuC4yP4izeXDertjCjem0k5KP3Wq6F+TmQMSo1Fnbtcg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", + "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", "requires": { "@github/auto-check-element": "^5.2.0", - "@github/auto-complete-element": "^3.6.0", + "@github/auto-complete-element": "^3.6.2", "@github/catalyst": "^1.6.0", "@github/clipboard-copy-element": "^1.3.0", "@github/details-menu-element": "^1.0.12", @@ -23904,7 +23904,7 @@ "integrity": "sha512-Mcpt9CyajnPW8TJmZYIUhnctdLk7rfsoyvh8w4qDydu2C7HHOHa0wKQjf0zofQ+AyJOIW1Gfa9xvBfwAeNkgoQ==", "requires": { "@primer/primitives": "^7.15.12", - "@primer/view-components": "npm:@openproject/primer-view-components@^0.23.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.25.0" } }, "@primer/primitives": { @@ -23913,12 +23913,12 @@ "integrity": "sha512-ujAsbRB5Xw6rrxizbTgv1bxpraZ091stPMsO6pqGxzc+zIyhrojpGVBuCKJ+RYkpbKK7T4bZzgOT/KyWBAFwwg==" }, "@primer/view-components": { - "version": "npm:@openproject/primer-view-components@0.23.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.23.0.tgz", - "integrity": "sha512-fdsP4UzOVqSEDWREk4F7W+N3VQjhUJIR3m8kebalnhVuC4yP4izeXDertjCjem0k5KP3Wq6F+TmQMSo1Fnbtcg==", + "version": "npm:@openproject/primer-view-components@0.25.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", + "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", "requires": { "@github/auto-check-element": "^5.2.0", - "@github/auto-complete-element": "^3.6.0", + "@github/auto-complete-element": "^3.6.2", "@github/catalyst": "^1.6.0", "@github/clipboard-copy-element": "^1.3.0", "@github/details-menu-element": "^1.0.12", From d622636a934ac2269531bcc03ecf95d41333f424 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 08:41:51 +0200 Subject: [PATCH 18/39] use double quotation marks for string --- app/components/members/index_page_header_component.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index 4735a527a34d..e288c580c9c9 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -5,7 +5,7 @@ header.with_action_icon_button(mobile_icon: "filter", scheme: :default, - icon: 'filter', + icon: "filter", label: I18n.t(:description_filter), id: 'filter-member-button', aria: { label: I18n.t(:description_filter) }, From 0ca05da0e216df30d9f067a319aea442be52f514 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 08:44:52 +0200 Subject: [PATCH 19/39] remove unnecessary system arguments --- app/components/projects/index_page_header_component.html.erb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/components/projects/index_page_header_component.html.erb b/app/components/projects/index_page_header_component.html.erb index 31ee66a1c959..3864dd6e94ee 100644 --- a/app/components/projects/index_page_header_component.html.erb +++ b/app/components/projects/index_page_header_component.html.erb @@ -4,9 +4,7 @@ <% header.with_breadcrumbs(breadcrumb_items)%> <% if query_saveable? %> - <% header.with_action_text(tag: :span, - mr: BUTTON_MARGIN_RIGHT, - color: :muted) { t('lists.can_be_saved_as') } %> + <% header.with_action_text { t('lists.can_be_saved_as') } %> <% header.with_action_button(mobile_icon: "op-save", mobile_label: t('button_save_as'), scheme: :invisible, From 1f6185fd0570a5b79aed41919d47b44e599ab7f3 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Wed, 3 Apr 2024 10:47:51 +0200 Subject: [PATCH 20/39] Wrap form around the PageHeader in order for the submit button to work again --- .../new_form_header_component.html.erb | 2 +- .../storages/admin/storages/edit.html.erb | 46 ++++++++++--------- .../storages/admin/storages/new.html.erb | 1 - 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/app/components/settings/project_custom_fields/new_form_header_component.html.erb b/app/components/settings/project_custom_fields/new_form_header_component.html.erb index a6051351a869..ab077ccbee28 100644 --- a/app/components/settings/project_custom_fields/new_form_header_component.html.erb +++ b/app/components/settings/project_custom_fields/new_form_header_component.html.erb @@ -29,7 +29,7 @@ See COPYRIGHT and LICENSE files for more details. <%= render(Primer::OpenProject::PageHeader.new) do |header| - header.with_title(variant: :medium) { t('settings.project_attributes.new.heading') } + header.with_title { t('settings.project_attributes.new.heading') } header.with_description { t('settings.project_attributes.new.description') } header.with_breadcrumbs(breadcrumb_items) end diff --git a/modules/storages/app/views/storages/admin/storages/edit.html.erb b/modules/storages/app/views/storages/admin/storages/edit.html.erb index 32c51675ad41..c394af2e30b0 100644 --- a/modules/storages/app/views/storages/admin/storages/edit.html.erb +++ b/modules/storages/app/views/storages/admin/storages/edit.html.erb @@ -35,31 +35,33 @@ See COPYRIGHT and LICENSE files for more details. %> <% html_title t(:label_administration), t("project_module_storages"), t('label_edit_x', x: @storage.name) %> -<% local_assigns[:additional_breadcrumb] = @storage.name %> -<%= render(Primer::OpenProject::PageHeader.new) do |header| %> - <% header.with_title(test_selector: 'storage-new-page-header--title') do %> - <%= render OpTurbo::FrameComponent.new(@storage, context: :edit_storage_header) do %> - <%= label_storage_name_with_provider_label %> +<%= primer_form_with( + model: @storage, + url: confirm_destroy_admin_settings_storage_path(@storage), + method: :get + ) do %> + <%= render(Primer::OpenProject::PageHeader.new) do |header| %> + <% header.with_title(test_selector: 'storage-new-page-header--title') do %> + <%= render OpTurbo::FrameComponent.new(@storage, context: :edit_storage_header) do %> + <%= label_storage_name_with_provider_label %> + <% end %> <% end %> - <% end %> - <% header.with_breadcrumbs([{href: admin_index_path, text: t("label_administration")}, - {href: admin_settings_storages_path, text: t("project_module_storages")}, - @storage.name]) %> - <%= primer_form_with( - model: @storage, - url: confirm_destroy_admin_settings_storage_path(@storage), - method: :get - ) do %> - <% header.with_action_button(mt: 2, mb: 2, data: { 'test-selector': "project-query-name"}, scheme: :danger,mobile_icon: "trash", mobile_label: I18n.t('button_delete'), - size: :medium, - type: :submit, - aria: { label: I18n.t("storages.label_delete_storage") }, - test_selector: "storage-delete-button") do |button| - button.with_leading_visual_icon(icon: :trash) - I18n.t("button_delete") - end %> + <% header.with_breadcrumbs([{href: admin_index_path, text: t("label_administration")}, + {href: admin_settings_storages_path, text: t("project_module_storages")}, + @storage.name]) %> + + <% header.with_action_button(scheme: :danger, + mobile_icon: :trash, + mobile_label: I18n.t("button_delete"), + type: :submit, + data: { "test-selector": "project-query-name"}, + aria: { label: I18n.t("storages.label_delete_storage") }, + test_selector: "storage-delete-button") do |button| + button.with_leading_visual_icon(icon: :trash) + I18n.t("button_delete") + end %> <% end %> <% end %> diff --git a/modules/storages/app/views/storages/admin/storages/new.html.erb b/modules/storages/app/views/storages/admin/storages/new.html.erb index 6c592bb337f6..53997a99e87e 100644 --- a/modules/storages/app/views/storages/admin/storages/new.html.erb +++ b/modules/storages/app/views/storages/admin/storages/new.html.erb @@ -5,7 +5,6 @@ %> <% html_title t(:label_administration), t("project_module_storages"), label_new_file_storage %> -<% local_assigns[:additional_breadcrumb] = label_new_file_storage %> <%= render(Primer::OpenProject::PageHeader.new) do |header| %> <% header.with_title(test_selector: 'storage-new-page-header--title') do %> From 978006bc4df76353f9d1daf58f0329efde1646ed Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Wed, 3 Apr 2024 11:36:25 +0200 Subject: [PATCH 21/39] Replace invisble button with a link as it matches the requirements better --- .../index_page_header_component.html.erb | 37 +++++++++++-------- .../openproject/_primer-adjustments.sass | 20 +--------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/app/components/projects/index_page_header_component.html.erb b/app/components/projects/index_page_header_component.html.erb index 3864dd6e94ee..2e905fe89bd5 100644 --- a/app/components/projects/index_page_header_component.html.erb +++ b/app/components/projects/index_page_header_component.html.erb @@ -6,25 +6,30 @@ <% if query_saveable? %> <% header.with_action_text { t('lists.can_be_saved_as') } %> - <% header.with_action_button(mobile_icon: "op-save", mobile_label: t('button_save_as'), - scheme: :invisible, - size: :medium, - mr: BUTTON_MARGIN_RIGHT, - tag: :a, - href: new_projects_query_path, - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - }, - classes: 'Button--invisibleOP') do |button|%> - <% button.with_leading_visual_icon(icon: "op-save") %> - t('button_save_as') + <% header.with_action_link(mobile_icon: nil, # Do not show on mobile as it is already part of the menu + mobile_label: nil, + href: new_projects_query_path, + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + }) do %> + <% render(Primer::Beta::Octicon.new(icon: "op-save", + align_self: :center, + "aria-label": I18n.t("button_save_as"), + mr: 1) + ) + content_tag(:span, t("button_save_as")) %> <% end %> - <% end %> - <%= header.with_action_menu(menu_arguments: { anchor_align: :end }, button_arguments: { icon: "op-kebab-vertical", "aria-label": t(:label_more), data: { 'test-selector': 'project-more-dropdown-menu' } }) do |menu, button| + <%= header.with_action_menu(menu_arguments: { + anchor_align: :end + }, + button_arguments: { + icon: "op-kebab-vertical", + "aria-label": t(:label_more), + data: { "test-selector": "project-more-dropdown-menu" } + }) do |menu, button| if gantt_portfolio_project_ids.any? menu.with_item( tag: :a, diff --git a/frontend/src/global_styles/openproject/_primer-adjustments.sass b/frontend/src/global_styles/openproject/_primer-adjustments.sass index aa4fee7f6263..51a5ae4295c1 100644 --- a/frontend/src/global_styles/openproject/_primer-adjustments.sass +++ b/frontend/src/global_styles/openproject/_primer-adjustments.sass @@ -49,7 +49,8 @@ ul.tabnav-tabs margin-left: 0 /* Remove margin-left: 2rem from Breadcrumbs */ -#breadcrumb,page-header +#breadcrumb, +page-header ol margin-left: 0 .breadcrumb-item.breadcrumb-item-selected @@ -63,20 +64,3 @@ ul.tabnav-tabs .Overlay &-body_autocomplete_height min-height: 300px - -/* TODO: The actions within the PageHeader are currently not aligned correctly. - The pageHeader itself already uses center alignment but the actions themselves default to 'normal'. - Will be added to our primer repository */ -.PageHeader-actions - align-items: center - -/* Primer uses the fgColor (blue) for Buttons having the :invisible schema unless they receive an trailing/leading icon. - Then, the color changes to gray. This seems inconsistent. An issue has been opened with Primer to discuss this behavior. - Until then, we will override the fgColor for the invisible schema. - No all invisible schema buttons are overwritten though and need to apply this modifier themselves. */ -.Button--invisibleOP, -.Button--invisibleOP:hover:not(:disabled,.Button--inactive) - color: var(--button-invisible-fgColor-rest,var(--color-btn-outline-text)) - - .Button-visual - color: var(--button-invisible-fgColor-rest,var(--color-btn-outline-text)) From 991be148a17535f5cbf2a893d59ef086714910c9 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 11:49:32 +0200 Subject: [PATCH 22/39] fix string definition in projects list --- app/components/projects/index_page_header_component.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/components/projects/index_page_header_component.rb b/app/components/projects/index_page_header_component.rb index 739d76ff5098..a6e327dd348b 100644 --- a/app/components/projects/index_page_header_component.rb +++ b/app/components/projects/index_page_header_component.rb @@ -37,8 +37,6 @@ class Projects::IndexPageHeaderComponent < ApplicationComponent :state, :params - BUTTON_MARGIN_RIGHT = 2 - STATE_DEFAULT = :show STATE_EDIT = :edit STATE_OPTIONS = [STATE_DEFAULT, STATE_EDIT].freeze @@ -69,6 +67,7 @@ def gantt_portfolio_project_ids def page_title query.name || t(:label_project_plural) end + def query_saveable? current_user.logged? && query.name.blank? end @@ -78,6 +77,6 @@ def show_state? end def breadcrumb_items - [{ href: projects_path, text: t("en.types.edit.projects") }, page_title] + [{ href: projects_path, text: t(:label_project_plural) }, page_title] end end From aab2443c720c60e7284ed868505a32d56d4a29b7 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 12:19:26 +0200 Subject: [PATCH 23/39] update primer view component version to 0.26.0 --- Gemfile | 6 +++--- Gemfile.lock | 16 ++++++++-------- frontend/package-lock.json | 28 ++++++++++++++-------------- frontend/package.json | 4 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Gemfile b/Gemfile index 25643486cbc6..ac42052f3d73 100644 --- a/Gemfile +++ b/Gemfile @@ -381,6 +381,6 @@ gemfiles.each do |file| send(:eval_gemfile, file) if File.readable?(file) end -gem "openproject-octicons", "~>19.8.0" -gem "openproject-octicons_helper", "~>19.8.0" -gem "openproject-primer_view_components", "~>0.25.0" +gem "openproject-octicons", "~>19.9.0" +gem "openproject-octicons_helper", "~>19.9.0" +gem "openproject-primer_view_components", "~>0.26.0" diff --git a/Gemfile.lock b/Gemfile.lock index 903488a44cb9..b73af27922ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -769,15 +769,15 @@ GEM validate_email validate_url webfinger (~> 2.0) - openproject-octicons (19.8.0) - openproject-octicons_helper (19.8.0) + openproject-octicons (19.9.0) + openproject-octicons_helper (19.9.0) actionview - openproject-octicons (= 19.8.0) + openproject-octicons (= 19.9.0) railties - openproject-primer_view_components (0.25.0) + openproject-primer_view_components (0.26.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) - openproject-octicons (>= 19.8.0) + openproject-octicons (>= 19.9.0) view_component (>= 3.1, < 4.0) openproject-token (4.0.0) activemodel @@ -1263,10 +1263,10 @@ DEPENDENCIES openproject-job_status! openproject-ldap_groups! openproject-meeting! - openproject-octicons (~> 19.8.0) - openproject-octicons_helper (~> 19.8.0) + openproject-octicons (~> 19.9.0) + openproject-octicons_helper (~> 19.9.0) openproject-openid_connect! - openproject-primer_view_components (~> 0.25.0) + openproject-primer_view_components (~> 0.26.0) openproject-recaptcha! openproject-reporting! openproject-storages! diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 64366855d5ae..c2e028d6f6aa 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,7 +47,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.25.0", + "@openproject/primer-view-components": "^0.26.0", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -4519,9 +4519,9 @@ } }, "node_modules/@openproject/primer-view-components": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", - "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", + "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", "dependencies": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -4604,9 +4604,9 @@ }, "node_modules/@primer/view-components": { "name": "@openproject/primer-view-components", - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", - "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", + "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", "dependencies": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -23846,9 +23846,9 @@ } }, "@openproject/primer-view-components": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", - "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", + "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", "requires": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -23904,7 +23904,7 @@ "integrity": "sha512-Mcpt9CyajnPW8TJmZYIUhnctdLk7rfsoyvh8w4qDydu2C7HHOHa0wKQjf0zofQ+AyJOIW1Gfa9xvBfwAeNkgoQ==", "requires": { "@primer/primitives": "^7.15.12", - "@primer/view-components": "npm:@openproject/primer-view-components@^0.25.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.26.0" } }, "@primer/primitives": { @@ -23913,9 +23913,9 @@ "integrity": "sha512-ujAsbRB5Xw6rrxizbTgv1bxpraZ091stPMsO6pqGxzc+zIyhrojpGVBuCKJ+RYkpbKK7T4bZzgOT/KyWBAFwwg==" }, "@primer/view-components": { - "version": "npm:@openproject/primer-view-components@0.25.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.25.0.tgz", - "integrity": "sha512-bTdb5LOpV9I6KgAARINwBlHdpaDV3vHbGmaFUnGV3HPRWQIYUH9DfK71OQQC4Dpx3YdB3dUdq2OG5awoyOzGww==", + "version": "npm:@openproject/primer-view-components@0.26.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", + "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", "requires": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", diff --git a/frontend/package.json b/frontend/package.json index cd8a13ded2e5..8453f292b0fd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -98,7 +98,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.25.0", + "@openproject/primer-view-components": "^0.26.0", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -176,6 +176,6 @@ "generate-typings": "tsc -d -p src/tsconfig.app.json" }, "overrides": { - "@primer/view-components": "npm:@openproject/primer-view-components@^0.25.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.26.0" } } From 49a06fa5ecf5a30310f640c7456849ad89fa9d18 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Wed, 3 Apr 2024 13:21:27 +0200 Subject: [PATCH 24/39] Extract menu logic of projects page into a helper to be able to access it for the PageHeader breadcrumb information --- .../projects/index_page_header_component.rb | 20 +++- app/controllers/projects/menus_controller.rb | 65 +------------ app/helpers/menus/projects_helper.rb | 94 +++++++++++++++++++ config/locales/en.yml | 2 + 4 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 app/helpers/menus/projects_helper.rb diff --git a/app/components/projects/index_page_header_component.rb b/app/components/projects/index_page_header_component.rb index a6e327dd348b..59f0ec5e3928 100644 --- a/app/components/projects/index_page_header_component.rb +++ b/app/components/projects/index_page_header_component.rb @@ -31,6 +31,7 @@ class Projects::IndexPageHeaderComponent < ApplicationComponent include OpPrimer::ComponentHelpers include Primer::FetchOrFallbackHelper + include Menus::ProjectsHelper attr_accessor :current_user, :query, @@ -77,6 +78,23 @@ def show_state? end def breadcrumb_items - [{ href: projects_path, text: t(:label_project_plural) }, page_title] + [ + { href: projects_path, text: t(:label_project_plural) }, + current_breadcrumb_element + ] + end + + def current_breadcrumb_element + return page_title if query.name.blank? + + current_object = first_level_menu_items.find do |section| + section.children.find { |menu_query| menu_query.title == query.name }.present? + end + + if current_object && current_object.header.present? + I18n.t("menus.breadcrumb.nested_element", section_header: current_object.header, title: query.name).html_safe + else + page_title + end end end diff --git a/app/controllers/projects/menus_controller.rb b/app/controllers/projects/menus_controller.rb index 78281abee108..fe5559240f37 100644 --- a/app/controllers/projects/menus_controller.rb +++ b/app/controllers/projects/menus_controller.rb @@ -27,6 +27,8 @@ # ++ module Projects class MenusController < ApplicationController + include Menus::ProjectsHelper + # No authorize as every user (or logged in user) # is allowed to see the menu. @@ -34,68 +36,5 @@ def show @sidebar_menu_items = first_level_menu_items render layout: nil end - - private - - def first_level_menu_items - [ - OpenProject::Menu::MenuGroup.new(header: nil, - children: static_filters), - OpenProject::Menu::MenuGroup.new(header: I18n.t(:"projects.lists.my_private"), - children: my_filters), - OpenProject::Menu::MenuGroup.new(header: I18n.t(:"activerecord.attributes.project.status_code"), - children: static_status_filters) - ] - end - - def static_filters - [ - query_menu_item(::Queries::Projects::Factory.static_query_active, selected: no_query_props?), - query_menu_item(::Queries::Projects::Factory.static_query_my, - id: ::Queries::Projects::Factory::STATIC_MY), - query_menu_item(::Queries::Projects::Factory.static_query_archived, - id: ::Queries::Projects::Factory::STATIC_ARCHIVED) - ] - end - - def static_status_filters - [ - query_menu_item(::Queries::Projects::Factory.static_query_status_on_track, - id: ::Queries::Projects::Factory::STATIC_ON_TRACK), - query_menu_item(::Queries::Projects::Factory.static_query_status_off_track, - id: ::Queries::Projects::Factory::STATIC_OFF_TRACK), - query_menu_item(::Queries::Projects::Factory.static_query_status_at_risk, - id: ::Queries::Projects::Factory::STATIC_AT_RISK) - ] - end - - def my_filters - ::Queries::Projects::ProjectQuery - .where(user: current_user) - .order(:name) - .map do |query| - query_menu_item(query) - end - end - - def query_menu_item(query, id: nil, selected: query_item_selected?(id || query.id)) - OpenProject::Menu::MenuItem.new(title: query.name, - href: projects_path(query_id: id || query.id), - selected:) - end - - def projects_path_with_filters(filters) - return projects_path if filters.empty? - - projects_path(filters: filters.to_json, hide_filters_section: true) - end - - def query_item_selected?(id) - id.to_s == params[:query_id] && params[:filters].nil? - end - - def no_query_props? - params[:query_id].nil? && params[:filters].nil? && params[:sortBy].nil? - end end end diff --git a/app/helpers/menus/projects_helper.rb b/app/helpers/menus/projects_helper.rb new file mode 100644 index 000000000000..3baee90fb0ba --- /dev/null +++ b/app/helpers/menus/projects_helper.rb @@ -0,0 +1,94 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 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 Menus + module ProjectsHelper + def first_level_menu_items + [ + OpenProject::Menu::MenuGroup.new(header: nil, + children: static_filters), + OpenProject::Menu::MenuGroup.new(header: I18n.t(:"projects.lists.my_private"), + children: my_filters), + OpenProject::Menu::MenuGroup.new(header: I18n.t(:"activerecord.attributes.project.status_code"), + children: static_status_filters) + ] + end + + private + + def static_filters + [ + query_menu_item(::Queries::Projects::Factory.static_query_active, selected: no_query_props?), + query_menu_item(::Queries::Projects::Factory.static_query_my, + id: ::Queries::Projects::Factory::STATIC_MY), + query_menu_item(::Queries::Projects::Factory.static_query_archived, + id: ::Queries::Projects::Factory::STATIC_ARCHIVED) + ] + end + + def static_status_filters + [ + query_menu_item(::Queries::Projects::Factory.static_query_status_on_track, + id: ::Queries::Projects::Factory::STATIC_ON_TRACK), + query_menu_item(::Queries::Projects::Factory.static_query_status_off_track, + id: ::Queries::Projects::Factory::STATIC_OFF_TRACK), + query_menu_item(::Queries::Projects::Factory.static_query_status_at_risk, + id: ::Queries::Projects::Factory::STATIC_AT_RISK) + ] + end + + def my_filters + ::Queries::Projects::ProjectQuery + .where(user: current_user) + .order(:name) + .map do |query| + query_menu_item(query) + end + end + + def query_menu_item(query, id: nil, selected: query_item_selected?(id || query.id)) + OpenProject::Menu::MenuItem.new(title: query.name, + href: projects_path(query_id: id || query.id), + selected:) + end + + def projects_path_with_filters(filters) + return projects_path if filters.empty? + + projects_path(filters: filters.to_json, hide_filters_section: true) + end + + def query_item_selected?(id) + id.to_s == params[:query_id] && params[:filters].nil? + end + + def no_query_props? + params[:query_id].nil? && params[:filters].nil? && params[:sortBy].nil? + end + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 94721a3df2f0..285542af49fb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1699,6 +1699,8 @@ Project attributes and sections are defined in the %{title}" my_account: access_tokens: From b70ddc526f4dd37f553fcac2e2dc6229a573cbfa Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 13:27:08 +0200 Subject: [PATCH 25/39] update breadcrumb in edit form of project attribute --- .../project_custom_fields/edit_form_header_component.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.rb b/app/components/settings/project_custom_fields/edit_form_header_component.rb index 62a47fc69377..41f0a1b562d1 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.rb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.rb @@ -36,8 +36,12 @@ def initialize(custom_field:) end def breadcrumbs_items - [{ href: admin_settings_project_custom_fields_path, text: t("label_administration") }, - t("settings.project_attributes.heading")] + [ + { href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_project_custom_fields_path, text: t("label_project_plural") }, + { href: admin_settings_project_custom_fields_path, text: t("settings.project_attributes.heading") }, + @custom_field.name + ] end end end From 338000b1dba3c87b68b30c88f20a8e59004e4151 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 13:47:00 +0200 Subject: [PATCH 26/39] update breadcrumb in edit form of project attribute --- .../project_custom_fields/edit_form_header_component.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.rb b/app/components/settings/project_custom_fields/edit_form_header_component.rb index 41f0a1b562d1..c606dd4c5e82 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.rb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.rb @@ -36,8 +36,7 @@ def initialize(custom_field:) end def breadcrumbs_items - [ - { href: admin_index_path, text: t("label_administration") }, + [{ href: admin_index_path, text: t("label_administration") }, { href: admin_settings_project_custom_fields_path, text: t("label_project_plural") }, { href: admin_settings_project_custom_fields_path, text: t("settings.project_attributes.heading") }, @custom_field.name From a7ebc43bfe6ea2cf6ecadbd93ea55293426351a0 Mon Sep 17 00:00:00 2001 From: Behrokh Satarnejad Date: Wed, 3 Apr 2024 15:23:20 +0200 Subject: [PATCH 27/39] remove show default breadcrumb method in some components --- .../admin/attachments/quarantined_attachments_controller.rb | 4 ---- .../attachments/quarantined_attachments/index.html.erb | 2 +- .../app/controllers/storages/admin/storages_controller.rb | 6 ------ 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/app/controllers/admin/attachments/quarantined_attachments_controller.rb b/app/controllers/admin/attachments/quarantined_attachments_controller.rb index 6df31b1b4e8d..233bc5e3e64a 100644 --- a/app/controllers/admin/attachments/quarantined_attachments_controller.rb +++ b/app/controllers/admin/attachments/quarantined_attachments_controller.rb @@ -51,10 +51,6 @@ def destroy redirect_to action: :index end - def show_local_breadcrumb - false - end - private def create_journal(container, user, notes) diff --git a/app/views/admin/attachments/quarantined_attachments/index.html.erb b/app/views/admin/attachments/quarantined_attachments/index.html.erb index 1a8524e0dcc4..fa7223bec0e1 100644 --- a/app/views/admin/attachments/quarantined_attachments/index.html.erb +++ b/app/views/admin/attachments/quarantined_attachments/index.html.erb @@ -2,7 +2,7 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| - header.with_title(variant: :large) { t('antivirus_scan.quarantined_attachments.title') } + header.with_title(variant: :default) { t('antivirus_scan.quarantined_attachments.title') } header.with_breadcrumbs(breadcrumb_items) end %> diff --git a/modules/storages/app/controllers/storages/admin/storages_controller.rb b/modules/storages/app/controllers/storages/admin/storages_controller.rb index 5c600ebd01eb..31043280f700 100644 --- a/modules/storages/app/controllers/storages/admin/storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/storages_controller.rb @@ -205,12 +205,6 @@ def default_breadcrumb end end - # See: default_breadcrum above - # Defines whether to show breadcrumbs on the page or not. - def show_local_breadcrumb - false - end - private def ensure_valid_provider_type_selected From ba91ed8f622ccbcaa97c4edaaa10042f87037d7e Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Thu, 4 Apr 2024 08:43:09 +0200 Subject: [PATCH 28/39] Add breadcrumb to edit state of the project list page header --- app/components/members/index_page_header_component.html.erb | 6 +++--- .../projects/index_page_header_component.html.erb | 3 ++- .../edit_form_header_component.html.erb | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index e288c580c9c9..dd9c385e5e57 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -7,9 +7,9 @@ scheme: :default, icon: "filter", label: I18n.t(:description_filter), - id: 'filter-member-button', + id: "filter-member-button", aria: { label: I18n.t(:description_filter) }, - class: 'toggle-member-filter-link', + class: "toggle-member-filter-link", data: filter_button_data_attributes) header.with_action_button(scheme: :primary, @@ -18,7 +18,7 @@ size: :medium, aria: { label: I18n.t(:button_add_member) }, title: I18n.t(:button_add_member), - id: 'add-member-button', + id: "add-member-button", data: add_button_data_attributes) do |button| button.with_leading_visual_icon(icon: :plus) t('activerecord.models.member') diff --git a/app/components/projects/index_page_header_component.html.erb b/app/components/projects/index_page_header_component.html.erb index 2e905fe89bd5..5c69aaf3b7f0 100644 --- a/app/components/projects/index_page_header_component.html.erb +++ b/app/components/projects/index_page_header_component.html.erb @@ -93,7 +93,7 @@ %> <% else %> - <% header.with_title(mt: 2, mb: 2, data: { 'test-selector': 'project-query-name'}) do + <% header.with_title(data: { 'test-selector': 'project-query-name'}) do primer_form_with(model: query, url: projects_queries_path, scope: 'query', @@ -106,6 +106,7 @@ render(Queries::Projects::Create.new(f)) end end %> + <% header.with_breadcrumbs(breadcrumb_items)%> <% end %> <% end %> diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.html.erb b/app/components/settings/project_custom_fields/edit_form_header_component.html.erb index 17cda2a8a7c2..9cb8f75cdd77 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.html.erb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.html.erb @@ -28,7 +28,7 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <%= render(Primer::OpenProject::PageHeader.new) do |header| - header.with_title(variant: :medium) { @custom_field.name } + header.with_title { @custom_field.name } header.with_description { t("settings.project_attributes.edit.description") } header.with_breadcrumbs(breadcrumbs_items) end From bbf0a01455823acd8a9c1e0deb3c7c4e0a6fef0a Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Thu, 4 Apr 2024 09:06:12 +0200 Subject: [PATCH 29/39] Add required breadcrumb elements to Storages and Project attribute page --- .../edit_form_header_component.rb | 6 +++--- .../project_custom_fields/header_component.rb | 2 ++ .../controllers/storages/admin/storages_controller.rb | 11 ----------- .../app/views/storages/admin/storages/index.html.erb | 7 +++---- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/app/components/settings/project_custom_fields/edit_form_header_component.rb b/app/components/settings/project_custom_fields/edit_form_header_component.rb index c606dd4c5e82..61365dec3320 100644 --- a/app/components/settings/project_custom_fields/edit_form_header_component.rb +++ b/app/components/settings/project_custom_fields/edit_form_header_component.rb @@ -37,9 +37,9 @@ def initialize(custom_field:) def breadcrumbs_items [{ href: admin_index_path, text: t("label_administration") }, - { href: admin_settings_project_custom_fields_path, text: t("label_project_plural") }, - { href: admin_settings_project_custom_fields_path, text: t("settings.project_attributes.heading") }, - @custom_field.name + { href: admin_settings_project_custom_fields_path, text: t("label_project_plural") }, + { href: admin_settings_project_custom_fields_path, text: t("settings.project_attributes.heading") }, + @custom_field.name ] end end diff --git a/app/components/settings/project_custom_fields/header_component.rb b/app/components/settings/project_custom_fields/header_component.rb index cf0b3e54cce7..7299ecc409a0 100644 --- a/app/components/settings/project_custom_fields/header_component.rb +++ b/app/components/settings/project_custom_fields/header_component.rb @@ -32,8 +32,10 @@ class HeaderComponent < ApplicationComponent include ApplicationHelper include OpPrimer::ComponentHelpers include OpTurbo::Streamable + def breadcrumbs_items [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_project_custom_fields_path, text: t("label_project_plural") }, t("settings.project_attributes.heading")] end end diff --git a/modules/storages/app/controllers/storages/admin/storages_controller.rb b/modules/storages/app/controllers/storages/admin/storages_controller.rb index 31043280f700..9fa06960d484 100644 --- a/modules/storages/app/controllers/storages/admin/storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/storages_controller.rb @@ -194,17 +194,6 @@ def replace_oauth_application end end - # Used by: admin layout - # Breadcrumbs is something like OpenProject > Admin > Storages. - # This returns the name of the last part (Storages admin page) - def default_breadcrumb - if action_name == "index" - t(:project_module_storages) - else - ActionController::Base.helpers.link_to(t(:project_module_storages), admin_settings_storages_path) - end - end - private def ensure_valid_provider_type_selected diff --git a/modules/storages/app/views/storages/admin/storages/index.html.erb b/modules/storages/app/views/storages/admin/storages/index.html.erb index 4601b5a0d68d..edbc7b211a7d 100644 --- a/modules/storages/app/views/storages/admin/storages/index.html.erb +++ b/modules/storages/app/views/storages/admin/storages/index.html.erb @@ -10,10 +10,9 @@ <%= t("storages.page_titles.file_storages.subtitle") %> <% end %> - <% header.with_breadcrumbs(breadcrumb_paths( - link_to(t(:label_administration), admin_index_path), - default_breadcrumb - )) %> + <% header.with_breadcrumbs([{ href: admin_index_path, text: t("label_administration") }, + t("project_module_storages")]) %> + <% header.with_action_button(mobile_icon: "star", mobile_label: "Star") do %> <%= render(Storages::Admin::NewStorageButtonComponent.new) %> <% end %> From 735e5ef9a9708c7cf0a43da9f9696a39fb030373 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Thu, 4 Apr 2024 14:16:33 +0200 Subject: [PATCH 30/39] Update primer to 0.27.0 so that we can use the Dialog slot on the project attribute page and the the extended menu on the storages index page --- Gemfile | 2 +- Gemfile.lock | 4 +- .../dialog_body_form_component.html.erb | 2 +- .../header_component.html.erb | 49 +++++++++---------- frontend/package-lock.json | 28 +++++------ frontend/package.json | 4 +- .../new_storage_button_component.html.erb | 14 +++--- .../admin/new_storage_button_component.rb | 5 ++ .../storages/admin/storages/index.html.erb | 14 ++---- 9 files changed, 59 insertions(+), 63 deletions(-) diff --git a/Gemfile b/Gemfile index ac42052f3d73..09657ff7d8d5 100644 --- a/Gemfile +++ b/Gemfile @@ -383,4 +383,4 @@ end gem "openproject-octicons", "~>19.9.0" gem "openproject-octicons_helper", "~>19.9.0" -gem "openproject-primer_view_components", "~>0.26.0" +gem "openproject-primer_view_components", "~>0.27.0" diff --git a/Gemfile.lock b/Gemfile.lock index b73af27922ab..b40fefdf14a4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -774,7 +774,7 @@ GEM actionview openproject-octicons (= 19.9.0) railties - openproject-primer_view_components (0.26.0) + openproject-primer_view_components (0.27.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) openproject-octicons (>= 19.9.0) @@ -1266,7 +1266,7 @@ DEPENDENCIES openproject-octicons (~> 19.9.0) openproject-octicons_helper (~> 19.9.0) openproject-openid_connect! - openproject-primer_view_components (~> 0.26.0) + openproject-primer_view_components (~> 0.27.0) openproject-recaptcha! openproject-reporting! openproject-storages! diff --git a/app/components/settings/project_custom_field_sections/dialog_body_form_component.html.erb b/app/components/settings/project_custom_field_sections/dialog_body_form_component.html.erb index 49626ea97d57..a45d6a52cb20 100644 --- a/app/components/settings/project_custom_field_sections/dialog_body_form_component.html.erb +++ b/app/components/settings/project_custom_field_sections/dialog_body_form_component.html.erb @@ -2,7 +2,7 @@ component_wrapper do primer_form_with(**form_config) do |f| component_collection do |collection| - collection.with_component(Primer::Alpha::Dialog::Body.new) do + collection.with_component(Primer::BaseComponent.new(tag: :div)) do flex_layout(my: 3) do |modal_body| modal_body.with_row do render(ProjectCustomFieldSections::NameForm.new(f)) diff --git a/app/components/settings/project_custom_fields/header_component.html.erb b/app/components/settings/project_custom_fields/header_component.html.erb index fdf0ceee9143..7f37d81f3e1f 100644 --- a/app/components/settings/project_custom_fields/header_component.html.erb +++ b/app/components/settings/project_custom_fields/header_component.html.erb @@ -1,33 +1,30 @@ +<% button_block = lambda do |button| + button.with_leading_visual_icon(icon: :plus) + t('settings.project_attributes.label_new_section') +end %> <%= - component_wrapper do + component_wrapper do render Primer::OpenProject::PageHeader.new do |header| - header.with_title(variant: :default) { t('settings.project_attributes.heading') } - header.with_description { t('settings.project_attributes.heading_description') } + header.with_title(variant: :default) { t("settings.project_attributes.heading") } + header.with_description { t("settings.project_attributes.heading_description") } header.with_breadcrumbs(breadcrumbs_items) - flex_layout(justify_content: :space_between, align_items: :center) do |action_buttons_container| - action_buttons_container.with_column(mr: 2) do - header.with_action_button(tag: :a, - href: new_admin_settings_project_custom_field_path(type: "ProjectCustomField"), - scheme: :primary, - data: { turbo: "false", qa_selector: "new-project-custom-field-button" }, - mobile_icon: 'plus', - mobile_label: t('settings.project_attributes.label_new_attribute')) do |button| - button.with_leading_visual_icon(icon: :plus) - t('settings.project_attributes.label_new_attribute') - end - end - action_buttons_container.with_column do - render(Primer::Alpha::Dialog.new( - id: "project-custom-field-section-dialog", title: t('settings.project_attributes.label_new_section'), - size: :medium_portrait - )) do |dialog| - dialog.with_show_button('aria-label': t('settings.project_attributes.label_new_section'), scheme: :default) do |button| - button.with_leading_visual_icon(icon: :plus) - t('settings.project_attributes.label_new_section') - end - render(Settings::ProjectCustomFieldSections::DialogBodyFormComponent.new()) - end + header.with_action_button(tag: :a, + href: new_admin_settings_project_custom_field_path(type: "ProjectCustomField"), + scheme: :primary, + data: { turbo: "false", qa_selector: "new-project-custom-field-button" }, + mobile_icon: :plus, + mobile_label: t("settings.project_attributes.label_new_attribute")) do |button| + button.with_leading_visual_icon(icon: :plus) + t("settings.project_attributes.label_new_attribute") + end + + header.with_action_dialog(mobile_icon: :plus, + mobile_label: t('settings.project_attributes.label_new_section'), + dialog_arguments: {id: "project-custom-field-section-dialog", title: t('settings.project_attributes.label_new_section', size: :medium_portrait)}, + button_arguments: {'aria-label': t('settings.project_attributes.label_new_section'), button_block: button_block}) do |dialog| + dialog.with_body do + render(Settings::ProjectCustomFieldSections::DialogBodyFormComponent.new) end end end diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c2e028d6f6aa..09ddf48d2498 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,7 +47,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.26.0", + "@openproject/primer-view-components": "^0.27.0", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -4519,9 +4519,9 @@ } }, "node_modules/@openproject/primer-view-components": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", - "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", + "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", "dependencies": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -4604,9 +4604,9 @@ }, "node_modules/@primer/view-components": { "name": "@openproject/primer-view-components", - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", - "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", + "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", "dependencies": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -23846,9 +23846,9 @@ } }, "@openproject/primer-view-components": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", - "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", + "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", "requires": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -23904,7 +23904,7 @@ "integrity": "sha512-Mcpt9CyajnPW8TJmZYIUhnctdLk7rfsoyvh8w4qDydu2C7HHOHa0wKQjf0zofQ+AyJOIW1Gfa9xvBfwAeNkgoQ==", "requires": { "@primer/primitives": "^7.15.12", - "@primer/view-components": "npm:@openproject/primer-view-components@^0.26.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.27.0" } }, "@primer/primitives": { @@ -23913,9 +23913,9 @@ "integrity": "sha512-ujAsbRB5Xw6rrxizbTgv1bxpraZ091stPMsO6pqGxzc+zIyhrojpGVBuCKJ+RYkpbKK7T4bZzgOT/KyWBAFwwg==" }, "@primer/view-components": { - "version": "npm:@openproject/primer-view-components@0.26.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.26.0.tgz", - "integrity": "sha512-jLvrZvod6tTWnXy3Qekd30KBYbGuXPB41cHOxtEQ4uBRe/nlNto1khB1yoZKeOFASaYYrJ7mwIQfx1S2EZ2Saw==", + "version": "npm:@openproject/primer-view-components@0.27.0", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", + "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", "requires": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", diff --git a/frontend/package.json b/frontend/package.json index 8453f292b0fd..7a696e868677 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -98,7 +98,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.26.0", + "@openproject/primer-view-components": "^0.27.0", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -176,6 +176,6 @@ "generate-typings": "tsc -d -p src/tsconfig.app.json" }, "overrides": { - "@primer/view-components": "npm:@openproject/primer-view-components@^0.26.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.27.0" } } diff --git a/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb b/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb index cf0ccf551ee6..90d627f3db27 100644 --- a/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb +++ b/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb @@ -1,10 +1,12 @@ +<% button_block = lambda do |button| + button.with_leading_visual_icon(icon: :plus) + button.with_trailing_action_icon(icon: :"triangle-down") + label +end %> + <%= - render(Primer::Alpha::ActionMenu.new(test_selector: 'storages-select-provider-action-menu')) do |menu| - menu.with_show_button(**show_button_options) do |button| - button.with_leading_visual_icon(icon: :plus) - button.with_trailing_action_icon(icon: :"triangle-down") - label - end + @header.with_action_menu(menu_arguments: { test_selector: 'storages-select-provider-action-menu', anchor_align: :end }, + button_arguments: { **show_button_options, button_block: button_block }) do |menu| ::Storages::Storage::PROVIDER_TYPES.each do |provider_type| short_provider_type = ::Storages::Storage.shorten_provider_type(provider_type) diff --git a/modules/storages/app/components/storages/admin/new_storage_button_component.rb b/modules/storages/app/components/storages/admin/new_storage_button_component.rb index 690c155e608c..a157eb5e5e63 100644 --- a/modules/storages/app/components/storages/admin/new_storage_button_component.rb +++ b/modules/storages/app/components/storages/admin/new_storage_button_component.rb @@ -33,6 +33,11 @@ class NewStorageButtonComponent < ApplicationComponent # rubocop:disable OpenPro options scheme: :primary, size: :medium + def initialize(header, **options) + @header = header + super + end + def show_button_options { scheme:, size:, diff --git a/modules/storages/app/views/storages/admin/storages/index.html.erb b/modules/storages/app/views/storages/admin/storages/index.html.erb index edbc7b211a7d..7fb325f3ed51 100644 --- a/modules/storages/app/views/storages/admin/storages/index.html.erb +++ b/modules/storages/app/views/storages/admin/storages/index.html.erb @@ -2,20 +2,12 @@ <% html_title t(:label_administration), t("project_module_storages") %> <%= render(Primer::OpenProject::PageHeader.new) do |header| %> - <% header.with_title do %> - <%= t("project_module_storages") %> - <% end %> - - <% header.with_description do %> - <%= t("storages.page_titles.file_storages.subtitle") %> - <% end %> - + <% header.with_title { t("project_module_storages") } %> + <% header.with_description { t("storages.page_titles.file_storages.subtitle") } %> <% header.with_breadcrumbs([{ href: admin_index_path, text: t("label_administration") }, t("project_module_storages")]) %> - <% header.with_action_button(mobile_icon: "star", mobile_label: "Star") do %> - <%= render(Storages::Admin::NewStorageButtonComponent.new) %> - <% end %> + <%= render(Storages::Admin::NewStorageButtonComponent.new(header)) %> <% end %> <%= render(::Storages::Admin::StorageListComponent.new(@storages)) %> From b1c39321ec2efc840f442ab2621e73997f174a79 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Thu, 4 Apr 2024 15:10:01 +0200 Subject: [PATCH 31/39] Reflect the sidebar hierarchy in the breadcrumbs of the Members page --- .../members/index_page_header_component.rb | 35 ++++++- app/controllers/members/menus_controller.rb | 73 +------------- app/helpers/menus/members_helper.rb | 98 +++++++++++++++++++ 3 files changed, 135 insertions(+), 71 deletions(-) create mode 100644 app/helpers/menus/members_helper.rb diff --git a/app/components/members/index_page_header_component.rb b/app/components/members/index_page_header_component.rb index 91fc6881983c..87a52bae23b5 100644 --- a/app/components/members/index_page_header_component.rb +++ b/app/components/members/index_page_header_component.rb @@ -31,6 +31,7 @@ class Members::IndexPageHeaderComponent < ApplicationComponent include OpPrimer::ComponentHelpers include ApplicationHelper + include Menus::MembersHelper def initialize(project: nil) super @@ -57,6 +58,38 @@ def filter_button_data_attributes end def breadcrumb_items - [{ href: project_overview_path(@project.id), text: @project.name }, t(:label_member_plural)] + [{ href: project_overview_path(@project.id), text: @project.name }, + current_breadcrumb_element] + end + + def current_breadcrumb_element + # Rework this, when the Members page actually works with queries + query = current_query + query_name = query[:query_name] + menu_header = query[:menu_header] + + if query && query_name + if menu_header.present? + I18n.t("menus.breadcrumb.nested_element", section_header: menu_header, title: query_name).html_safe + else + query_name + end + else + t(:label_member_plural) + end + end + + def current_query + current_query_name = I18n.t(:label_member_plural) + current_object = first_level_menu_items.find do |section| + section.children.find do |menu_query| + if !!menu_query.selected + current_query_name = menu_query.title + menu_query + end + end + end + + { query_name: current_query_name, menu_header: current_object&.header } end end diff --git a/app/controllers/members/menus_controller.rb b/app/controllers/members/menus_controller.rb index ab205fc3aff0..75be7ba2c8c2 100644 --- a/app/controllers/members/menus_controller.rb +++ b/app/controllers/members/menus_controller.rb @@ -27,81 +27,14 @@ #++ module Members class MenusController < ApplicationController + include Menus::MembersHelper + before_action :find_project_by_project_id, :authorize def show - @sidebar_menu_items = first_level_menu_items + nested_menu_items + @sidebar_menu_items = first_level_menu_items render layout: nil end - - private - - def first_level_menu_items - [ - OpenProject::Menu::MenuGroup.new(header: nil, children: user_status_options) - ] - end - - def user_status_options - [ - OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.all"), - href: project_members_path, - selected: active_filter_count == 0), - OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.locked"), - href: project_members_path(status: :locked), - selected: selected?(:status, :locked)), - OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.invited"), - href: project_members_path(status: :invited), - selected: selected?(:status, :invited)) - ] - end - - def nested_menu_items - [ - OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.project_roles"), children: project_roles_entries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.wp_shares"), children: permission_menu_entries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.groups"), children: project_group_entries) - ] - end - - def project_roles_entries - ProjectRole - .where(id: MemberRole.where(member_id: @project.members.select(:id)).select(:role_id)) - .distinct - .pluck(:id, :name) - .map { |id, name| menu_item(:role_id, id, name) } - end - - def permission_menu_entries - Members::UserFilterComponent - .share_options - .map { |name, id| menu_item(:shared_role_id, id, name) } - end - - def project_group_entries - @project - .groups - .order(lastname: :asc) - .distinct - .pluck(:id, :lastname) - .map { |id, name| menu_item(:group_id, id, name) } - end - - def menu_item(filter_key, id, name) - OpenProject::Menu::MenuItem.new(title: name, - href: project_members_path(filter_key => id), - selected: selected?(filter_key, id)) - end - - def selected?(filter_key, value) - return false if active_filter_count > 1 - - params[filter_key] == value.to_s - end - - def active_filter_count - @active_filter_count ||= (params.keys & Members::UserFilterComponent.filter_param_keys.map(&:to_s)).count - end end end diff --git a/app/helpers/menus/members_helper.rb b/app/helpers/menus/members_helper.rb new file mode 100644 index 000000000000..06fe2d4931d6 --- /dev/null +++ b/app/helpers/menus/members_helper.rb @@ -0,0 +1,98 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 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 Menus + module MembersHelper + def first_level_menu_items + [OpenProject::Menu::MenuGroup.new(header: nil, children: user_status_options)] + nested_menu_items + end + + private + + def user_status_options + [ + OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.all"), + href: project_members_path, + selected: active_filter_count == 0), + OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.locked"), + href: project_members_path(status: :locked), + selected: selected?(:status, :locked)), + OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.invited"), + href: project_members_path(status: :invited), + selected: selected?(:status, :invited)) + ] + end + + def nested_menu_items + [ + OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.project_roles"), children: project_roles_entries), + OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.wp_shares"), children: permission_menu_entries), + OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.groups"), children: project_group_entries) + ] + end + + def project_roles_entries + ProjectRole + .where(id: MemberRole.where(member_id: @project.members.select(:id)).select(:role_id)) + .distinct + .pluck(:id, :name) + .map { |id, name| menu_item(:role_id, id, name) } + end + + def permission_menu_entries + Members::UserFilterComponent + .share_options + .map { |name, id| menu_item(:shared_role_id, id, name) } + end + + def project_group_entries + @project + .groups + .order(lastname: :asc) + .distinct + .pluck(:id, :lastname) + .map { |id, name| menu_item(:group_id, id, name) } + end + + def menu_item(filter_key, id, name) + OpenProject::Menu::MenuItem.new(title: name, + href: project_members_path(filter_key => id), + selected: selected?(filter_key, id)) + end + + def selected?(filter_key, value) + return false if active_filter_count > 1 + + params[filter_key] == value.to_s + end + + def active_filter_count + @active_filter_count ||= (params.keys & Members::UserFilterComponent.filter_param_keys.map(&:to_s)).count + end + end +end From 15d619b9b5953d45bbed370f745278355c21ad19 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Fri, 5 Apr 2024 08:24:47 +0200 Subject: [PATCH 32/39] Fix breadcrumb and page title for the members page --- .../index_page_header_component.html.erb | 2 +- .../members/index_page_header_component.rb | 33 ++++++++++++++----- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index dd9c385e5e57..9d1c80dae7bd 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -1,6 +1,6 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| - header.with_title { t(:label_member_plural) } + header.with_title { page_title } header.with_breadcrumbs(breadcrumb_items) header.with_action_icon_button(mobile_icon: "filter", diff --git a/app/components/members/index_page_header_component.rb b/app/components/members/index_page_header_component.rb index 87a52bae23b5..6c6df07280c1 100644 --- a/app/components/members/index_page_header_component.rb +++ b/app/components/members/index_page_header_component.rb @@ -59,16 +59,29 @@ def filter_button_data_attributes def breadcrumb_items [{ href: project_overview_path(@project.id), text: @project.name }, + { href: project_members_path(@project), text: t(:label_member_plural) }, current_breadcrumb_element] end + def page_title + # Rework this, when the Members page actually works with queries + @query ||= current_query + query_name = @query[:query_name] + + if @query && query_name + query_name + else + t(:label_member_plural) + end + end + def current_breadcrumb_element # Rework this, when the Members page actually works with queries - query = current_query - query_name = query[:query_name] - menu_header = query[:menu_header] + @query ||= current_query + query_name = @query[:query_name] + menu_header = @query[:menu_header] - if query && query_name + if @query && query_name if menu_header.present? I18n.t("menus.breadcrumb.nested_element", section_header: menu_header, title: query_name).html_safe else @@ -80,16 +93,18 @@ def current_breadcrumb_element end def current_query - current_query_name = I18n.t(:label_member_plural) - current_object = first_level_menu_items.find do |section| + query_name = nil + menu_header = nil + + first_level_menu_items.find do |section| section.children.find do |menu_query| if !!menu_query.selected - current_query_name = menu_query.title - menu_query + query_name = menu_query.title + menu_header = section.header end end end - { query_name: current_query_name, menu_header: current_object&.header } + { query_name:, menu_header: } end end From 4ffa2ff111586faf37b1a49d7ad029101681ec06 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Fri, 5 Apr 2024 08:25:10 +0200 Subject: [PATCH 33/39] Add label for zen mode (used by Primer::OpenProject::ZenModeButton) --- config/locales/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index f2d943350150..e6fddf53ef48 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2384,6 +2384,7 @@ Project attributes and sections are defined in the Date: Fri, 5 Apr 2024 08:32:36 +0200 Subject: [PATCH 34/39] Remove NewStorageButtonComponent as it does not work outside a header any more and is thus obsolete --- .../new_storage_button_component.html.erb | 22 -------- .../admin/new_storage_button_component.rb | 55 ------------------- .../storages/admin/storages/index.html.erb | 26 ++++++++- .../new_storage_button_component_spec.rb | 42 -------------- 4 files changed, 25 insertions(+), 120 deletions(-) delete mode 100644 modules/storages/app/components/storages/admin/new_storage_button_component.html.erb delete mode 100644 modules/storages/app/components/storages/admin/new_storage_button_component.rb delete mode 100644 modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb diff --git a/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb b/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb deleted file mode 100644 index 90d627f3db27..000000000000 --- a/modules/storages/app/components/storages/admin/new_storage_button_component.html.erb +++ /dev/null @@ -1,22 +0,0 @@ -<% button_block = lambda do |button| - button.with_leading_visual_icon(icon: :plus) - button.with_trailing_action_icon(icon: :"triangle-down") - label -end %> - -<%= - @header.with_action_menu(menu_arguments: { test_selector: 'storages-select-provider-action-menu', anchor_align: :end }, - button_arguments: { **show_button_options, button_block: button_block }) do |menu| - - ::Storages::Storage::PROVIDER_TYPES.each do |provider_type| - short_provider_type = ::Storages::Storage.shorten_provider_type(provider_type) - - menu.with_item( - label: I18n.t("storages.provider_types.#{short_provider_type}.name"), - href: url_helpers.select_provider_admin_settings_storages_path(provider: short_provider_type) - ) do |item| - item.with_trailing_visual_icon(icon: "op-enterprise-addons", classes: "upsale-colored") if show_ee_icon?(provider_type:) - end - end - end -%> diff --git a/modules/storages/app/components/storages/admin/new_storage_button_component.rb b/modules/storages/app/components/storages/admin/new_storage_button_component.rb deleted file mode 100644 index a157eb5e5e63..000000000000 --- a/modules/storages/app/components/storages/admin/new_storage_button_component.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 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 Storages::Admin - class NewStorageButtonComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent - options scheme: :primary, - size: :medium - - def initialize(header, **options) - @header = header - super - end - - def show_button_options - { scheme:, - size:, - aria: { label: I18n.t("storages.label_add_new_storage") } } - end - - def label - I18n.t("storages.label_storage") - end - - def show_ee_icon?(provider_type:) - ::Storages::Storage::one_drive_without_ee_token?(provider_type) - end - end -end diff --git a/modules/storages/app/views/storages/admin/storages/index.html.erb b/modules/storages/app/views/storages/admin/storages/index.html.erb index 7fb325f3ed51..61e09bd52bf4 100644 --- a/modules/storages/app/views/storages/admin/storages/index.html.erb +++ b/modules/storages/app/views/storages/admin/storages/index.html.erb @@ -1,13 +1,37 @@ <% html_title t(:label_administration), t("project_module_storages") %> +<% button_block = lambda do |button| + button.with_leading_visual_icon(icon: :plus) + button.with_trailing_action_icon(icon: :"triangle-down") + I18n.t("storages.label_storage") +end %> + <%= render(Primer::OpenProject::PageHeader.new) do |header| %> <% header.with_title { t("project_module_storages") } %> <% header.with_description { t("storages.page_titles.file_storages.subtitle") } %> <% header.with_breadcrumbs([{ href: admin_index_path, text: t("label_administration") }, t("project_module_storages")]) %> - <%= render(Storages::Admin::NewStorageButtonComponent.new(header)) %> + <%= header.with_action_menu(menu_arguments: { test_selector: 'storages-select-provider-action-menu', + anchor_align: :end }, + button_arguments: { scheme: :primary, + aria: { label: I18n.t("storages.label_add_new_storage") }, + button_block: button_block }) do |menu| + ::Storages::Storage::PROVIDER_TYPES.each do |provider_type| + short_provider_type = ::Storages::Storage.shorten_provider_type(provider_type) + + menu.with_item( + label: I18n.t("storages.provider_types.#{short_provider_type}.name"), + href: url_helpers.select_provider_admin_settings_storages_path(provider: short_provider_type) + ) do |item| + item.with_trailing_visual_icon( + icon: "op-enterprise-addons", + classes: "upsale-colored" + ) if ::Storages::Storage::one_drive_without_ee_token?(provider_type:) + end + end + end %> <% end %> <%= render(::Storages::Admin::StorageListComponent.new(@storages)) %> diff --git a/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb b/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb deleted file mode 100644 index 1ded64dab4f8..000000000000 --- a/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 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. -#++ -# -require "spec_helper" -require_module_spec_helper - -RSpec.describe Storages::Admin::NewStorageButtonComponent, type: :component do - include Rails.application.routes.url_helpers - - it 'renders a "New Storage" Action Menu' do - render_inline(described_class.new) - expect(page).to have_button "Storage", aria: { label: "Add new storage" } - - expect(page).to have_link "Nextcloud", href: select_provider_admin_settings_storages_path(provider: "nextcloud") - expect(page).to have_link "OneDrive/SharePoint", href: select_provider_admin_settings_storages_path(provider: "one_drive") - end -end From b110240b5c8c855d6a221a19f589bb8051167259 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Fri, 5 Apr 2024 08:33:25 +0200 Subject: [PATCH 35/39] Add old breadcrumb methods again for super class compliance && fix tests --- .../project_custom_fields/new_form_header_component.rb | 1 + .../admin/attachments/quarantined_attachments_controller.rb | 6 ++++++ .../attachments/quarantined_attachments/index.html.erb | 2 +- .../admin/settings/project_custom_fields/index.html.erb | 2 ++ .../app/controllers/storages/admin/storages_controller.rb | 6 ++++++ .../app/views/storages/admin/storages/edit.html.erb | 1 - .../app/views/storages/admin/storages/index.html.erb | 2 +- .../spec/features/storages/admin/edit_storage_spec.rb | 4 +--- .../spec/features/storages/admin/index_storages_spec.rb | 1 - spec/features/admin/project_custom_fields/create_spec.rb | 3 ++- spec/features/admin/project_custom_fields/edit_spec.rb | 6 ++++-- spec/support/pages/members.rb | 1 - 12 files changed, 24 insertions(+), 11 deletions(-) diff --git a/app/components/settings/project_custom_fields/new_form_header_component.rb b/app/components/settings/project_custom_fields/new_form_header_component.rb index 29bb2748b729..dca15e48831b 100644 --- a/app/components/settings/project_custom_fields/new_form_header_component.rb +++ b/app/components/settings/project_custom_fields/new_form_header_component.rb @@ -31,6 +31,7 @@ module ProjectCustomFields class NewFormHeaderComponent < ApplicationComponent def breadcrumb_items [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_project_custom_fields_path, text: t("label_project_plural") }, { href: admin_settings_project_custom_fields_path, text: t("settings.project_attributes.heading") }, t("settings.project_attributes.new.heading")] end diff --git a/app/controllers/admin/attachments/quarantined_attachments_controller.rb b/app/controllers/admin/attachments/quarantined_attachments_controller.rb index 233bc5e3e64a..ab85b24b67e5 100644 --- a/app/controllers/admin/attachments/quarantined_attachments_controller.rb +++ b/app/controllers/admin/attachments/quarantined_attachments_controller.rb @@ -51,6 +51,12 @@ def destroy redirect_to action: :index end + def default_breadcrumb; end + + def show_local_breadcrumb + false + end + private def create_journal(container, user, notes) diff --git a/app/views/admin/attachments/quarantined_attachments/index.html.erb b/app/views/admin/attachments/quarantined_attachments/index.html.erb index fa7223bec0e1..55eefb1f37e9 100644 --- a/app/views/admin/attachments/quarantined_attachments/index.html.erb +++ b/app/views/admin/attachments/quarantined_attachments/index.html.erb @@ -2,7 +2,7 @@ <%= render(Primer::OpenProject::PageHeader.new) do |header| - header.with_title(variant: :default) { t('antivirus_scan.quarantined_attachments.title') } + header.with_title { t('antivirus_scan.quarantined_attachments.title') } header.with_breadcrumbs(breadcrumb_items) end %> diff --git a/app/views/admin/settings/project_custom_fields/index.html.erb b/app/views/admin/settings/project_custom_fields/index.html.erb index 14b91d79930d..71c74dbe15b5 100644 --- a/app/views/admin/settings/project_custom_fields/index.html.erb +++ b/app/views/admin/settings/project_custom_fields/index.html.erb @@ -26,6 +26,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See COPYRIGHT and LICENSE files for more details. ++#%> +<% html_title t(:label_administration), t("settings.project_attributes.heading") %> +
<%= render(Settings::ProjectCustomFields::HeaderComponent.new()) %> <%= render(Settings::ProjectCustomFieldSections::IndexComponent.new( diff --git a/modules/storages/app/controllers/storages/admin/storages_controller.rb b/modules/storages/app/controllers/storages/admin/storages_controller.rb index 9fa06960d484..71b478a08147 100644 --- a/modules/storages/app/controllers/storages/admin/storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/storages_controller.rb @@ -194,6 +194,12 @@ def replace_oauth_application end end + def default_breadcrumb; end + + def show_local_breadcrumb + false + end + private def ensure_valid_provider_type_selected diff --git a/modules/storages/app/views/storages/admin/storages/edit.html.erb b/modules/storages/app/views/storages/admin/storages/edit.html.erb index c394af2e30b0..1cc4b02666f2 100644 --- a/modules/storages/app/views/storages/admin/storages/edit.html.erb +++ b/modules/storages/app/views/storages/admin/storages/edit.html.erb @@ -56,7 +56,6 @@ See COPYRIGHT and LICENSE files for more details. mobile_icon: :trash, mobile_label: I18n.t("button_delete"), type: :submit, - data: { "test-selector": "project-query-name"}, aria: { label: I18n.t("storages.label_delete_storage") }, test_selector: "storage-delete-button") do |button| button.with_leading_visual_icon(icon: :trash) diff --git a/modules/storages/app/views/storages/admin/storages/index.html.erb b/modules/storages/app/views/storages/admin/storages/index.html.erb index 61e09bd52bf4..11f1b1192132 100644 --- a/modules/storages/app/views/storages/admin/storages/index.html.erb +++ b/modules/storages/app/views/storages/admin/storages/index.html.erb @@ -28,7 +28,7 @@ end %> item.with_trailing_visual_icon( icon: "op-enterprise-addons", classes: "upsale-colored" - ) if ::Storages::Storage::one_drive_without_ee_token?(provider_type:) + ) if ::Storages::Storage::one_drive_without_ee_token?(provider_type) end end end %> diff --git a/modules/storages/spec/features/storages/admin/edit_storage_spec.rb b/modules/storages/spec/features/storages/admin/edit_storage_spec.rb index bbe471e671a9..5bde5245503b 100644 --- a/modules/storages/spec/features/storages/admin/edit_storage_spec.rb +++ b/modules/storages/spec/features/storages/admin/edit_storage_spec.rb @@ -42,9 +42,7 @@ storage = create(:nextcloud_storage, name: "Foo Nextcloud") visit edit_admin_settings_storage_path(storage) - within_test_selector("page-header-actions") do - click_on "Delete" - end + page.find_test_selector("storage-delete-button").click expect(page).to have_text("DELETE FILE STORAGE") expect(page).to have_current_path("#{confirm_destroy_admin_settings_storage_path(storage)}?utf8=%E2%9C%93") diff --git a/modules/storages/spec/features/storages/admin/index_storages_spec.rb b/modules/storages/spec/features/storages/admin/index_storages_spec.rb index 1d7e00cb790d..c2ba31580596 100644 --- a/modules/storages/spec/features/storages/admin/index_storages_spec.rb +++ b/modules/storages/spec/features/storages/admin/index_storages_spec.rb @@ -48,7 +48,6 @@ it "renders a list of all storages" do within :css, "#content" do - expect(page).to have_list_item(count: 2) expect(page).to have_list_item(nextcloud_storage.name) expect(page).to have_list_item(one_drive_storage.name) end diff --git a/spec/features/admin/project_custom_fields/create_spec.rb b/spec/features/admin/project_custom_fields/create_spec.rb index d6229369c93f..d54e663a4e82 100644 --- a/spec/features/admin/project_custom_fields/create_spec.rb +++ b/spec/features/admin/project_custom_fields/create_spec.rb @@ -48,8 +48,9 @@ end it "shows a correct breadcrumb menu" do - within "#breadcrumb" do + within ".PageHeader-breadcrumbs" do expect(page).to have_link("Administration") + expect(page).to have_link("Projects") expect(page).to have_link("Project attributes") expect(page).to have_text("New attribute") end diff --git a/spec/features/admin/project_custom_fields/edit_spec.rb b/spec/features/admin/project_custom_fields/edit_spec.rb index 3ff90c44b8d0..6c127e877295 100644 --- a/spec/features/admin/project_custom_fields/edit_spec.rb +++ b/spec/features/admin/project_custom_fields/edit_spec.rb @@ -48,8 +48,9 @@ end it "shows a correct breadcrumb menu" do - within "#breadcrumb" do + within ".PageHeader-breadcrumbs" do expect(page).to have_link("Administration") + expect(page).to have_link("Projects") expect(page).to have_link("Project attributes") expect(page).to have_text(boolean_project_custom_field.name) end @@ -71,8 +72,9 @@ expect(boolean_project_custom_field.reload.name).to eq("Updated name") expect(boolean_project_custom_field.reload.project_custom_field_section).to eq(section_for_select_fields) - within "#breadcrumb" do + within ".PageHeader-breadcrumbs" do expect(page).to have_link("Administration") + expect(page).to have_link("Projects") expect(page).to have_link("Project attributes") expect(page).to have_text("Updated name") end diff --git a/spec/support/pages/members.rb b/spec/support/pages/members.rb index a60bfb6e1818..736afb0794a3 100644 --- a/spec/support/pages/members.rb +++ b/spec/support/pages/members.rb @@ -41,7 +41,6 @@ def initialize(project_identifier) def visit! super - expect(page).to have_css('h2', text: I18n.t(:label_member_plural)) self end From ac68ad856cd53ed9890d37c4e0320d0efeed1963 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Fri, 5 Apr 2024 11:14:29 +0200 Subject: [PATCH 36/39] Add correct breadcrumb element for the project settings page of project attributes --- .../projects/settings/project_custom_fields_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/projects/settings/project_custom_fields_controller.rb b/app/controllers/projects/settings/project_custom_fields_controller.rb index b6bd57987504..66fea6fb2dd0 100644 --- a/app/controllers/projects/settings/project_custom_fields_controller.rb +++ b/app/controllers/projects/settings/project_custom_fields_controller.rb @@ -109,6 +109,7 @@ def bulk_edit_service def breadcrumb_items [{ href: project_overview_path(@project.id), text: @project.name }, + { href: project_settings_general_path(@project.id), text: I18n.t("label_project_settings") }, t("settings.project_attributes.heading")] end helper_method :breadcrumb_items From c60c1503dde525e2c2307ef9b1563351c14c3046 Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Wed, 10 Apr 2024 08:58:13 +0200 Subject: [PATCH 37/39] Change order of buttons back until we have decided on how we want to order those buttons and improve code quality --- .../index_page_header_component.html.erb | 18 +- .../index_page_header_component.html.erb | 186 +++++++++--------- .../projects/index_page_header_component.rb | 2 +- 3 files changed, 104 insertions(+), 102 deletions(-) diff --git a/app/components/members/index_page_header_component.html.erb b/app/components/members/index_page_header_component.html.erb index 9d1c80dae7bd..861806cdb5c1 100644 --- a/app/components/members/index_page_header_component.html.erb +++ b/app/components/members/index_page_header_component.html.erb @@ -3,15 +3,6 @@ header.with_title { page_title } header.with_breadcrumbs(breadcrumb_items) - header.with_action_icon_button(mobile_icon: "filter", - scheme: :default, - icon: "filter", - label: I18n.t(:description_filter), - id: "filter-member-button", - aria: { label: I18n.t(:description_filter) }, - class: "toggle-member-filter-link", - data: filter_button_data_attributes) - header.with_action_button(scheme: :primary, mobile_icon: :plus, mobile_label: t('activerecord.models.member'), @@ -23,5 +14,14 @@ button.with_leading_visual_icon(icon: :plus) t('activerecord.models.member') end + + header.with_action_icon_button(mobile_icon: "filter", + scheme: :default, + icon: "filter", + label: I18n.t(:description_filter), + id: "filter-member-button", + aria: { label: I18n.t(:description_filter) }, + class: "toggle-member-filter-link", + data: filter_button_data_attributes) end %> diff --git a/app/components/projects/index_page_header_component.html.erb b/app/components/projects/index_page_header_component.html.erb index 5c69aaf3b7f0..d1ddafbc2a9a 100644 --- a/app/components/projects/index_page_header_component.html.erb +++ b/app/components/projects/index_page_header_component.html.erb @@ -1,114 +1,116 @@ -<%= render(Primer::OpenProject::PageHeader.new) do |header| %> - <% if show_state? %> - <% header.with_title(data: { 'test-selector': 'project-query-name'}) { page_title } %> - <% header.with_breadcrumbs(breadcrumb_items)%> +<%= + render(Primer::OpenProject::PageHeader.new) do |header| + if show_state? + header.with_title(data: { 'test-selector': 'project-query-name'}) { page_title } + header.with_breadcrumbs(breadcrumb_items) - <% if query_saveable? %> - <% header.with_action_text { t('lists.can_be_saved_as') } %> + if query_saveable? + header.with_action_text { t('lists.can_be_saved_as') } + + header.with_action_link(mobile_icon: nil, # Do not show on mobile as it is already part of the menu + mobile_label: nil, + href: new_projects_query_path, + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + }) do + render(Primer::Beta::Octicon.new(icon: "op-save", + align_self: :center, + "aria-label": I18n.t("button_save_as"), + mr: 1) + ) + content_tag(:span, t("button_save_as")) + end + end - <% header.with_action_link(mobile_icon: nil, # Do not show on mobile as it is already part of the menu - mobile_label: nil, - href: new_projects_query_path, - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - }) do %> - <% render(Primer::Beta::Octicon.new(icon: "op-save", - align_self: :center, - "aria-label": I18n.t("button_save_as"), - mr: 1) - ) + content_tag(:span, t("button_save_as")) %> - <% end %> - <% end %> + header.with_action_menu(menu_arguments: { + anchor_align: :end + }, + button_arguments: { + icon: "op-kebab-vertical", + "aria-label": t(:label_more), + data: { "test-selector": "project-more-dropdown-menu" } + }) do |menu| + if gantt_portfolio_project_ids.any? + menu.with_item( + tag: :a, + label: t('projects.index.open_as_gantt'), + href: gantt_portfolio_query_link, + id: 'projects-index-open-as-gantt', + content_arguments: { target: '_blank' } + ) do |item| + item.with_leading_visual_icon(icon: 'op-view-timeline') + end + end - <%= header.with_action_menu(menu_arguments: { - anchor_align: :end - }, - button_arguments: { - icon: "op-kebab-vertical", - "aria-label": t(:label_more), - data: { "test-selector": "project-more-dropdown-menu" } - }) do |menu, button| - if gantt_portfolio_project_ids.any? menu.with_item( tag: :a, - label: t('projects.index.open_as_gantt'), - href: gantt_portfolio_query_link, - id: 'projects-index-open-as-gantt', - content_arguments: { target: '_blank' } + label: t(:label_overall_activity), + href: activities_path ) do |item| - item.with_leading_visual_icon(icon: 'op-view-timeline') + item.with_leading_visual_icon(icon: 'tasklist') end - end - menu.with_item( - tag: :a, - label: t(:label_overall_activity), - href: activities_path - ) do |item| - item.with_leading_visual_icon(icon: 'tasklist') - end + if query_saveable? + menu.with_item( + label: t('button_save_as'), + href: new_projects_query_path, + content_arguments: { + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + } + } + ) do |item| + item.with_leading_visual_icon(icon: :'op-save') + end + end - if query_saveable? menu.with_item( - label: t('button_save_as'), - href: new_projects_query_path, - content_arguments: { - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - } - } + label: t('js.label_export'), + content_arguments: { 'data-show-dialog-id': Projects::ExportListModalComponent::MODAL_ID } ) do |item| - item.with_leading_visual_icon(icon: :'op-save') + item.with_leading_visual_icon(icon: 'sign-out') end - end - menu.with_item( - label: t('js.label_export'), - content_arguments: { 'data-show-dialog-id': Projects::ExportListModalComponent::MODAL_ID } - ) do |item| - item.with_leading_visual_icon(icon: 'sign-out') - end - - menu.with_item( - label: t(:'queries.configure_view.heading'), - content_arguments: { 'data-show-dialog-id': Projects::ConfigureViewModalComponent::MODAL_ID } - ) do |item| - item.with_leading_visual_icon(icon: :gear) - end - - if query.persisted? menu.with_item( - label: t(:button_delete), - scheme: :danger, - content_arguments: { 'data-show-dialog-id': Projects::DeleteListModalComponent::MODAL_ID } + label: t(:'queries.configure_view.heading'), + content_arguments: { 'data-show-dialog-id': Projects::ConfigureViewModalComponent::MODAL_ID } ) do |item| - item.with_leading_visual_icon(icon: 'trash') + item.with_leading_visual_icon(icon: :gear) + end + + if query.persisted? + menu.with_item( + label: t(:button_delete), + scheme: :danger, + content_arguments: { 'data-show-dialog-id': Projects::DeleteListModalComponent::MODAL_ID } + ) do |item| + item.with_leading_visual_icon(icon: 'trash') + end end end - end - %> - <% else %> - <% header.with_title(data: { 'test-selector': 'project-query-name'}) do - primer_form_with(model: query, - url: projects_queries_path, - scope: 'query', - data: { - controller: "params-from-query", - 'application-target': "dynamic", - 'params-from-query-allowed-value': '["filters", "columns"]' - }, - id: 'project-save-form') do |f| - render(Queries::Projects::Create.new(f)) + + else + header.with_title(data: { 'test-selector': 'project-query-name'}) do + primer_form_with(model: query, + url: projects_queries_path, + scope: 'query', + data: { + controller: "params-from-query", + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["filters", "columns"]' + }, + id: 'project-save-form') do |f| + render(Queries::Projects::Create.new(f)) + end end - end %> - <% header.with_breadcrumbs(breadcrumb_items)%> - <% end %> -<% end %> + header.with_breadcrumbs(breadcrumb_items) + end + end +%> <% if show_state? %> <%= render(Projects::ConfigureViewModalComponent.new(query:)) %> diff --git a/app/components/projects/index_page_header_component.rb b/app/components/projects/index_page_header_component.rb index 59f0ec5e3928..ebba3e8a5e4f 100644 --- a/app/components/projects/index_page_header_component.rb +++ b/app/components/projects/index_page_header_component.rb @@ -88,7 +88,7 @@ def current_breadcrumb_element return page_title if query.name.blank? current_object = first_level_menu_items.find do |section| - section.children.find { |menu_query| menu_query.title == query.name }.present? + section.children.any?(&:selected) end if current_object && current_object.header.present? From 2ece709b23d17a36f9575f28b6be1611c226339a Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Wed, 10 Apr 2024 11:01:28 +0200 Subject: [PATCH 38/39] Extract header into separate components for separation of concerns --- .../index_page_header_component.html.erb | 6 +++ .../index_page_header_component.rb | 42 +++++++++++++++++ .../index_page_header_component.html.erb | 6 +++ .../index_page_header_component.rb | 42 +++++++++++++++++ .../index_page_header_component.html.erb | 8 ++++ .../index_page_header_component.rb | 47 +++++++++++++++++++ .../quarantined_attachments_controller.rb | 7 --- .../virus_scanning_settings_controller.rb | 7 --- .../project_custom_fields_controller.rb | 7 --- .../quarantined_attachments/index.html.erb | 7 +-- .../virus_scanning_settings/show.html.erb | 7 +-- .../project_custom_fields/show.html.erb | 11 +---- 12 files changed, 155 insertions(+), 42 deletions(-) create mode 100644 app/components/admin/quarantined_attachments/index_page_header_component.html.erb create mode 100644 app/components/admin/quarantined_attachments/index_page_header_component.rb create mode 100644 app/components/admin/virus_scanning/index_page_header_component.html.erb create mode 100644 app/components/admin/virus_scanning/index_page_header_component.rb create mode 100644 app/components/projects/settings/project_custom_field_sections/index_page_header_component.html.erb create mode 100644 app/components/projects/settings/project_custom_field_sections/index_page_header_component.rb diff --git a/app/components/admin/quarantined_attachments/index_page_header_component.html.erb b/app/components/admin/quarantined_attachments/index_page_header_component.html.erb new file mode 100644 index 000000000000..994462d08155 --- /dev/null +++ b/app/components/admin/quarantined_attachments/index_page_header_component.html.erb @@ -0,0 +1,6 @@ +<%= + render(Primer::OpenProject::PageHeader.new) do |header| + header.with_title { t('antivirus_scan.quarantined_attachments.title') } + header.with_breadcrumbs(breadcrumb_items) + end +%> diff --git a/app/components/admin/quarantined_attachments/index_page_header_component.rb b/app/components/admin/quarantined_attachments/index_page_header_component.rb new file mode 100644 index 000000000000..ed0adf5629a5 --- /dev/null +++ b/app/components/admin/quarantined_attachments/index_page_header_component.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# -- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2010-2023 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 Admin::QuarantinedAttachments + # rubocop:disable OpenProject/AddPreviewForViewComponent + class IndexPageHeaderComponent < ApplicationComponent + include ApplicationHelper + + def breadcrumb_items + [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_attachments_path, text: t("attributes.attachments") }, + t("antivirus_scan.quarantined_attachments.title")] + end + end +end diff --git a/app/components/admin/virus_scanning/index_page_header_component.html.erb b/app/components/admin/virus_scanning/index_page_header_component.html.erb new file mode 100644 index 000000000000..44a4a26f3f3c --- /dev/null +++ b/app/components/admin/virus_scanning/index_page_header_component.html.erb @@ -0,0 +1,6 @@ +<%= render(Primer::OpenProject::PageHeader.new) do |header| %> + <% header.with_title do %> + <%= t('settings.antivirus.title') %> + <% end %> + <% header.with_breadcrumbs(breadcrumb_items)%> +<% end %> diff --git a/app/components/admin/virus_scanning/index_page_header_component.rb b/app/components/admin/virus_scanning/index_page_header_component.rb new file mode 100644 index 000000000000..1ccf9648cb63 --- /dev/null +++ b/app/components/admin/virus_scanning/index_page_header_component.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# -- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2010-2023 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 Admin::VirusScanning + # rubocop:disable OpenProject/AddPreviewForViewComponent + class IndexPageHeaderComponent < ApplicationComponent + include ApplicationHelper + + def breadcrumb_items + [{ href: admin_index_path, text: t("label_administration") }, + { href: admin_settings_attachments_path, text: t("attributes.attachments") }, + t("settings.antivirus.title")] + end + end +end diff --git a/app/components/projects/settings/project_custom_field_sections/index_page_header_component.html.erb b/app/components/projects/settings/project_custom_field_sections/index_page_header_component.html.erb new file mode 100644 index 000000000000..7cbbd5903e1d --- /dev/null +++ b/app/components/projects/settings/project_custom_field_sections/index_page_header_component.html.erb @@ -0,0 +1,8 @@ +<%= render Primer::OpenProject::PageHeader.new do |header| %> + <%= header.with_title(variant: :default) { t('projects.settings.project_custom_fields.header.title') } %> + <%= header.with_description { t('projects.settings.project_custom_fields.header.description', + overview_url: project_path(@project), + admin_settings_url: admin_settings_project_custom_fields_path + ).html_safe } %> + <%= header.with_breadcrumbs(breadcrumb_items) %> +<% end %> diff --git a/app/components/projects/settings/project_custom_field_sections/index_page_header_component.rb b/app/components/projects/settings/project_custom_field_sections/index_page_header_component.rb new file mode 100644 index 000000000000..645e9f17f431 --- /dev/null +++ b/app/components/projects/settings/project_custom_field_sections/index_page_header_component.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# -- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2010-2023 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 Projects::Settings::ProjectCustomFieldSections + # rubocop:disable OpenProject/AddPreviewForViewComponent + class IndexPageHeaderComponent < ApplicationComponent + include ApplicationHelper + + def initialize(project: nil) + super + @project = project + end + + def breadcrumb_items + [{ href: project_overview_path(@project.id), text: @project.name }, + { href: project_settings_general_path(@project.id), text: I18n.t("label_project_settings") }, + t("settings.project_attributes.heading")] + end + end +end diff --git a/app/controllers/admin/attachments/quarantined_attachments_controller.rb b/app/controllers/admin/attachments/quarantined_attachments_controller.rb index ab85b24b67e5..c3fba094ea59 100644 --- a/app/controllers/admin/attachments/quarantined_attachments_controller.rb +++ b/app/controllers/admin/attachments/quarantined_attachments_controller.rb @@ -76,13 +76,6 @@ def find_attachment rescue ActiveRecord::RecordNotFound render_404 end - - def breadcrumb_items - [{ href: admin_index_path, text: t("label_administration") }, - { href: admin_settings_attachments_path, text: t("attributes.attachments") }, - t("antivirus_scan.quarantined_attachments.title")] - end - helper_method :breadcrumb_items end end end diff --git a/app/controllers/admin/settings/virus_scanning_settings_controller.rb b/app/controllers/admin/settings/virus_scanning_settings_controller.rb index 841464c503e9..047391403b77 100644 --- a/app/controllers/admin/settings/virus_scanning_settings_controller.rb +++ b/app/controllers/admin/settings/virus_scanning_settings_controller.rb @@ -101,12 +101,5 @@ def remaining_quarantine_warning file_count: t(:label_x_files, count: Attachment.status_quarantined.count)) redirect_to action: :show end - - def breadcrumb_items - [{ href: admin_index_path, text: t("label_administration") }, - { href: admin_settings_attachments_path, text: t("attributes.attachments") }, - t("settings.antivirus.title")] - end - helper_method :breadcrumb_items end end diff --git a/app/controllers/projects/settings/project_custom_fields_controller.rb b/app/controllers/projects/settings/project_custom_fields_controller.rb index 66fea6fb2dd0..9dbcb329fe5a 100644 --- a/app/controllers/projects/settings/project_custom_fields_controller.rb +++ b/app/controllers/projects/settings/project_custom_fields_controller.rb @@ -106,11 +106,4 @@ def bulk_edit_service project_custom_field_section: @project_custom_field_section ) end - - def breadcrumb_items - [{ href: project_overview_path(@project.id), text: @project.name }, - { href: project_settings_general_path(@project.id), text: I18n.t("label_project_settings") }, - t("settings.project_attributes.heading")] - end - helper_method :breadcrumb_items end diff --git a/app/views/admin/attachments/quarantined_attachments/index.html.erb b/app/views/admin/attachments/quarantined_attachments/index.html.erb index 55eefb1f37e9..adc117666473 100644 --- a/app/views/admin/attachments/quarantined_attachments/index.html.erb +++ b/app/views/admin/attachments/quarantined_attachments/index.html.erb @@ -1,10 +1,5 @@ <% html_title t('antivirus_scan.quarantined_attachments.title') %> -<%= - render(Primer::OpenProject::PageHeader.new) do |header| - header.with_title { t('antivirus_scan.quarantined_attachments.title') } - header.with_breadcrumbs(breadcrumb_items) - end -%> +<%= render ::Admin::QuarantinedAttachments::IndexPageHeaderComponent.new %> <%= render ::Admin::QuarantinedAttachments::TableComponent.new(rows: @attachments) %> diff --git a/app/views/admin/settings/virus_scanning_settings/show.html.erb b/app/views/admin/settings/virus_scanning_settings/show.html.erb index 1550ba9bba95..b036a72431bb 100644 --- a/app/views/admin/settings/virus_scanning_settings/show.html.erb +++ b/app/views/admin/settings/virus_scanning_settings/show.html.erb @@ -28,12 +28,7 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <% html_title t(:label_administration), t('settings.antivirus.title') %> -<%= render(Primer::OpenProject::PageHeader.new) do |header| %> - <% header.with_title do %> - <%= t('settings.antivirus.title') %> - <% end %> - <% header.with_breadcrumbs(breadcrumb_items)%> -<% end %> +<%= render ::Admin::VirusScanning::IndexPageHeaderComponent.new %> <%= styled_form_tag( admin_settings_virus_scanning_path, diff --git a/app/views/projects/settings/project_custom_fields/show.html.erb b/app/views/projects/settings/project_custom_fields/show.html.erb index d0e42b6b05a1..9ca23bd11ef1 100644 --- a/app/views/projects/settings/project_custom_fields/show.html.erb +++ b/app/views/projects/settings/project_custom_fields/show.html.erb @@ -27,17 +27,10 @@ See COPYRIGHT and LICENSE files for more details. ++#%>
- <%= render Primer::OpenProject::PageHeader.new do |header| %> - <%= header.with_title(variant: :default) { t('projects.settings.project_custom_fields.header.title') } %> - <%= header.with_description { t('projects.settings.project_custom_fields.header.description', - overview_url: project_path(@project), - admin_settings_url: admin_settings_project_custom_fields_path - ).html_safe } %> - <%= header.with_breadcrumbs(breadcrumb_items) %> - <% end %> + <%= render Projects::Settings::ProjectCustomFieldSections::IndexPageHeaderComponent.new(project: @project) %> + <%= render(Projects::Settings::ProjectCustomFieldSections::IndexComponent.new( project: @project, project_custom_field_sections: @project_custom_field_sections, )) %>
- From 1a1a3f6c4ade2c33e7b4056a01c13a6bc395ccfd Mon Sep 17 00:00:00 2001 From: Henriette Darge Date: Wed, 10 Apr 2024 11:54:44 +0200 Subject: [PATCH 39/39] Bump to primer version 0.28.1 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- frontend/package-lock.json | 28 ++++++++++++++-------------- frontend/package.json | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Gemfile b/Gemfile index 20e4cd9d71a5..f9abc7f637a5 100644 --- a/Gemfile +++ b/Gemfile @@ -383,4 +383,4 @@ end gem "openproject-octicons", "~>19.9.0" gem "openproject-octicons_helper", "~>19.9.0" -gem "openproject-primer_view_components", "~>0.27.0" +gem "openproject-primer_view_components", "~>0.28.1" diff --git a/Gemfile.lock b/Gemfile.lock index f274f23f6844..f769b91d43e8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -777,7 +777,7 @@ GEM actionview openproject-octicons (= 19.9.0) railties - openproject-primer_view_components (0.27.0) + openproject-primer_view_components (0.28.1) actionview (>= 5.0.0) activesupport (>= 5.0.0) openproject-octicons (>= 19.9.0) @@ -1272,7 +1272,7 @@ DEPENDENCIES openproject-octicons (~> 19.9.0) openproject-octicons_helper (~> 19.9.0) openproject-openid_connect! - openproject-primer_view_components (~> 0.27.0) + openproject-primer_view_components (~> 0.28.1) openproject-recaptcha! openproject-reporting! openproject-storages! diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f38091009196..e4b187fb7cde 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,7 +47,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.27.0", + "@openproject/primer-view-components": "^0.28.1", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -4519,9 +4519,9 @@ } }, "node_modules/@openproject/primer-view-components": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", - "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.28.1.tgz", + "integrity": "sha512-vnVvCHK24uyu8278DTEG+NBK9uwZzimPgAAcN6290MQl0IVKN1PlEkKmqomP69gfXzpZkVIS1rxy0nejKnuXpw==", "dependencies": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -4604,9 +4604,9 @@ }, "node_modules/@primer/view-components": { "name": "@openproject/primer-view-components", - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", - "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.28.1.tgz", + "integrity": "sha512-vnVvCHK24uyu8278DTEG+NBK9uwZzimPgAAcN6290MQl0IVKN1PlEkKmqomP69gfXzpZkVIS1rxy0nejKnuXpw==", "dependencies": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -23846,9 +23846,9 @@ } }, "@openproject/primer-view-components": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", - "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.28.1.tgz", + "integrity": "sha512-vnVvCHK24uyu8278DTEG+NBK9uwZzimPgAAcN6290MQl0IVKN1PlEkKmqomP69gfXzpZkVIS1rxy0nejKnuXpw==", "requires": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", @@ -23904,7 +23904,7 @@ "integrity": "sha512-Mcpt9CyajnPW8TJmZYIUhnctdLk7rfsoyvh8w4qDydu2C7HHOHa0wKQjf0zofQ+AyJOIW1Gfa9xvBfwAeNkgoQ==", "requires": { "@primer/primitives": "^7.15.12", - "@primer/view-components": "npm:@openproject/primer-view-components@^0.27.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.28.1" } }, "@primer/primitives": { @@ -23913,9 +23913,9 @@ "integrity": "sha512-ujAsbRB5Xw6rrxizbTgv1bxpraZ091stPMsO6pqGxzc+zIyhrojpGVBuCKJ+RYkpbKK7T4bZzgOT/KyWBAFwwg==" }, "@primer/view-components": { - "version": "npm:@openproject/primer-view-components@0.27.0", - "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.27.0.tgz", - "integrity": "sha512-nhE6ngu3O/4rQboT1XGCX5854lefvdTcljgqjz6xsqnhlm5WLUje2GQCMR2DvOvOIid1f+F4ZOvmlWkfRYPk2Q==", + "version": "npm:@openproject/primer-view-components@0.28.1", + "resolved": "https://registry.npmjs.org/@openproject/primer-view-components/-/primer-view-components-0.28.1.tgz", + "integrity": "sha512-vnVvCHK24uyu8278DTEG+NBK9uwZzimPgAAcN6290MQl0IVKN1PlEkKmqomP69gfXzpZkVIS1rxy0nejKnuXpw==", "requires": { "@github/auto-check-element": "^5.2.0", "@github/auto-complete-element": "^3.6.2", diff --git a/frontend/package.json b/frontend/package.json index 7a696e868677..e6310aa2c9f8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -98,7 +98,7 @@ "@ngneat/content-loader": "^7.0.0", "@ngx-formly/core": "^6.1.4", "@openproject/octicons-angular": "^19.8.0", - "@openproject/primer-view-components": "^0.27.0", + "@openproject/primer-view-components": "^0.28.1", "@openproject/reactivestates": "^3.0.1", "@primer/css": "^21.1.1", "@uirouter/angular": "^12.0.0", @@ -176,6 +176,6 @@ "generate-typings": "tsc -d -p src/tsconfig.app.json" }, "overrides": { - "@primer/view-components": "npm:@openproject/primer-view-components@^0.27.0" + "@primer/view-components": "npm:@openproject/primer-view-components@^0.28.1" } }