From 75f4179a6769b89b8beb62b66192ea87524d5ae3 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Tue, 14 Nov 2023 13:21:58 +0300 Subject: [PATCH 1/8] feat[Op#50985] Add Primer Flash https://community.openproject.org/work_packages/50985 --- app/helpers/application_helper.rb | 20 ++++++++++++++++++-- app/views/layouts/base.html.erb | 3 ++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 353511180a87..d15e7ee1df38 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -115,8 +115,20 @@ def due_date_distance_in_words(date) end end + def render_primer_flash_message? + flash[:primer_flash].present? + end + + def render_primer_flash_message + return unless render_primer_flash_message? + + render(FlashMessageComponent.new(**flash[:primer_flash].to_hash)) + end + # Renders flash messages - def render_flash_messages + def render_legacy_flash_messages + return if render_primer_flash_message? + messages = flash .reject { |k, _| k.start_with? '_' } .map do |k, v| @@ -139,20 +151,24 @@ def join_flash_messages(messages) end end - def render_flash_message(type, message, html_options = {}) + def render_legacy_flash_message(type, message, html_options = {}) # rubocop:disable Metrics/AbcSize if type.to_s == 'notice' type = 'success' end + toast_css_classes = ["op-toast -#{type}", html_options.delete(:class)] + # Add autohide class to notice flashes if configured if type.to_s == 'success' && User.current.pref.auto_hide_popups? toast_css_classes << 'autohide-toaster' end + html_options = { class: toast_css_classes.join(' '), role: 'alert' }.merge(html_options) close_button = content_tag :a, '', class: 'op-toast--close icon-context icon-close', title: I18n.t('js.close_popup_title'), tabindex: '0' toast = content_tag(:div, join_flash_messages(message), class: 'op-toast--content') + content_tag :div, '', class: 'op-toast--wrapper' do content_tag :div, '', class: 'op-toast--casing' do content_tag :div, html_options do diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb index b5030dc79043..1c8889d18dee 100644 --- a/app/views/layouts/base.html.erb +++ b/app/views/layouts/base.html.erb @@ -115,6 +115,7 @@ See COPYRIGHT and LICENSE files for more details. <% end %>
+ <%= render_primer_flash_message %> <% if show_decoration %> <% end %> - <%= render_flash_messages %> + <%= render_legacy_flash_messages %> <% if show_onboarding_modal? %>
Date: Wed, 22 Nov 2023 17:14:04 +0300 Subject: [PATCH 2/8] feat[Op#50985]: Use Primer Flash for Administration settings with Primer --- .../app/components/flash_message_component.rb | 7 +++++-- ...matically_managed_project_folders_controller.rb | 7 ++++++- .../storages/admin/oauth_clients_controller.rb | 9 +++++++-- .../storages/spec/features/admin_storages_spec.rb | 14 ++++++++++---- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/modules/meeting/app/components/flash_message_component.rb b/modules/meeting/app/components/flash_message_component.rb index bddfb6cc9fee..0431be865f2d 100644 --- a/modules/meeting/app/components/flash_message_component.rb +++ b/modules/meeting/app/components/flash_message_component.rb @@ -31,7 +31,8 @@ class FlashMessageComponent < ApplicationComponent include OpTurbo::Streamable include OpPrimer::ComponentHelpers - def initialize(message: nil, full: false, spacious: false, dismissible: false, icon: nil, scheme: :default) + def initialize(message: nil, full: false, spacious: false, dismissible: false, icon: nil, scheme: :default, + test_selector: "primer-flash-message-component") super @message = message @@ -40,6 +41,7 @@ def initialize(message: nil, full: false, spacious: false, dismissible: false, i @dismissible = dismissible # TODO: not working yet -> JS dependency not provided? @icon = icon @scheme = scheme + @test_selector = test_selector end def call @@ -56,7 +58,8 @@ def call def flash_partial render(Primer::Beta::Flash.new( - full: @full, spacious: @spacious, dismissible: @dismissible, icon: @icon, scheme: @scheme + full: @full, spacious: @spacious, dismissible: @dismissible, icon: @icon, scheme: @scheme, + test_selector: @test_selector )) { @message } end end diff --git a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb index 08c6ccabbbcd..9fe01f4ebae0 100644 --- a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb +++ b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb @@ -74,7 +74,12 @@ def create service_result = call_update_service if service_result.success? - flash[:notice] = I18n.t(:'storages.notice_successful_storage_connection') + flash[:primer_flash] = { + message: I18n.t(:'storages.notice_successful_storage_connection'), + scheme: :success, + dismissible: true, + full: true + } redirect_to admin_settings_storages_path else respond_to do |format| diff --git a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb index de67ad1a96db..a0ea23dce9bd 100644 --- a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb +++ b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb @@ -62,7 +62,7 @@ def new # Actually create a OAuthClient object. # Use service pattern to create a new OAuthClient # Called by: Global app/config/routes.rb to serve Web page - def create # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity + def create # rubocop:disable Metrics/AbcSize call_oauth_clients_create_service service_result.on_failure do @@ -77,7 +77,12 @@ def create # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity format.turbo_stream { render :create } end elsif @storage.provider_type_one_drive? - flash[:notice] = I18n.t(:'storages.notice_successful_storage_connection') + flash[:primer_flash] = { + message: I18n.t(:'storages.notice_successful_storage_connection'), + scheme: :success, + dismissible: true, + full: true + } redirect_to admin_settings_storages_path else raise "Unsupported provider type: #{@storage.short_provider_type}" diff --git a/modules/storages/spec/features/admin_storages_spec.rb b/modules/storages/spec/features/admin_storages_spec.rb index a13f6b2bc96f..f68936d8a976 100644 --- a/modules/storages/spec/features/admin_storages_spec.rb +++ b/modules/storages/spec/features/admin_storages_spec.rb @@ -250,8 +250,11 @@ end expect(page).to have_current_path(admin_settings_storages_path) - expect(page).to have_text("Storage connected successfully! Remember to activate the module and the specific " \ - "storage in the project settings of each desired project to use it.") + expect(page).to have_test_selector( + "primer-flash-message-component", + text: "Storage connected successfully! Remember to activate the module and the specific " \ + "storage in the project settings of each desired project to use it." + ) end end end @@ -320,8 +323,11 @@ end expect(page).to have_current_path(admin_settings_storages_path) - wait_for(page).to have_text("Storage connected successfully! Remember to activate the module and the specific " \ - "storage in the project settings of each desired project to use it.") + wait_for(page).to have_test_selector( + "primer-flash-message-component", + text: "Storage connected successfully! Remember to activate the module and the specific " \ + "storage in the project settings of each desired project to use it." + ) end end end From 9cd439a4c7937c852676dc9f476d992c5968fd9c Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 23 Nov 2023 13:51:18 +0300 Subject: [PATCH 3/8] feat[Op#50985]: Adopt primer banner as it's more feature complete albeit in alpha --- .../app/components/flash_message_component.rb | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/modules/meeting/app/components/flash_message_component.rb b/modules/meeting/app/components/flash_message_component.rb index 0431be865f2d..698aa0d1221b 100644 --- a/modules/meeting/app/components/flash_message_component.rb +++ b/modules/meeting/app/components/flash_message_component.rb @@ -31,14 +31,14 @@ class FlashMessageComponent < ApplicationComponent include OpTurbo::Streamable include OpPrimer::ComponentHelpers - def initialize(message: nil, full: false, spacious: false, dismissible: false, icon: nil, scheme: :default, + def initialize(message: nil, full: false, full_when_narrow: false, dismissible: false, icon: false, scheme: :default, test_selector: "primer-flash-message-component") super @message = message @full = full - @spacious = spacious - @dismissible = dismissible # TODO: not working yet -> JS dependency not provided? + @full_when_narrow = full_when_narrow + @dismissible = dismissible @icon = icon @scheme = scheme @test_selector = test_selector @@ -48,7 +48,7 @@ def call component_wrapper do # even without provided message, the wrapper should be rendered as this allows # for triggering a flash message via turbo stream - if @message.present? + if message.present? flash_partial end end @@ -56,10 +56,24 @@ def call private + attr_reader :message, :full, :full_when_narrow, :dismissible, :icon, :scheme, :test_selector + def flash_partial - render(Primer::Beta::Flash.new( - full: @full, spacious: @spacious, dismissible: @dismissible, icon: @icon, scheme: @scheme, - test_selector: @test_selector - )) { @message } + # The banner component is similar to the flash message component, but is more feature rich. + # - It ALWAYS renders with an icon + # - It can be dismissed + # - It allows for custom actions while flash messages only allow for a dismiss action (which doesn't work yet :/) + # See https://primer.style/components/banner/rails/alpha + render( + Primer::Alpha::Banner.new( + full:, full_when_narrow:, + dismiss_scheme:, icon:, scheme:, + test_selector: + ) + ) { message } + end + + def dismiss_scheme + dismissible ? :remove : :none end end From 6e1a70d24c99d8a217d14d39fe999664efc6e60c Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 23 Nov 2023 14:04:33 +0300 Subject: [PATCH 4/8] feat[Op#50985]: Separate primer banner from FlashMessageComponent --- app/helpers/application_helper.rb | 20 ++++----- app/views/layouts/base.html.erb | 4 +- .../banner_message_component.html.erb | 32 ++++++++++++++ .../components/banner_message_component.rb | 44 +++++++++++++++++++ .../app/components/flash_message_component.rb | 31 +++---------- ...ally_managed_project_folders_controller.rb | 4 +- .../admin/oauth_clients_controller.rb | 4 +- .../spec/features/admin_storages_spec.rb | 4 +- 8 files changed, 99 insertions(+), 44 deletions(-) create mode 100644 modules/meeting/app/components/banner_message_component.html.erb create mode 100644 modules/meeting/app/components/banner_message_component.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d15e7ee1df38..4b092d0ad4df 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -115,19 +115,19 @@ def due_date_distance_in_words(date) end end - def render_primer_flash_message? - flash[:primer_flash].present? + def render_primer_banner_message? + flash[:primer_banner].present? end - def render_primer_flash_message - return unless render_primer_flash_message? + def render_primer_banner_message + return unless render_primer_banner_message? - render(FlashMessageComponent.new(**flash[:primer_flash].to_hash)) + render(BannerMessageComponent.new(**flash[:primer_banner].to_hash)) end # Renders flash messages - def render_legacy_flash_messages - return if render_primer_flash_message? + def render_flash_messages + return if render_primer_banner_message? messages = flash .reject { |k, _| k.start_with? '_' } @@ -151,24 +151,20 @@ def join_flash_messages(messages) end end - def render_legacy_flash_message(type, message, html_options = {}) # rubocop:disable Metrics/AbcSize + def render_flash_message(type, message, html_options = {}) if type.to_s == 'notice' type = 'success' end - toast_css_classes = ["op-toast -#{type}", html_options.delete(:class)] - # Add autohide class to notice flashes if configured if type.to_s == 'success' && User.current.pref.auto_hide_popups? toast_css_classes << 'autohide-toaster' end - html_options = { class: toast_css_classes.join(' '), role: 'alert' }.merge(html_options) close_button = content_tag :a, '', class: 'op-toast--close icon-context icon-close', title: I18n.t('js.close_popup_title'), tabindex: '0' toast = content_tag(:div, join_flash_messages(message), class: 'op-toast--content') - content_tag :div, '', class: 'op-toast--wrapper' do content_tag :div, '', class: 'op-toast--casing' do content_tag :div, html_options do diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb index 1c8889d18dee..9c1dbeddfd61 100644 --- a/app/views/layouts/base.html.erb +++ b/app/views/layouts/base.html.erb @@ -115,7 +115,7 @@ See COPYRIGHT and LICENSE files for more details. <% end %>
- <%= render_primer_flash_message %> + <%= render_primer_banner_message %> <% if show_decoration %> <% end %> - <%= render_legacy_flash_messages %> + <%= render_flash_messages %> <% if show_onboarding_modal? %>
+ +<%= + render(Primer::Alpha::Banner.new(full:, full_when_narrow:, dismiss_scheme:, icon:, scheme:,test_selector:)) { message } +%> diff --git a/modules/meeting/app/components/banner_message_component.rb b/modules/meeting/app/components/banner_message_component.rb new file mode 100644 index 000000000000..cfec9cf6a504 --- /dev/null +++ b/modules/meeting/app/components/banner_message_component.rb @@ -0,0 +1,44 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-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. +#++ + +class BannerMessageComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent + def initialize(message: nil, full: false, full_when_narrow: false, dismiss_scheme: :none, icon: false, scheme: :default, + test_selector: "primer-banner-message-component") + super + + @message = message + @full = full + @full_when_narrow = full_when_narrow + @dismiss_scheme = dismiss_scheme + @icon = icon + @scheme = scheme + @test_selector = test_selector + end + + attr_reader :message, :full, :full_when_narrow, :dismiss_scheme, :icon, :scheme, :test_selector +end diff --git a/modules/meeting/app/components/flash_message_component.rb b/modules/meeting/app/components/flash_message_component.rb index 698aa0d1221b..bddfb6cc9fee 100644 --- a/modules/meeting/app/components/flash_message_component.rb +++ b/modules/meeting/app/components/flash_message_component.rb @@ -31,24 +31,22 @@ class FlashMessageComponent < ApplicationComponent include OpTurbo::Streamable include OpPrimer::ComponentHelpers - def initialize(message: nil, full: false, full_when_narrow: false, dismissible: false, icon: false, scheme: :default, - test_selector: "primer-flash-message-component") + def initialize(message: nil, full: false, spacious: false, dismissible: false, icon: nil, scheme: :default) super @message = message @full = full - @full_when_narrow = full_when_narrow - @dismissible = dismissible + @spacious = spacious + @dismissible = dismissible # TODO: not working yet -> JS dependency not provided? @icon = icon @scheme = scheme - @test_selector = test_selector end def call component_wrapper do # even without provided message, the wrapper should be rendered as this allows # for triggering a flash message via turbo stream - if message.present? + if @message.present? flash_partial end end @@ -56,24 +54,9 @@ def call private - attr_reader :message, :full, :full_when_narrow, :dismissible, :icon, :scheme, :test_selector - def flash_partial - # The banner component is similar to the flash message component, but is more feature rich. - # - It ALWAYS renders with an icon - # - It can be dismissed - # - It allows for custom actions while flash messages only allow for a dismiss action (which doesn't work yet :/) - # See https://primer.style/components/banner/rails/alpha - render( - Primer::Alpha::Banner.new( - full:, full_when_narrow:, - dismiss_scheme:, icon:, scheme:, - test_selector: - ) - ) { message } - end - - def dismiss_scheme - dismissible ? :remove : :none + render(Primer::Beta::Flash.new( + full: @full, spacious: @spacious, dismissible: @dismissible, icon: @icon, scheme: @scheme + )) { @message } end end diff --git a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb index 9fe01f4ebae0..6be4d24b03c4 100644 --- a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb +++ b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb @@ -74,10 +74,10 @@ def create service_result = call_update_service if service_result.success? - flash[:primer_flash] = { + flash[:primer_banner] = { message: I18n.t(:'storages.notice_successful_storage_connection'), scheme: :success, - dismissible: true, + dismiss_scheme: :hide, full: true } redirect_to admin_settings_storages_path diff --git a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb index a0ea23dce9bd..dd40f150c1c9 100644 --- a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb +++ b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb @@ -77,10 +77,10 @@ def create # rubocop:disable Metrics/AbcSize format.turbo_stream { render :create } end elsif @storage.provider_type_one_drive? - flash[:primer_flash] = { + flash[:primer_banner] = { message: I18n.t(:'storages.notice_successful_storage_connection'), scheme: :success, - dismissible: true, + dismiss_scheme: :hide, full: true } redirect_to admin_settings_storages_path diff --git a/modules/storages/spec/features/admin_storages_spec.rb b/modules/storages/spec/features/admin_storages_spec.rb index f68936d8a976..eab0f310d3dd 100644 --- a/modules/storages/spec/features/admin_storages_spec.rb +++ b/modules/storages/spec/features/admin_storages_spec.rb @@ -251,7 +251,7 @@ expect(page).to have_current_path(admin_settings_storages_path) expect(page).to have_test_selector( - "primer-flash-message-component", + "primer-banner-message-component", text: "Storage connected successfully! Remember to activate the module and the specific " \ "storage in the project settings of each desired project to use it." ) @@ -324,7 +324,7 @@ expect(page).to have_current_path(admin_settings_storages_path) wait_for(page).to have_test_selector( - "primer-flash-message-component", + "primer-banner-message-component", text: "Storage connected successfully! Remember to activate the module and the specific " \ "storage in the project settings of each desired project to use it." ) From 4d3fba0cf25a60fd54d890734bf0032a7d350af2 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 30 Nov 2023 15:04:53 +0300 Subject: [PATCH 5/8] chore[Op#50985]: Extract flash message helper from application helper --- app/helpers/application_helper.rb | 60 ---------------- app/helpers/flash_messages_helper.rb | 100 +++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 60 deletions(-) create mode 100644 app/helpers/flash_messages_helper.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4b092d0ad4df..7cdaf798e0d2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -115,66 +115,6 @@ def due_date_distance_in_words(date) end end - def render_primer_banner_message? - flash[:primer_banner].present? - end - - def render_primer_banner_message - return unless render_primer_banner_message? - - render(BannerMessageComponent.new(**flash[:primer_banner].to_hash)) - end - - # Renders flash messages - def render_flash_messages - return if render_primer_banner_message? - - messages = flash - .reject { |k, _| k.start_with? '_' } - .map do |k, v| - if k.to_sym == :modal - component = v[:type].constantize - component.new(**v[:parameters]).render_in(self) - else - render_flash_message(k, v) - end - end - - safe_join messages, "\n" - end - - def join_flash_messages(messages) - if messages.respond_to?(:join) - safe_join(messages, '
'.html_safe) - else - messages - end - end - - def render_flash_message(type, message, html_options = {}) - if type.to_s == 'notice' - type = 'success' - end - toast_css_classes = ["op-toast -#{type}", html_options.delete(:class)] - # Add autohide class to notice flashes if configured - if type.to_s == 'success' && User.current.pref.auto_hide_popups? - toast_css_classes << 'autohide-toaster' - end - html_options = { class: toast_css_classes.join(' '), role: 'alert' }.merge(html_options) - close_button = content_tag :a, '', class: 'op-toast--close icon-context icon-close', - title: I18n.t('js.close_popup_title'), - tabindex: '0' - toast = content_tag(:div, join_flash_messages(message), class: 'op-toast--content') - content_tag :div, '', class: 'op-toast--wrapper' do - content_tag :div, '', class: 'op-toast--casing' do - content_tag :div, html_options do - concat(close_button) - concat(toast) - end - end - end - end - # Yields the given block for each project with its level in the tree # # Wrapper for Project#project_tree diff --git a/app/helpers/flash_messages_helper.rb b/app/helpers/flash_messages_helper.rb new file mode 100644 index 000000000000..ee43bce13ee5 --- /dev/null +++ b/app/helpers/flash_messages_helper.rb @@ -0,0 +1,100 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-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 FlashMessagesHelper + extend ActiveSupport::Concern + + included do + # For .safe_join in join_flash_messages + include ActionView::Helpers::OutputSafetyHelper + end + + def render_primer_banner_message? + flash[:primer_banner].present? + end + + def render_primer_banner_message + return unless render_primer_banner_message? + + render(BannerMessageComponent.new(**flash[:primer_banner].to_hash)) + end + + # Renders flash messages + def render_flash_messages + return if render_primer_banner_message? + + messages = flash + .reject { |k, _| k.start_with? '_' } + .map do |k, v| + if k.to_sym == :modal + component = v[:type].constantize + component.new(**v[:parameters]).render_in(self) + else + render_flash_message(k, v) + end + end + + safe_join messages, "\n" + end + + def join_flash_messages(messages) + if messages.respond_to?(:join) + safe_join(messages, '
'.html_safe) + else + messages + end + end + + def render_flash_message(type, message, html_options = {}) # rubocop:disable Metrics/AbcSize + if type.to_s == 'notice' + type = 'success' + end + + toast_css_classes = ["op-toast -#{type}", html_options.delete(:class)] + + # Add autohide class to notice flashes if configured + if type.to_s == 'success' && User.current.pref.auto_hide_popups? + toast_css_classes << 'autohide-toaster' + end + + html_options = { class: toast_css_classes.join(' '), role: 'alert' }.merge(html_options) + close_button = content_tag :a, '', class: 'op-toast--close icon-context icon-close', + title: I18n.t('js.close_popup_title'), + tabindex: '0' + toast = content_tag(:div, join_flash_messages(message), class: 'op-toast--content') + content_tag :div, '', class: 'op-toast--wrapper' do + content_tag :div, '', class: 'op-toast--casing' do + content_tag :div, html_options do + concat(close_button) + concat(toast) + end + end + end + end +end From 9008257445d346c715664e3f515f65ee33e9b20b Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 30 Nov 2023 15:05:50 +0300 Subject: [PATCH 6/8] chore[Op#50985]: Define common settings as defaults --- modules/meeting/app/components/banner_message_component.rb | 2 +- .../controllers/storages/admin/oauth_clients_controller.rb | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/meeting/app/components/banner_message_component.rb b/modules/meeting/app/components/banner_message_component.rb index cfec9cf6a504..0c865f821c5a 100644 --- a/modules/meeting/app/components/banner_message_component.rb +++ b/modules/meeting/app/components/banner_message_component.rb @@ -27,7 +27,7 @@ #++ class BannerMessageComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent - def initialize(message: nil, full: false, full_when_narrow: false, dismiss_scheme: :none, icon: false, scheme: :default, + def initialize(message: nil, full: true, full_when_narrow: false, dismiss_scheme: :hide, icon: false, scheme: :default, test_selector: "primer-banner-message-component") super diff --git a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb index dd40f150c1c9..bdb512f35972 100644 --- a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb +++ b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb @@ -77,12 +77,7 @@ def create # rubocop:disable Metrics/AbcSize format.turbo_stream { render :create } end elsif @storage.provider_type_one_drive? - flash[:primer_banner] = { - message: I18n.t(:'storages.notice_successful_storage_connection'), - scheme: :success, - dismiss_scheme: :hide, - full: true - } + flash[:primer_banner] = { message: I18n.t(:'storages.notice_successful_storage_connection'), scheme: :success } redirect_to admin_settings_storages_path else raise "Unsupported provider type: #{@storage.short_provider_type}" From 9b22ec5ff02cfdba1953b5ac710bc02c8c46d287 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 30 Nov 2023 15:13:29 +0300 Subject: [PATCH 7/8] fix[Op#50985]: Update delete storage flash messages to primer --- .../storages/admin/storages_controller.rb | 28 +++++++++---------- .../spec/features/admin_storages_spec.rb | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/modules/storages/app/controllers/storages/admin/storages_controller.rb b/modules/storages/app/controllers/storages/admin/storages_controller.rb index 6ad24737f62c..3bf99d2784ea 100644 --- a/modules/storages/app/controllers/storages/admin/storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/storages_controller.rb @@ -31,6 +31,7 @@ # Purpose: CRUD the global admin page of Storages (=Nextcloud servers) class Storages::Admin::StoragesController < ApplicationController using Storages::Peripherals::ServiceResultRefinements + include FlashMessagesHelper # See https://guides.rubyonrails.org/layouts_and_rendering.html for reference on layout layout 'admin' @@ -133,19 +134,14 @@ def edit_host # Update is similar to create above # See also: create above # Called by: Global app/config/routes.rb to serve Web page - def update # rubocop:disable Metrics/AbcSize + def update service_result = ::Storages::Storages::UpdateService .new(user: current_user, model: @storage) .call(permitted_storage_params) @storage = service_result.result if service_result.success? - flash[:notice] = I18n.t(:notice_successful_update) - - respond_to do |format| - format.html { redirect_to edit_admin_settings_storage_path(@storage) } - format.turbo_stream - end + respond_to { |format| format.turbo_stream } else respond_to do |format| format.html { render :edit } @@ -159,15 +155,19 @@ def confirm_destroy end def destroy - Storages::Storages::DeleteService + service_result = Storages::Storages::DeleteService .new(user: User.current, model: @storage) .call - .match( - # rubocop:disable Rails/ActionControllerFlashBeforeRender - on_success: ->(*) { flash[:notice] = I18n.t(:notice_successful_delete) }, - on_failure: ->(error) { flash[:error] = error.full_messages } - # rubocop:enable Rails/ActionControllerFlashBeforeRender - ) + + # rubocop:disable Rails/ActionControllerFlashBeforeRender + service_result.on_failure do + flash[:primer_banner] = { message: join_flash_messages(service_result.errors.full_messages), scheme: :danger } + end + + service_result.on_success do + flash[:primer_banner] = { message: I18n.t(:notice_successful_delete), scheme: :success } + end + # rubocop:enable Rails/ActionControllerFlashBeforeRender redirect_to admin_settings_storages_path end diff --git a/modules/storages/spec/features/admin_storages_spec.rb b/modules/storages/spec/features/admin_storages_spec.rb index eab0f310d3dd..c470062d5571 100644 --- a/modules/storages/spec/features/admin_storages_spec.rb +++ b/modules/storages/spec/features/admin_storages_spec.rb @@ -373,6 +373,7 @@ storage_delete_button.click expect(page).not_to have_text("Foo Nextcloud") + expect(page).to have_text('Successful deletion.') expect(page).to have_current_path(admin_settings_storages_path) end From 6ff1ae574fd27b79c2a865e8c8719d11d9738ed2 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 30 Nov 2023 15:17:09 +0300 Subject: [PATCH 8/8] chore[Op#50985]: Use defaults --- .../admin/automatically_managed_project_folders_controller.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb index 6be4d24b03c4..a0cd6e738c25 100644 --- a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb +++ b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb @@ -76,9 +76,7 @@ def create if service_result.success? flash[:primer_banner] = { message: I18n.t(:'storages.notice_successful_storage_connection'), - scheme: :success, - dismiss_scheme: :hide, - full: true + scheme: :success } redirect_to admin_settings_storages_path else