diff --git a/app/components/button_component.rb b/app/components/button_component.rb index 28615b1ac92..29bca1161a5 100644 --- a/app/components/button_component.rb +++ b/app/components/button_component.rb @@ -1,10 +1,21 @@ # frozen_string_literal: true class ButtonComponent < BaseComponent - attr_reader :action, :icon, :big, :wide, :full_width, :outline, :unstyled, :danger, :tag_options + attr_reader :url, + :method, + :icon, + :big, + :wide, + :full_width, + :outline, + :unstyled, + :danger, + :tag_options def initialize( - action: ->(**tag_options, &block) { button_tag(**tag_options, &block) }, + action: nil, + url: nil, + method: nil, icon: nil, big: false, wide: false, @@ -15,6 +26,8 @@ def initialize( **tag_options ) @action = action + @url = url + @method = method @icon = icon @big = big @wide = wide @@ -53,4 +66,18 @@ def content original_content end end + + def action + @action ||= begin + if url + if method && method != :get + ->(**tag_options, &block) { button_to(url, method:, **tag_options, &block) } + else + ->(**tag_options, &block) { link_to(url, **tag_options, &block) } + end + else + ->(**tag_options, &block) { button_tag(**tag_options, &block) } + end + end + end end diff --git a/app/views/accounts/_pii.html.erb b/app/views/accounts/_pii.html.erb index c4597b8ebaa..8decfe81eb5 100644 --- a/app/views/accounts/_pii.html.erb +++ b/app/views/accounts/_pii.html.erb @@ -5,9 +5,7 @@
<%= t('account.re_verify.banner') %> <%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(account_reauthentication_path, **tag_options, &block) - end, + url: account_reauthentication_path, method: :post, class: 'usa-button usa-button--unstyled', ).with_content(t('account.re_verify.footer')) %> diff --git a/app/views/idv/cancellations/new.html.erb b/app/views/idv/cancellations/new.html.erb index 492cc9ead83..ef752a26176 100644 --- a/app/views/idv/cancellations/new.html.erb +++ b/app/views/idv/cancellations/new.html.erb @@ -7,15 +7,11 @@

<%= t('idv.cancel.description.hybrid') %>

<% c.with_action_button( - action: ->(**tag_options, &block) do - button_to(idv_cancel_path(step: params[:step], location: 'cancel'), **tag_options, &block) - end, + url: idv_cancel_path(step: params[:step], location: 'cancel'), method: :delete, ).with_content(t('forms.buttons.cancel')) %> <% c.with_action_button( - action: ->(**tag_options, &block) do - button_to(idv_cancel_path(step: params[:step]), **tag_options, &block) - end, + url: idv_cancel_path(step: params[:step]), method: :put, outline: true, ).with_content(t('links.go_back')) %> @@ -28,9 +24,7 @@
<%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_session_path(step: params[:step]), **tag_options, &block) - end, + url: idv_session_path(step: params[:step]), method: :delete, big: true, wide: true, @@ -39,9 +33,7 @@ %>
<%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_cancel_path(step: params[:step]), **tag_options, &block) - end, + url: idv_cancel_path(step: params[:step]), method: :put, big: true, wide: true, @@ -61,9 +53,7 @@
<%= render SpinnerButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_cancel_path(step: params[:step], location: 'cancel'), **tag_options, &block) - end, + url: idv_cancel_path(step: params[:step], location: 'cancel'), method: :delete, big: true, wide: true, diff --git a/app/views/idv/confirm_start_over/before_letter.html.erb b/app/views/idv/confirm_start_over/before_letter.html.erb index 1c235438c4b..17f0549a699 100644 --- a/app/views/idv/confirm_start_over/before_letter.html.erb +++ b/app/views/idv/confirm_start_over/before_letter.html.erb @@ -13,9 +13,7 @@
<%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_session_path(step: :request_letter), **tag_options, &block) - end, + url: idv_session_path(step: :request_letter), method: :delete, big: true, wide: true, diff --git a/app/views/idv/confirm_start_over/index.html.erb b/app/views/idv/confirm_start_over/index.html.erb index 5ea412f297c..4d7cc1bf879 100644 --- a/app/views/idv/confirm_start_over/index.html.erb +++ b/app/views/idv/confirm_start_over/index.html.erb @@ -17,9 +17,7 @@
<%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_session_path(step: :gpo_verify), **tag_options, &block) - end, + url: idv_session_path(step: :gpo_verify), method: :delete, big: true, wide: true, diff --git a/app/views/idv/in_person/verify_info/show.html.erb b/app/views/idv/in_person/verify_info/show.html.erb index c89c3a20bf2..5ce62008459 100644 --- a/app/views/idv/in_person/verify_info/show.html.erb +++ b/app/views/idv/in_person/verify_info/show.html.erb @@ -142,9 +142,7 @@ locals:
<%= render SpinnerButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_in_person_verify_info_path, **tag_options, &block) - end, + url: idv_in_person_verify_info_path, big: true, wide: true, action_message: t('idv.messages.verifying'), diff --git a/app/views/idv/verify_info/show.html.erb b/app/views/idv/verify_info/show.html.erb index 9e3e63843b3..a87a5aedd74 100644 --- a/app/views/idv/verify_info/show.html.erb +++ b/app/views/idv/verify_info/show.html.erb @@ -119,9 +119,7 @@ locals:
<%= render SpinnerButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(idv_verify_info_path, **tag_options, &block) - end, + url: idv_verify_info_path, big: true, wide: true, action_message: t('idv.messages.verifying'), diff --git a/app/views/session_timeout/_warning.html.erb b/app/views/session_timeout/_warning.html.erb index abf656dd841..62faad7810b 100644 --- a/app/views/session_timeout/_warning.html.erb +++ b/app/views/session_timeout/_warning.html.erb @@ -49,9 +49,7 @@ t('continue', scope: modal_presenter.translation_scope), ) %> <%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(logout_path, **tag_options, &block) - end, + url: logout_path, method: :delete, big: true, full_width: true, diff --git a/app/views/users/auth_app/edit.html.erb b/app/views/users/auth_app/edit.html.erb index 55bbe2409a5..5345c9bce9c 100644 --- a/app/views/users/auth_app/edit.html.erb +++ b/app/views/users/auth_app/edit.html.erb @@ -22,15 +22,9 @@ <% end %> <%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to( - auth_app_path(id: @form.configuration.id), - form: { aria: { label: t('two_factor_authentication.auth_app.delete') } }, - **tag_options, - &block - ) - end, + url: auth_app_path(id: @form.configuration.id), method: :delete, + form: { aria: { label: t('two_factor_authentication.auth_app.delete') } }, big: true, wide: true, danger: true, diff --git a/app/views/users/authorization_confirmation/new.html.erb b/app/views/users/authorization_confirmation/new.html.erb index ea34d93ec14..8c69467c9bd 100644 --- a/app/views/users/authorization_confirmation/new.html.erb +++ b/app/views/users/authorization_confirmation/new.html.erb @@ -20,9 +20,8 @@
<%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(user_authorization_confirmation_path, method: :post, **tag_options, &block) - end, + url: user_authorization_confirmation_path, + method: :post, big: true, wide: true, ).with_content(t('user_authorization_confirmation.continue')) %> @@ -30,9 +29,8 @@ <%= t('user_authorization_confirmation.or') %>
<%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to(reset_user_authorization_path, method: :delete, **tag_options, &block) - end, + url: reset_user_authorization_path, + method: :delete, big: true, wide: true, ).with_content(t('user_authorization_confirmation.sign_in')) %> diff --git a/app/views/users/backup_code_setup/edit.html.erb b/app/views/users/backup_code_setup/edit.html.erb index 3da1ef6a5c4..0d872caed14 100644 --- a/app/views/users/backup_code_setup/edit.html.erb +++ b/app/views/users/backup_code_setup/edit.html.erb @@ -1,17 +1,21 @@ <% self.title = t('forms.backup_code_regenerate.confirm') %> -<%= render AlertIconComponent.new(icon_name: :warning, class: 'display-block margin-bottom-4') %> +<%= render StatusPageComponent.new(status: :warning) do |c| %> + <% c.with_header { t('forms.backup_code_regenerate.confirm') } %> -<%= render PageHeadingComponent.new.with_content(t('forms.backup_code_regenerate.confirm')) %> +

<%= t('forms.backup_code_regenerate.caution') %>

-

- <%= t('forms.backup_code_regenerate.caution') %> -

+ <%= render ButtonComponent.new( + url: backup_code_setup_path, + big: true, + wide: true, + class: 'margin-top-3 margin-bottom-2', + ).with_content(t('account.index.backup_code_confirm_regenerate')) %> -<%= form_tag(backup_code_setup_path, method: :get, class: 'margin-top-5') do %> - <%= button_tag t('account.index.backup_code_confirm_regenerate'), type: 'submit', - class: 'usa-button usa-button--big usa-button--wide margin-bottom-2' %> + <%= render ButtonComponent.new( + url: account_path, + big: true, + wide: true, + outline: true, + ).with_content(t('links.cancel')) %> <% end %> - -<%= link_to t('links.cancel'), account_path, - class: 'usa-button usa-button--big usa-button--wide usa-button--outline' %> diff --git a/app/views/users/piv_cac/edit.html.erb b/app/views/users/piv_cac/edit.html.erb index 7995216d56c..a4a48700f53 100644 --- a/app/views/users/piv_cac/edit.html.erb +++ b/app/views/users/piv_cac/edit.html.erb @@ -21,19 +21,13 @@ <% end %> <%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to( - piv_cac_path(id: @form.configuration.id), - form: { aria: { label: @presenter.delete_button_label } }, - **tag_options, - &block - ) - end, + url: piv_cac_path(id: @form.configuration.id), method: :delete, + form: { aria: { label: @presenter.delete_button_label } }, big: true, wide: true, danger: true, class: 'display-block margin-top-2', ).with_content(@presenter.delete_button_label) %> -<%= render 'shared/cancel', link: account_path %> \ No newline at end of file +<%= render 'shared/cancel', link: account_path %> diff --git a/app/views/users/webauthn/edit.html.erb b/app/views/users/webauthn/edit.html.erb index 5dc61948680..f57ad50edc9 100644 --- a/app/views/users/webauthn/edit.html.erb +++ b/app/views/users/webauthn/edit.html.erb @@ -19,15 +19,9 @@ <% end %> <%= render ButtonComponent.new( - action: ->(**tag_options, &block) do - button_to( - webauthn_path(id: @form.configuration.id), - form: { aria: { label: @presenter.delete_button_label } }, - **tag_options, - &block - ) - end, + url: webauthn_path(id: @form.configuration.id), method: :delete, + form: { aria: { label: @presenter.delete_button_label } }, big: true, wide: true, danger: true, diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 07cc533c85e..031a569d24c 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -3,19 +3,19 @@ { "warning_type": "Dynamic Render Path", "warning_code": 15, - "fingerprint": "406a2c5ea3d852268958d2db11c146841491b6e87cee9c583dd35f5f41898fb7", + "fingerprint": "0550ef2573eae747e7e4bb6f31851ed77713409b74f7abe48c15a6a82801babb", "check_name": "Render", "message": "Render path contains parameter value", "file": "app/views/idv/cancellations/new.html.erb", - "line": 43, + "line": 31, "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", - "code": "render(action => ButtonComponent.new(:action => (lambda do\n button_to(idv_cancel_path(:step => params[:step]), { **tag_options }, &block)\n end), :method => :put, :big => true, :wide => true, :outline => true, :form => ({ :\"aria-label\" => t(\"idv.cancel.actions.keep_going\") })).with_content(t(\"idv.cancel.actions.keep_going\")), {})", + "code": "render(action => ButtonComponent.new(:url => idv_session_path(:step => params[:step]), :method => :delete, :big => true, :wide => true, :form => ({ :\"aria-label\" => t(\"idv.cancel.actions.start_over\") })).with_content(t(\"idv.cancel.actions.start_over\")), {})", "render_path": [ { "type": "controller", "class": "Idv::CancellationsController", "method": "new", - "line": 13, + "line": 16, "file": "app/controllers/idv/cancellations_controller.rb", "rendered": { "name": "idv/cancellations/new", @@ -37,19 +37,19 @@ { "warning_type": "Dynamic Render Path", "warning_code": 15, - "fingerprint": "8b51f403181f74421f5681ada1096371e1f55fb03d0127db01b5e5da7dda3c51", + "fingerprint": "278d16995e8a645908c9a043314cfeebd8cb094bce766ad5101c62ff08853de6", "check_name": "Render", "message": "Render path contains parameter value", "file": "app/views/idv/cancellations/new.html.erb", - "line": 32, + "line": 60, "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", - "code": "render(action => ButtonComponent.new(:action => (lambda do\n button_to(idv_session_path(:step => params[:step]), { **tag_options }, &block)\n end), :method => :delete, :big => true, :wide => true, :form => ({ :\"aria-label\" => t(\"idv.cancel.actions.start_over\") })).with_content(t(\"idv.cancel.actions.start_over\")), {})", + "code": "render(action => SpinnerButtonComponent.new(:url => idv_cancel_path(:step => params[:step], :location => \"cancel\"), :method => :delete, :big => true, :wide => true, :outline => true, :form => ({ :\"aria-label\" => CancellationsPresenter.new(:sp_name => decorated_sp_session.sp_name, :url_options => url_options).exit_action_text, :data => ({ :form_steps_wait => \"\" }) })).with_content(CancellationsPresenter.new(:sp_name => decorated_sp_session.sp_name, :url_options => url_options).exit_action_text), {})", "render_path": [ { "type": "controller", "class": "Idv::CancellationsController", "method": "new", - "line": 13, + "line": 16, "file": "app/controllers/idv/cancellations_controller.rb", "rendered": { "name": "idv/cancellations/new", @@ -71,19 +71,19 @@ { "warning_type": "Dynamic Render Path", "warning_code": 15, - "fingerprint": "f7d01c6318e6ce369f9fe9bf59b6a3a323034b4b826e2a52a9a87b581d468598", + "fingerprint": "341d99a0fdaf75dff50ea66c9da1b973cb36fc1aac2221480deff6e30d11540a", "check_name": "Render", "message": "Render path contains parameter value", "file": "app/views/idv/cancellations/new.html.erb", - "line": 65, + "line": 40, "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", - "code": "render(action => SpinnerButtonComponent.new(:action => (lambda do\n button_to(idv_cancel_path(:step => params[:step], :location => \"cancel\"), { **tag_options }, &block)\n end), :method => :delete, :big => true, :wide => true, :outline => true, :form => ({ :\"aria-label\" => CancellationsPresenter.new(:sp_name => decorated_sp_session.sp_name, :url_options => url_options).exit_action_text, :data => ({ :form_steps_wait => \"\" }) })).with_content(CancellationsPresenter.new(:sp_name => decorated_sp_session.sp_name, :url_options => url_options).exit_action_text), {})", + "code": "render(action => ButtonComponent.new(:url => idv_cancel_path(:step => params[:step]), :method => :put, :big => true, :wide => true, :outline => true, :form => ({ :\"aria-label\" => t(\"idv.cancel.actions.keep_going\") })).with_content(t(\"idv.cancel.actions.keep_going\")), {})", "render_path": [ { "type": "controller", "class": "Idv::CancellationsController", "method": "new", - "line": 13, + "line": 16, "file": "app/controllers/idv/cancellations_controller.rb", "rendered": { "name": "idv/cancellations/new", @@ -103,6 +103,6 @@ "note": "" } ], - "updated": "2023-11-02 09:34:28 -0400", - "brakeman_version": "6.0.1" + "updated": "2024-04-19 08:20:16 -0400", + "brakeman_version": "6.1.0" } diff --git a/spec/components/button_component_spec.rb b/spec/components/button_component_spec.rb index f448f220ce9..57bfc72d25a 100644 --- a/spec/components/button_component_spec.rb +++ b/spec/components/button_component_spec.rb @@ -131,4 +131,33 @@ ) end end + + context 'with url' do + let(:url) { '/' } + let(:options) { { url: } } + + it 'renders link to url' do + expect(rendered).to have_link(content, href: url) + end + + context 'with method' do + let(:method) { :put } + let(:options) { super().merge(method:) } + + it 'renders button to url' do + expect(rendered).to have_selector("form[action='#{url}']") + expect(rendered).to have_selector("input[name='_method'][value='#{method}']", visible: :all) + expect(rendered).to have_selector("button[type='submit']") + expect(rendered).to have_text(content) + end + + context 'with get method' do + let(:method) { :get } + + it 'renders link to url' do + expect(rendered).to have_link(content, href: url) + end + end + end + end end diff --git a/spec/views/users/backup_code_setup/edit.html.erb_spec.rb b/spec/views/users/backup_code_setup/edit.html.erb_spec.rb new file mode 100644 index 00000000000..dee4a74f66c --- /dev/null +++ b/spec/views/users/backup_code_setup/edit.html.erb_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +RSpec.describe 'users/backup_code_setup/edit.html.erb' do + subject(:rendered) { render } + + it 'has a link to confirm and proceed to setup' do + expect(rendered).to have_link( + t('account.index.backup_code_confirm_regenerate'), + href: backup_code_setup_path, + ) + end + + it 'has a link to cancel and return to account page' do + expect(rendered).to have_link(t('links.cancel'), href: account_path) + end +end