diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb
index 64d6ba155cd1474b378645d88a3b32f41c92171f..6e0ba748d85a8c60d6d048d9b57bf6116ff7820a 100644
--- a/app/helpers/button_helper.rb
+++ b/app/helpers/button_helper.rb
@@ -98,6 +98,68 @@ def dropdown_item_with_description(title, description, href: nil, data: nil, def
href: href,
data: data
end
+
+ # Creates a link that looks like a button.
+ #
+ # It renders a Pajamas::ButtonComponent.
+ #
+ # It has the same API as `link_to`, but with some additional options
+ # specific to button rendering.
+ #
+ # Examples:
+ # # Default button
+ # link_button_to _('Foo'), some_path
+ #
+ # # Default button using a block
+ # link_button_to some_path do
+ # _('Foo')
+ # end
+ #
+ # # Confirm variant
+ # link_button_to _('Foo'), some_path, variant: :confirm
+ #
+ # # With icon
+ # link_button_to _('Foo'), some_path, icon: 'pencil'
+ #
+ # # Icon-only
+ # # NOTE: The content must be `nil` in order to correctly render. Use aria-label
+ # # to ensure the link is accessible.
+ # link_button_to nil, some_path, icon: 'pencil', 'aria-label': _('Foo')
+ #
+ # # Small button
+ # link_button_to _('Foo'), some_path, size: :small
+ #
+ # # Secondary category danger button
+ # link_button_to _('Foo'), some_path, variant: :danger, category: :secondary
+ #
+ # For accessibility, ensure that icon-only links have aria-label set.
+ def link_button_to(name = nil, href = nil, options = nil, &block)
+ if block
+ options = href
+ href = name
+ end
+
+ options ||= {}
+
+ # Ignore args that don't make sense for links, like disabled, loading, etc.
+ options_for_button = %i[
+ category
+ variant
+ size
+ block
+ selected
+ icon
+ target
+ method
+ ]
+
+ args = options.slice(*options_for_button)
+ button_options = options.except(*options_for_button)
+
+ render Pajamas::ButtonComponent.new(href: href, **args, button_options: button_options) do
+ block.present? ? yield : name
+ end
+ end
end
ButtonHelper.prepend_mod_with('ButtonHelper')
diff --git a/app/views/admin/labels/_label.html.haml b/app/views/admin/labels/_label.html.haml
index f4f64eadf210e67d54349eff53217200367738d6..19460ddb0e5973d2d1ae4c3278aed8a1c0a585ed 100644
--- a/app/views/admin/labels/_label.html.haml
+++ b/app/views/admin/labels/_label.html.haml
@@ -10,8 +10,8 @@
.dropdown-menu.dropdown-menu-right
%ul
%li
- = link_to edit_admin_label_path(label), class: 'btn gl-btn label-action dropdown-item btn-link' do
+ = link_to edit_admin_label_path(label), class: 'btn label-action dropdown-item btn-link' do
= _('Edit')
%li
- = link_to admin_label_path(label), class: 'btn gl-btn js-remove-label dropdown-item btn-link gl-text-red-500!', data: { confirm: _('Are you sure you want to delete this label?'), confirm_btn_variant: 'danger' }, aria: { label: _('Delete label') }, method: :delete, remote: true do
+ = link_to admin_label_path(label), class: 'btn js-remove-label dropdown-item btn-link gl-text-red-500!', data: { confirm: _('Are you sure you want to delete this label?'), confirm_btn_variant: 'danger' }, aria: { label: _('Delete label') }, method: :delete, remote: true do
= _('Delete')
diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml
index 1f3e8f4bba289b37b7574f69bd766d1d69293c64..fa89c3d4b4f34d224a60e5dc55ee02717e548ed9 100644
--- a/app/views/admin/users/projects.html.haml
+++ b/app/views/admin/users/projects.html.haml
@@ -18,8 +18,7 @@
.float-right
%span.light.vertical-align-middle= group_member.human_access
- unless group_member.owner?
- = link_to group_group_member_path(group, group_member), data: { confirm: remove_member_message(group_member), confirm_btn_variant: 'danger', testid: 'remove-user' }, aria: { label: _('Remove') }, method: :delete, remote: true, class: "btn btn-sm btn-danger gl-button btn-icon gl-ml-3", title: _('Remove user from group') do
- = sprite_icon('remove', size: 16, css_class: 'gl-icon')
+ = link_button_to nil, group_group_member_path(group, group_member), data: { confirm: remove_member_message(group_member), confirm_btn_variant: 'danger', testid: 'remove-user' }, aria: { label: _('Remove') }, method: :delete, remote: true, class: 'gl-ml-3', title: _('Remove user from group'), variant: :danger, size: :small, icon: 'remove'
.row
.col-md-6
@@ -50,5 +49,4 @@
%span.light.vertical-align-middle= member.human_access
- if member.respond_to? :project
- = link_to project_project_member_path(project, member), data: { confirm: remove_member_message(member), confirm_btn_variant: 'danger' }, aria: { label: _('Remove') }, remote: true, method: :delete, class: "btn btn-sm btn-danger gl-button btn-icon gl-ml-3", title: _('Remove user from project') do
- = sprite_icon('remove', size: 16, css_class: 'gl-icon')
+ = link_button_to nil, project_project_member_path(project, member), data: { confirm: remove_member_message(member), confirm_btn_variant: 'danger' }, aria: { label: _('Remove') }, remote: true, method: :delete, class: 'gl-ml-3', title: _('Remove user from project'), variant: :danger, size: :small, icon: 'remove'
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index ea6525e1b96a9b526ae08bce9635e3d4565d9266..a1b0c6c612b332035051366f6c6aee6c813dfd2b 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -42,8 +42,7 @@
%span.light= _('Secondary email:')
%strong
= render partial: 'shared/email_with_badge', locals: { email: email.email, verified: email.confirmed? }
- = link_to remove_email_admin_user_path(@user, email), data: { confirm: _("Are you sure you want to remove %{email}?") % { email: email.email }, 'confirm-btn-variant': 'danger' }, method: :delete, class: "btn btn-sm btn-danger gl-button btn-icon float-right", title: _('Remove secondary email'), id: "remove_email_#{email.id}" do
- = sprite_icon('close', size: 16, css_class: 'gl-icon')
+ = link_button_to nil, remove_email_admin_user_path(@user, email), data: { confirm: _("Are you sure you want to remove %{email}?") % { email: email.email }, 'confirm-btn-variant': 'danger' }, method: :delete, class: 'float-right', title: _('Remove secondary email'), id: "remove_email_#{email.id}", variant: :danger, size: :small, icon: 'close'
%li
%span.light ID:
%strong{ data: { qa_selector: 'user_id_content' } }
diff --git a/app/views/profiles/active_sessions/_active_session.html.haml b/app/views/profiles/active_sessions/_active_session.html.haml
index 9ec8d694dac23562f1ea074c83ac795cb8b4e986..e91c28e6e84ddb8c994bc0aa3c0c99b33047061b 100644
--- a/app/views/profiles/active_sessions/_active_session.html.haml
+++ b/app/views/profiles/active_sessions/_active_session.html.haml
@@ -27,9 +27,5 @@
- unless is_current_session
.float-right
- = link_to(revoke_session_path(active_session),
- { data: { confirm: _('Are you sure? The device will be signed out of GitLab and all remember me tokens revoked.') },
- method: :delete,
- class: "gl-button btn btn-danger gl-ml-3" }) do
- %span.sr-only= _('Revoke')
+ = link_button_to revoke_session_path(active_session), data: { confirm: _('Are you sure? The device will be signed out of GitLab and all remember me tokens revoked.'), confirm_btn_variant: :danger }, method: :delete, class: 'gl-ml-3', variant: :danger, 'aria-label': _('Revoke') do
= _('Revoke')
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index c16f3c3b12b6e9937ac88355608397a9dab179d2..5686adaa3f5b70009138116dfa6f310edb507a3e 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -61,6 +61,4 @@
- confirm_title = "#{email.confirmation_sent_at ? _('Resend confirmation email') : _('Send confirmation email')}"
= link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'gl-button btn btn-sm btn-default'
- = link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'gl-button btn btn-sm btn-danger' do
- %span.sr-only= _('Remove')
- = sprite_icon('remove')
+ = link_button_to nil, profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, variant: :danger, size: :small, icon: 'remove', 'aria-label': _('Remove')
diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml
index d52b16814c03be34ffc58112ede18a8584799efd..d8b8dda29dce51673ca0e36fedb972314efbddae 100644
--- a/app/views/profiles/gpg_keys/_key.html.haml
+++ b/app/views/profiles/gpg_keys/_key.html.haml
@@ -19,9 +19,6 @@
.float-right
%span.key-created-at
= html_escape(s_('Profiles|Created %{time_ago}')) % { time_ago: time_ago_with_tooltip(key.created_at) }
- = link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-icon btn-danger gl-ml-3" do
- %span.sr-only= _('Remove')
- = sprite_icon('remove')
- = link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "gl-button btn btn-danger gl-ml-3" do
- %span.sr-only= _('Revoke')
+ = link_button_to nil, profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: 'gl-ml-3', variant: :danger, icon: 'remove', 'aria-label': _('Remove')
+ = link_button_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: 'gl-ml-3', variant: :danger, 'aria-label': _('Revoke') do
= _('Revoke')
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index 118f6fb129682bc65ceadf1cb388f52b8136058c..00da6c73081cf497a29e6019a39ccdc6646be498 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -3,8 +3,7 @@
.nav-block.d-none.d-sm-flex.activities.gl-static
= render 'shared/event_filter'
.controls.gl-display-flex
- = link_to project_path(@project, rss_url_options), title: s_("ProjectActivityRSS|Subscribe"), class: 'btn gl-button btn-default btn-icon d-none d-sm-inline-flex has-tooltip' do
- = sprite_icon('rss', css_class: 'gl-icon')
+ = link_button_to nil, project_path(@project, rss_url_options), title: s_("ProjectActivityRSS|Subscribe"), class: 'd-none d-sm-inline-flex has-tooltip', icon: 'rss'
- if is_project_overview && can?(current_user, :download_code, @project)
.project-clone-holder.d-none.d-md-inline-flex.gl-ml-2
= render "projects/buttons/clone", dropdown_class: 'dropdown-menu-right'
diff --git a/app/views/projects/_find_file_link.html.haml b/app/views/projects/_find_file_link.html.haml
index a4bf72edf1225186f9a37c502b2981c5dba4f2a4..4ad2c339bcc1d633ebe56d343099c83862c298e2 100644
--- a/app/views/projects/_find_file_link.html.haml
+++ b/app/views/projects/_find_file_link.html.haml
@@ -1,2 +1,2 @@
-= link_to project_find_file_path(@project, @ref), class: 'gl-button btn btn-default shortcuts-find-file', rel: 'nofollow' do
+= link_button_to project_find_file_path(@project, @ref), class: 'shortcuts-find-file', rel: 'nofollow' do
= _('Find file')
diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml
index 947a1007fd513b36dfcbf1cb09b4ca06d5e75db5..6315c6dc52d7e0c213d2c5beaf16ed7de7192a56 100644
--- a/app/views/projects/_import_project_pane.html.haml
+++ b/app/views/projects/_import_project_pane.html.haml
@@ -43,9 +43,7 @@
- if gitea_import_enabled?
%div
- = link_to new_import_gitea_path(namespace_id: namespace_id), class: 'gl-button btn-default btn import_gitea js-import-project-btn', data: { platform: 'gitea', **tracking_attrs_data(track_label, 'click_button', 'gitea') } do
- .gl-button-icon
- = custom_icon('gitea_logo')
+ = render Pajamas::ButtonComponent.new(href: new_import_gitea_path(namespace_id: namespace_id), icon: 'gitea', button_options: { class: 'import_gitea js-import-project-btn', data: { platform: 'gitea', **tracking_attrs_data(track_label, 'click_button', 'gitea') } }) do
Gitea
- if git_import_enabled?
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index ccda06c7e4cbe2cfc4a0ba6b8ad090ff97b98795..ebeeaed7ae9b2db8ded9b35e6b84353cd64b325b 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -18,10 +18,8 @@
= link_to truncate(title, length: 40), browse_project_job_artifacts_path(@project, @build, path)
.tree-controls<
- = link_to download_project_job_artifacts_path(@project, @build),
- rel: 'nofollow', download: '', class: 'gl-button btn btn-default download' do
- = sprite_icon('download', css_class: 'gl-mr-2')
- Download artifacts archive
+ = link_button_to download_project_job_artifacts_path(@project, @build), rel: 'nofollow', download: '', class: 'download', icon: 'download' do
+ = _('Download artifacts archive')
.tree-content-holder
%table.table.tree-table
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 3e98383f13ecd6dc79a2ac6a81cb737bed6164ab..c03de6646cf4be928a49444262b0e8b679e576e2 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -23,11 +23,11 @@
}
- if can_view_branch_rules?
- = link_to project_settings_repository_path(@project, anchor: 'js-branch-rules'), class: 'gl-button btn btn-default' do
+ = link_button_to project_settings_repository_path(@project, anchor: 'js-branch-rules') do
= s_('Branches|View branch rules')
- if can_push_code?
- = link_to new_project_branch_path(@project), class: 'gl-button btn btn-confirm' do
+ = link_button_to new_project_branch_path(@project), variant: :confirm do
= s_('Branches|New branch')
.js-delete-merged-branches.gl-w-7{ data: {
default_branch: @project.repository.root_ref,
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 6d05f1dc955e63568d97e40acd82f35f868d616e..c9dcfaff8c6b8d607756ce0386fff9e7e92fa1c6 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -2,17 +2,15 @@
- if current_user
.count-badge.btn-group
- if current_user.already_forked?(@project) && current_user.forkable_namespaces.size < 2
- = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'gl-button btn btn-default has-tooltip fork-btn' do
- = sprite_icon('fork', css_class: 'icon')
- %span= s_('ProjectOverview|Fork')
+ = link_button_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'has-tooltip fork-btn', icon: 'fork' do
+ = s_('ProjectOverview|Fork')
- else
- disabled_tooltip = fork_button_disabled_tooltip(@project)
- count_class = 'disabled' unless can?(current_user, :read_code, @project)
- button_class = 'disabled' if disabled_tooltip
%span.btn-group{ class: ('has-tooltip' if disabled_tooltip), title: disabled_tooltip }
- = link_to new_project_fork_path(@project), class: "gl-button btn btn-default fork-btn #{button_class}", data: { qa_selector: 'fork_button' } do
- = sprite_icon('fork', css_class: 'icon')
- %span= s_('ProjectOverview|Fork')
- = link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Forks'), s_('ProjectOverview|Forks'), @project.forks_count), class: "gl-button btn btn-default count has-tooltip fork-count #{count_class}" do
+ = link_button_to new_project_fork_path(@project), class: "fork-btn #{button_class}", data: { qa_selector: 'fork_button' }, icon: 'fork' do
+ = s_('ProjectOverview|Fork')
+ = link_button_to project_forks_path(@project), title: n_(s_('ProjectOverview|Forks'), s_('ProjectOverview|Forks'), @project.forks_count), class: "count has-tooltip fork-count #{count_class}" do
= @project.forks_count
diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml
index d4dcfbdff5419ef6068c7c3eca2ebef4e00a7ff2..35318f68f572e319329a3cdc91a376680d6cc73c 100644
--- a/app/views/projects/buttons/_star.html.haml
+++ b/app/views/projects/buttons/_star.html.haml
@@ -6,12 +6,11 @@
.count-badge.d-inline-flex.align-item-stretch.btn-group
= render Pajamas::ButtonComponent.new(size: :medium, icon: icon, button_text_classes: button_text_classes, button_options: { class: 'star-btn toggle-star', data: { endpoint: toggle_star_project_path(@project, :json) } }) do
- button_text
- = link_to project_starrers_path(@project), title: n_(s_('ProjectOverview|Starrer'), s_('ProjectOverview|Starrers'), @project.star_count), class: 'gl-button btn btn-default has-tooltip star-count count' do
+ = link_button_to project_starrers_path(@project), title: n_(s_('ProjectOverview|Starrer'), s_('ProjectOverview|Starrers'), @project.star_count), class: 'has-tooltip star-count count' do
= @project.star_count
- else
.count-badge.d-inline-flex.align-item-stretch.btn-group
- = link_to new_user_session_path, class: 'gl-button btn btn-default has-tooltip star-btn', title: s_('ProjectOverview|You must sign in to star a project') do
- = sprite_icon('star-o', css_class: 'icon')
- %span= s_('ProjectOverview|Star')
- = link_to project_starrers_path(@project), title: n_(s_('ProjectOverview|Starrer'), s_('ProjectOverview|Starrers'), @project.star_count), class: 'gl-button btn btn-default has-tooltip star-count count' do
+ = link_button_to new_user_session_path, class: 'has-tooltip star-btn', title: s_('ProjectOverview|You must sign in to star a project'), icon: 'star-o' do
+ = s_('ProjectOverview|Star')
+ = link_button_to project_starrers_path(@project), title: n_(s_('ProjectOverview|Starrer'), s_('ProjectOverview|Starrers'), @project.star_count), class: 'has-tooltip star-count count' do
= @project.star_count
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index ecdd43a54f9f3310978e29812b2e5fba8f7c1926..4017db459a9bf63ddc94761df745d3ad5e1930b5 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -103,33 +103,28 @@
.gl-text-right
.btn-group
- if can?(current_user, :read_job_artifacts, job) && job.artifacts?
- = link_to download_project_job_artifacts_path(job.project, job), rel: 'nofollow', download: '', title: _('Download artifacts'), class: 'gl-button btn btn-default btn-icon' do
- = sprite_icon('download', css_class: 'gl-icon')
+ = link_button_to nil, download_project_job_artifacts_path(job.project, job), rel: 'nofollow', download: '', title: _('Download artifacts'), icon: 'download'
- if can?(current_user, :update_build, job)
- if job.active?
- = link_to cancel_project_job_path(job.project, job, continue: { to: request.fullpath }), method: :post, title: _('Cancel'), class: 'gl-button btn btn-default btn-icon' do
- = sprite_icon('cancel', css_class: 'gl-icon')
+ = link_button_to nil, cancel_project_job_path(job.project, job, continue: { to: request.fullpath }), method: :post, title: _('Cancel'), icon: 'cancel'
- elsif job.scheduled?
- .gl-button.btn.btn-default.btn-icon.disabled{ disabled: true }
- = sprite_icon('planning', css_class: 'gl-icon')
+ = render Pajamas::ButtonComponent.new(disabled: true, icon: 'planning') do
%time.js-remaining-time{ datetime: job.scheduled_at.utc.iso8601 }
= duration_in_numbers(job.execute_in)
- confirmation_message = s_("DelayedJobs|Are you sure you want to run %{job_name} immediately? This job will run automatically after it's timer finishes.") % { job_name: job.name }
- = link_to play_project_job_path(job.project, job, return_to: request.original_url),
+ = link_button_to nil, play_project_job_path(job.project, job, return_to: request.original_url),
method: :post,
title: s_('DelayedJobs|Start now'),
- class: 'gl-button btn btn-default btn-icon has-tooltip',
- data: { confirm: confirmation_message } do
- = sprite_icon('play', css_class: 'gl-icon')
- = link_to unschedule_project_job_path(job.project, job, return_to: request.original_url),
+ class: 'has-tooltip',
+ data: { confirm: confirmation_message },
+ icon: 'play'
+ = link_button_to nil, unschedule_project_job_path(job.project, job, return_to: request.original_url),
method: :post,
title: s_('DelayedJobs|Unschedule'),
- class: 'gl-button btn btn-default btn-icon has-tooltip' do
- = sprite_icon('time-out', css_class: 'gl-icon')
+ class: 'has-tooltip',
+ icon: 'time-out'
- elsif allow_retry
- if job.playable? && !admin && can?(current_user, :update_build, job)
- = link_to play_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Play'), class: 'gl-button btn btn-default btn-icon' do
- = sprite_icon('play', css_class: 'gl-icon')
+ = link_button_to nil, play_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Play'), icon: 'play'
- elsif job.retryable?
- = link_to retry_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Retry'), class: 'gl-button btn btn-default btn-icon' do
- = sprite_icon('retry', css_class: 'gl-icon')
+ = link_button_to nil, retry_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Retry'), icon: 'retry'
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 4c5a9acdf83532458d3cc334917d6f4718d5cbde..8afc9ade3e14c52b15f2c601b42f5736d22cc6f5 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -18,7 +18,7 @@
.tree-controls
- if @merge_request.present?
.control.d-none.d-md-block
- = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn gl-button'
+ = link_button_to _("View open merge request"), project_merge_request_path(@project, @merge_request)
- elsif create_mr_button?(from: @ref, source_project: @project)
.control.d-none.d-md-block
= render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path(from: @ref, source_project: @project)) do
@@ -28,8 +28,7 @@
= form_tag(project_commits_path(@project, @id, ref_type: @ref_type), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path(ref_type: @ref_type)}) do
= search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control gl-form-input input-short gl-mt-3 gl-sm-mt-0 gl-min-w-full', spellcheck: false }
.control.d-none.d-md-block
- = link_to project_commits_path(@project, @id, rss_url_options), title: _("Commits feed"), class: 'btn gl-button btn-default btn-icon' do
- = sprite_icon('rss')
+ = link_button_to nil, project_commits_path(@project, @id, rss_url_options), title: _("Commits feed"), icon: 'rss'
= render_if_exists 'projects/commits/mirror_status'
diff --git a/app/views/projects/confluences/show.html.haml b/app/views/projects/confluences/show.html.haml
index 6fec9b501ea6b914d5fbc3be65244e4e1573cf62..283408ffa63a80af7a5544d1c4fc30828038c8fe 100644
--- a/app/views/projects/confluences/show.html.haml
+++ b/app/views/projects/confluences/show.html.haml
@@ -8,6 +8,6 @@
- wiki_confluence_epic_link_url = 'https://gitlab.com/groups/gitlab-org/-/epics/3629'
- wiki_confluence_epic_link_start = ''.html_safe % { url: wiki_confluence_epic_link_url }
= html_escape(s_("WikiEmpty|You've enabled the Confluence Workspace integration. Your wiki will be viewable directly within Confluence. We are hard at work integrating Confluence more seamlessly into GitLab. If you'd like to stay up to date, follow our %{wiki_confluence_epic_link_start}Confluence epic%{wiki_confluence_epic_link_end}.")) % { wiki_confluence_epic_link_start: wiki_confluence_epic_link_start, wiki_confluence_epic_link_end: ''.html_safe }
- = link_to @project.confluence_integration.confluence_url, target: '_blank', rel: 'noopener noreferrer', class: 'gl-button btn btn-confirm external-url', title: s_('WikiEmpty|Go to Confluence') do
+ = link_button_to @project.confluence_integration.confluence_url, target: '_blank', rel: 'noopener noreferrer', class: 'external-url', title: s_('WikiEmpty|Go to Confluence'), variant: :confirm do
= s_('WikiEmpty|Go to Confluence')
= sprite_icon('external-link')
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 5ec95c3095da0893ab73514406ef1cbc46c1854e..3db1467df60f4ebaa49eea5894b55fd3cad6d801 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -18,9 +18,7 @@
#js-diff-stats{ data: diff_file_stats_data(diff_file) }
- if diff_file.blob&.readable_text?
- unless @diff_notes_disabled
- %span.has-tooltip{ title: _("Toggle comments for this file") }
- = link_to '#', class: 'js-toggle-diff-comments btn gl-button btn-default btn-icon selected' do
- = sprite_icon('comment')
+ = link_button_to nil, '#', class: 'js-toggle-diff-comments has-tooltip', icon: 'comment', title: _("Toggle comments for this file")
\
- if editable_diff?(diff_file)
- link_opts = @merge_request.persisted? ? { from_merge_request_iid: @merge_request.iid } : {}
diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml
index 7c837d4ded0685527063d00b7cae9a87df0a5078..c2ad91918002b26047a341d6cb3bb198df4ed91a 100644
--- a/app/views/projects/environments/terminal.html.haml
+++ b/app/views/projects/environments/terminal.html.haml
@@ -13,8 +13,7 @@
.col-sm-6
.nav-controls
- if @environment.external_url.present?
- = link_to @environment.external_url, class: 'gl-button btn btn-default', target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('external-link')
+ = link_button_to nil, @environment.external_url, target: '_blank', rel: 'noopener noreferrer nofollow', icon: 'external-link'
= render 'projects/deployments/actions', deployment: @environment.last_deployment
.terminal-container{ class: container_class }
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index d28ee30b6f9556d7662c77f469a6911ff26116e5..49047749b71e31eef967ffcab492cf25248c423d 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -20,12 +20,10 @@
- if current_user && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.forkable_namespaces.size < 2
- = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn gl-button btn-confirm gl-md-ml-3' do
- = sprite_icon('fork', size: 12)
- %span= _('Fork')
+ = link_button_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'gl-md-ml-3', variant: :confirm, icon: 'fork' do
+ = _('Fork')
- else
- = link_to new_project_fork_path(@project), title: _("Fork project"), class: 'btn gl-button btn-confirm gl-md-ml-3 gl-mt-3 gl-md-mt-0' do
- = sprite_icon('fork', size: 12)
- %span= _('Fork')
+ = link_button_to new_project_fork_path(@project), title: _("Fork project"), class: 'gl-md-ml-3 gl-mt-3 gl-md-mt-0', variant: :confirm, icon: 'fork' do
+ = _('Fork')
= render 'projects', projects: @forks
diff --git a/app/views/projects/integrations/shimos/show.html.haml b/app/views/projects/integrations/shimos/show.html.haml
index 92b9e03d5bda216fcdd96a6d72d0b5bf76c6b34c..e6cd8c15809ada69e6ebd7760f344ce5c9f48320 100644
--- a/app/views/projects/integrations/shimos/show.html.haml
+++ b/app/views/projects/integrations/shimos/show.html.haml
@@ -6,5 +6,5 @@
= s_('Shimo|Shimo Workspace integration is enabled')
%p
= s_("Shimo|You've enabled the Shimo Workspace integration. You can view your wiki directly in Shimo.")
- = link_to @project.shimo_integration.external_wiki_url, target: '_blank', rel: 'noopener noreferrer', class: 'gl-button btn btn-confirm', title: s_('Shimo|Go to Shimo Workspace') do
+ = link_button_to @project.shimo_integration.external_wiki_url, target: '_blank', rel: 'noopener noreferrer', title: s_('Shimo|Go to Shimo Workspace'), variant: :confirm do
= s_('Shimo|Go to Shimo Workspace')
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 326a7c4027f049372a146ebc9f5b566483c13945..a7a21ef0440b391da09dd2e4a3764afacbd47854 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -9,14 +9,14 @@
= render 'shared/milestones/search_form'
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @project)
- = link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm gl-ml-3', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
+ = link_button_to new_project_milestone_path(@project), class: 'gl-ml-3', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone'), variant: :confirm do
= _('New milestone')
- if @milestones.blank?
= render 'shared/empty_states/milestones_tab' do
- if can?(current_user, :admin_milestone, @project)
.text-center
- = link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
+ = link_button_to new_project_milestone_path(@project), data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone'), variant: :confirm do
= _('New milestone')
- else
@@ -32,5 +32,5 @@
= render 'shared/empty_states/milestones' do
- if can?(current_user, :admin_milestone, @project)
.text-center
- = link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
+ = link_button_to new_project_milestone_path(@project), data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone'), variant: :confirm do
= _('New milestone')
diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml
index e3f46d601a382d4a0e403c1de13c0cd165c65faa..5cc909741f6aa8d09318b3a4199855d69b7af5ea 100644
--- a/app/views/projects/no_repo.html.haml
+++ b/app/views/projects/no_repo.html.haml
@@ -13,13 +13,13 @@
%hr
.no-repo-actions
- = link_to project_repository_path(@project), method: :post, class: 'btn gl-button btn-confirm' do
- #{ _('Create empty repository') }
+ = link_button_to project_repository_path(@project), method: :post, variant: :confirm do
+ = _('Create empty repository')
%strong.gl-ml-3.gl-mr-3 or
- = link_to new_project_import_path(@project), class: 'btn gl-button btn-default' do
- #{ _('Import repository') }
+ = link_button_to new_project_import_path(@project) do
+ = _('Import repository')
- if can? current_user, :remove_project, @project
.prepend-top-20
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
index 37b2b3ecfdeb296c4b1238b089621cec29010455..a050808f13c819dfa5eb0f0f0fb300e08c1ced6e 100644
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
@@ -35,14 +35,11 @@
%td{ role: 'cell', data: { label: _('Actions') } }
.float-right.btn-group
- if can?(current_user, :play_pipeline_schedule, pipeline_schedule)
- = link_to play_pipeline_schedule_path(pipeline_schedule), method: :post, title: _('Play'), class: 'btn gl-button btn-default btn-icon' do
- = sprite_icon('play')
+ = link_button_to nil, play_pipeline_schedule_path(pipeline_schedule), method: :post, title: _('Play'), icon: 'play'
- if can?(current_user, :admin_pipeline_schedule, pipeline_schedule) && pipeline_schedule.owner != current_user
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-take-ownership-button has-tooltip', title: s_('PipelineSchedule|Take ownership to edit'), data: { url: take_ownership_pipeline_schedule_path(pipeline_schedule) } }) do
= s_('PipelineSchedules|Take ownership')
- if can?(current_user, :update_pipeline_schedule, pipeline_schedule)
- = link_to edit_pipeline_schedule_path(pipeline_schedule), title: _('Edit'), class: 'btn gl-button btn-default btn-icon' do
- = sprite_icon('pencil')
+ = link_button_to nil, edit_pipeline_schedule_path(pipeline_schedule), title: _('Edit'), icon: 'pencil'
- if can?(current_user, :admin_pipeline_schedule, pipeline_schedule)
- = link_to pipeline_schedule_path(pipeline_schedule), title: _('Delete'), method: :delete, class: 'btn gl-button btn-danger btn-icon', aria: { label: _('Delete pipeline schedule') }, data: { confirm: _("Are you sure you want to delete this pipeline schedule?"), confirm_btn_variant: 'danger' } do
- = sprite_icon('remove')
+ = link_button_to nil, pipeline_schedule_path(pipeline_schedule), title: _('Delete'), method: :delete, aria: { label: _('Delete pipeline schedule') }, data: { confirm: _("Are you sure you want to delete this pipeline schedule?"), confirm_btn_variant: 'danger' }, variant: :danger, icon: 'remove'
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index f2cefa402672a3612c986340d25a3ed47d03377a..88a60b1fb068031c94f7920e3a77b3101741d5e2 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -14,8 +14,8 @@
- if can?(current_user, :create_pipeline_schedule, @project)
.nav-controls
- = link_to new_project_pipeline_schedule_path(@project), class: 'btn gl-button btn-confirm' do
- %span= _('New schedule')
+ = link_button_to new_project_pipeline_schedule_path(@project), variant: :confirm do
+ = _('New schedule')
- if @schedules.present?
%ul.content-list
diff --git a/app/views/projects/runners/_group_runners.html.haml b/app/views/projects/runners/_group_runners.html.haml
index d71bcd12e64751612f11efec3bb54c986c337dd6..32a2e36c779e703413225adb5d88c7d4cca00f83 100644
--- a/app/views/projects/runners/_group_runners.html.haml
+++ b/app/views/projects/runners/_group_runners.html.haml
@@ -13,10 +13,10 @@
%br
%br
- if @project.group_runners_enabled?
- = link_to toggle_group_runners_project_runners_path(@project), class: 'btn gl-button btn-default', method: :post do
+ = link_button_to toggle_group_runners_project_runners_path(@project), method: :post do
= _('Disable group runners')
- else
- = link_to toggle_group_runners_project_runners_path(@project), class: 'btn gl-button btn-confirm-secondary', method: :post do
+ = link_button_to toggle_group_runners_project_runners_path(@project), method: :post, variant: :confirm, category: :secondary do
= _('Enable group runners')
= _('for this project')
diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml
index e517b37aae951cf44478ee4cd13cd3d014b34046..6d60370d2e05d916cec5b6330d15cb44a7d36e52 100644
--- a/app/views/projects/runners/_runner.html.haml
+++ b/app/views/projects/runners/_runner.html.haml
@@ -13,14 +13,11 @@
.gl-ml-2
.btn-group.btn-group-sm
- if @project_runners.include?(runner)
- = link_to edit_project_runner_path(@project, runner), class: 'btn gl-button btn-icon', title: _('Edit'), aria: { label: _('Edit') }, data: { testid: 'edit-runner-link', toggle: 'tooltip', placement: 'top', container: 'body' } do
- = sprite_icon('pencil')
+ = link_button_to nil, edit_project_runner_path(@project, runner), title: _('Edit'), aria: { label: _('Edit') }, data: { testid: 'edit-runner-link', toggle: 'tooltip', placement: 'top', container: 'body' }, icon: 'pencil'
- if runner.active?
- = link_to pause_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: s_('Runners|Pause from accepting jobs'), aria: { label: _('Pause') }, data: { toggle: 'tooltip', container: 'body', confirm: _("Are you sure?") } do
- = sprite_icon('pause')
+ = link_button_to nil, pause_project_runner_path(@project, runner), method: :post, title: s_('Runners|Pause from accepting jobs'), aria: { label: _('Pause') }, data: { toggle: 'tooltip', container: 'body', confirm: _("Are you sure?") }, icon: 'pause'
- else
- = link_to resume_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: s_('Runners|Resume accepting jobs'), aria: { label: _('Resume') }, data: { toggle: 'tooltip', container: 'body' } do
- = sprite_icon('play')
+ = link_button_to nil, resume_project_runner_path(@project, runner), method: :post, title: s_('Runners|Resume accepting jobs'), aria: { label: _('Resume') }, data: { toggle: 'tooltip', container: 'body' }, icon: 'play'
- if runner.belongs_to_one_project?
= link_to _('Remove runner'), project_runner_path(@project, runner), aria: { label: _('Remove') }, data: { confirm: _("Are you sure?"), 'confirm-btn-variant': 'danger' }, method: :delete, class: 'btn gl-button btn-danger'
- else
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index fda797f3228cae43900d63589c29dbcb6eaa65dd..b0be748eb366254449c2e5717eb86ec23dda161f 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -9,10 +9,9 @@
.nav-controls
#js-tags-sort-dropdown{ data: { filter_tags_path: filter_tags_path(search: @search, sort: @sort), sort_options: tags_sort_options_hash.to_json } }
- = link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn gl-button btn-default btn-icon has-tooltip gl-ml-auto' do
- = sprite_icon('rss', css_class: 'gl-icon')
+ = link_button_to nil, project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'has-tooltip gl-ml-auto', icon: 'rss'
- if can?(current_user, :admin_tag, @project)
- = link_to new_project_tag_path(@project), class: 'btn gl-button btn-confirm', data: { qa_selector: "new_tag_button" } do
+ = link_button_to new_project_tag_path(@project), data: { qa_selector: "new_tag_button" }, variant: :confirm do
= s_('TagsPage|New tag')
= render_if_exists 'projects/commits/mirror_status'
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 5127972c40673fee3528d483bdd8d7d238599f73..1649e56043e81d5ad71d08bca2251113bf70399c 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -45,10 +45,8 @@
= render partial: 'projects/commit/signature', object: @tag.signature
- if can?(current_user, :admin_tag, @project)
= render 'edit_release_button', tag: @tag, project: @project, release: @release
- = link_to project_tree_path(@project, @tag.name), class: 'btn btn-icon gl-button btn-default has-tooltip', title: s_('TagsPage|Browse files') do
- = sprite_icon('folder-open', css_class: 'gl-icon')
- = link_to project_commits_path(@project, @tag.name), class: 'btn btn-icon gl-button btn-default has-tooltip', title: s_('TagsPage|Browse commits') do
- = sprite_icon('history', css_class: 'gl-icon')
+ = link_button_to nil, project_tree_path(@project, @tag.name), class: 'has-tooltip', title: s_('TagsPage|Browse files'), icon: 'folder-open'
+ = link_button_to nil, project_commits_path(@project, @tag.name), class: 'has-tooltip', title: s_('TagsPage|Browse commits'), icon: 'history'
= render 'projects/buttons/download', project: @project, ref: @tag.name
- if can?(current_user, :admin_tag, @project)
= render 'projects/buttons/remove_tag', project: @project, tag: @tag
diff --git a/app/views/shared/_remote_mirror_update_button.html.haml b/app/views/shared/_remote_mirror_update_button.html.haml
index bc80ebe39506fca60e956b74bc109064c9808503..fa5c862b768a37b4cb9a3e77ebae0b64b7f0ad35 100644
--- a/app/views/shared/_remote_mirror_update_button.html.haml
+++ b/app/views/shared/_remote_mirror_update_button.html.haml
@@ -3,5 +3,4 @@
button_options: { class: 'disabled', title: _('Updating'), data: { toggle: 'tooltip', container: 'body' } },
icon_classes: 'spin')
- elsif remote_mirror.enabled?
- = link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn btn-icon gl-button rspec-update-now-button", data: { toggle: 'tooltip', container: 'body', qa_selector: 'update_now_button' }, title: _('Update now') do
- = sprite_icon("retry")
+ = link_button_to nil, update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: 'rspec-update-now-button', data: { toggle: 'tooltip', container: 'body', qa_selector: 'update_now_button' }, title: _('Update now'), icon: 'retry'
diff --git a/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml b/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml
index 290152d5803372ff23f18cd8140618bb36c0ded0..e372dbd983ce923312fa90b8599101a60007b672 100644
--- a/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml
+++ b/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml
@@ -8,5 +8,5 @@
= s_('Profiles|Ensure you have two-factor authentication recovery codes stored in a safe place.')
= link_to _('Learn more.'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'recovery-codes'), target: '_blank', rel: 'noopener noreferrer'
- c.with_actions do
- = link_to profile_two_factor_auth_path, class: 'deferred-link btn gl-alert-action btn-confirm btn-md gl-button' do
+ = link_button_to profile_two_factor_auth_path, class: 'deferred-link gl-alert-action', variant: :confirm do
= s_('Profiles|Manage two-factor authentication')
diff --git a/app/views/shared/doorkeeper/applications/_index.html.haml b/app/views/shared/doorkeeper/applications/_index.html.haml
index cffe645d698e9720b5856f9dfcebeac39333e7d9..31407c60e845b772429e0115873557df6bc09652 100644
--- a/app/views/shared/doorkeeper/applications/_index.html.haml
+++ b/app/views/shared/doorkeeper/applications/_index.html.haml
@@ -43,10 +43,7 @@
%div= uri
%td= application.access_tokens.count
%td.gl-display-flex
- = link_to edit_application_url.call(application), class: "gl-button btn btn-default btn-icon gl-mr-3" do
- %span.sr-only
- = _('Edit')
- = sprite_icon('pencil')
+ = link_button_to nil, edit_application_url.call(application), class: 'gl-mr-3', icon: 'pencil', 'aria-label': _('Edit')
= render 'shared/doorkeeper/applications/delete_form', path: application_url.call(application), small: true
- else
.settings-message
diff --git a/app/views/shared/integrations/gitlab_slack_application/_slack_button.html.haml b/app/views/shared/integrations/gitlab_slack_application/_slack_button.html.haml
index b22a6eeca908e261b96a152d3c139524903bdb7d..1ec669d5745fbf1cf9277026198d992b0040053a 100644
--- a/app/views/shared/integrations/gitlab_slack_application/_slack_button.html.haml
+++ b/app/views/shared/integrations/gitlab_slack_application/_slack_button.html.haml
@@ -1,4 +1,4 @@
-= link_to add_to_slack_link(project, slack_app_id), class: 'btn btn-default gl-button gl-pr-6!' do
+= link_button_to add_to_slack_link(project, slack_app_id), class: 'gl-pr-6!' do
= image_tag 'illustrations/slack_logo.svg', class: 'gl-icon gl-button-icon gl-w-9! gl-h-9! gl-my-n3! gl-mr-0!'
%strong.gl-button-text
= label
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index b8f98c285745cd16a06efea825a1ab772d2a2f06..d590c859945d27246ade86b225c39cfb03429571 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -34,7 +34,7 @@
#js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item{ data: {hint: "#{'{{hint}}'}", tag: "#{'{{tag}}'}", action: "#{'{{hint === \'search\' ? \'submit\' : \'\' }}'}" } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
-# Encapsulate static class name `{{icon}}` inside #{} to bypass
-# haml lint's ClassAttributeWithStaticValue
%svg
@@ -44,7 +44,7 @@
#js-dropdown-operator.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dropdown: true, dynamic: true } }
%li.filter-dropdown-item{ data: { value: "{{ title }}" } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
{{ title }}
%span.btn-helptext
{{ help }}
@@ -60,10 +60,10 @@
#js-dropdown-assignee.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Any')
%li.divider.droplab-item-ignore
- if current_user
@@ -76,10 +76,10 @@
#js-dropdown-reviewer.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Any')
%li.divider.droplab-item-ignore
- if current_user
@@ -94,101 +94,101 @@
#js-dropdown-milestone.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Any')
%li.filter-dropdown-item{ data: { value: 'Upcoming' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Upcoming')
%li.filter-dropdown-item{ data: { value: 'Started' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Started')
%li.divider.droplab-item-ignore
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.gl-button.btn.btn-link.js-data-value{ type: 'button' }
+ %button.btn.btn-link.js-data-value{ type: 'button' }
{{title}}
= render_if_exists 'shared/issuable/filter_iteration', type: type
#js-dropdown-release.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Any')
%li.divider.droplab-item-ignore
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.gl-button.btn.btn-link.js-data-value{ type: 'button' }
+ %button.btn.btn-link.js-data-value{ type: 'button' }
{{title}}
#js-dropdown-label.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Any')
%li.divider.droplab-item-ignore
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
%span.dropdown-label-box{ style: 'background: {{color}}' }
%span.label-title.js-data-value
{{title}}
#js-dropdown-my-reaction.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Any')
%li.divider.droplab-item-ignore
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
%gl-emoji
%span.js-data-value.gl-ml-3
{{name}}
#js-dropdown-wip.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Yes')
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('No')
- if ::Feature.enabled?(:mr_approved_filter, type: :ops)
#js-dropdown-approved.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Yes')
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('No')
#js-dropdown-confidential.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('Yes')
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
- %button.gl-button.btn.btn-link{ type: 'button' }
+ %button.btn.btn-link{ type: 'button' }
= _('No')
- unless disable_target_branch
#js-dropdown-target-branch.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.gl-button.btn.btn-link.js-data-value.monospace
+ %button.btn.btn-link.js-data-value.monospace
{{title}}
#js-dropdown-environment.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.gl-button.btn.btn-link.js-data-value{ type: 'button' }
+ %button.btn.btn-link.js-data-value{ type: 'button' }
{{title}}
= render_if_exists 'shared/issuable/filter_weight', type: type
diff --git a/app/views/shared/members/_manage_access_button.html.haml b/app/views/shared/members/_manage_access_button.html.haml
index c88198ec3809fcc788923bc8a885e34953563cf3..910d62d4dc42b50606dae1b5dfcf78f834caa674 100644
--- a/app/views/shared/members/_manage_access_button.html.haml
+++ b/app/views/shared/members/_manage_access_button.html.haml
@@ -1,7 +1,5 @@
- path = local_assigns.fetch(:path, nil)
.gl-float-right
- = link_to path, class: 'btn btn-default btn-sm gl-button' do
- = sprite_icon('pencil', css_class: 'gl-icon gl-button-icon')
- %span.gl-button-text
- = _('Manage access')
+ = link_button_to path, size: :small, icon: 'pencil' do
+ = _('Manage access')
diff --git a/app/views/shared/milestones/_labels_tab.html.haml b/app/views/shared/milestones/_labels_tab.html.haml
index d2bee57992deb2c11155e2dd840faea45781eeba..1e856bf435519c555a979af8f1dcbc5ece5f2bb6 100644
--- a/app/views/shared/milestones/_labels_tab.html.haml
+++ b/app/views/shared/milestones/_labels_tab.html.haml
@@ -8,7 +8,7 @@
= markdown_field(label, :description)
.float-right.d-none.d-lg-block
- = link_to milestones_issues_path(options.merge(state: 'opened')), class: 'btn gl-button btn-default-tertiary' do
- - pluralize milestone_issues_by_label_count(@milestone, label, state: :opened), _('open issue')
- = link_to milestones_issues_path(options.merge(state: 'closed')), class: 'btn gl-button btn-default-tertiary' do
- - pluralize milestone_issues_by_label_count(@milestone, label, state: :closed), _('closed issue')
+ = link_button_to milestones_issues_path(options.merge(state: 'opened')), category: :tertiary do
+ = n_('open issue', 'open issues', milestone_issues_by_label_count(@milestone, label, state: :opened))
+ = link_button_to milestones_issues_path(options.merge(state: 'closed')), category: :tertiary do
+ = n_('closed issue', 'closed issues', milestone_issues_by_label_count(@milestone, label, state: :closed))
diff --git a/app/views/shared/projects/_search_form.html.haml b/app/views/shared/projects/_search_form.html.haml
index 72709b3ed2fbe81db96d038fb2936f4b816ae079..2388bf2f0be0b27716d3764e5022f02b35f5e655 100644
--- a/app/views/shared/projects/_search_form.html.haml
+++ b/app/views/shared/projects/_search_form.html.haml
@@ -51,5 +51,5 @@
.gl-display-flex.gl-w-full.gl-md-w-auto{ class: 'gl-m-0!' }
.js-namespace-select{ data: { field_name: 'namespace_id', selected_id: namespace&.id, selected_text: selected_text, update_location: 'true' } }
- = link_to new_project_path, class: 'gl-button btn btn-confirm gl-display-inline gl-mb-0!' do
+ = link_button_to new_project_path, class: 'gl-display-inline gl-mb-0!', variant: :confirm do
= _('New Project')
diff --git a/app/views/shared/wikis/_main_links.html.haml b/app/views/shared/wikis/_main_links.html.haml
index c1fd8c48c602e50db009f7c741d85b4507463b93..41831c95198cde2fc07bdf422ee70fed9e9ddd14 100644
--- a/app/views/shared/wikis/_main_links.html.haml
+++ b/app/views/shared/wikis/_main_links.html.haml
@@ -1,6 +1,6 @@
- if @page&.persisted?
- = link_to wiki_page_path(@wiki, @page, action: :history), class: "btn gl-button btn-default", role: "button", data: { qa_selector: 'page_history_button' } do
+ = link_button_to wiki_page_path(@wiki, @page, action: :history), role: "button", data: { qa_selector: 'page_history_button' } do
= s_("Wiki|Page history")
- if can?(current_user, :create_wiki, @wiki.container)
- = link_to wiki_path(@wiki, action: :new), class: "btn gl-button btn-confirm-secondary", role: "button", data: { qa_selector: 'new_page_button' } do
+ = link_button_to wiki_path(@wiki, action: :new), role: "button", data: { qa_selector: 'new_page_button' }, variant: :confirm, category: :secondary do
= s_("Wiki|New page")
diff --git a/app/views/shared/wikis/_sidebar.html.haml b/app/views/shared/wikis/_sidebar.html.haml
index 8b8c981da96d81ec2985f11a239834db62ad77cd..a34827602abcba68779eb03314911643f9ba6f12 100644
--- a/app/views/shared/wikis/_sidebar.html.haml
+++ b/app/views/shared/wikis/_sidebar.html.haml
@@ -32,5 +32,5 @@
= render partial: entry.to_partial_path, object: entry, locals: { context: 'sidebar' }
.block.w-100
- if @sidebar_limited
- = link_to wiki_path(@wiki, action: :pages), class: 'btn gl-button btn-block', data: { qa_selector: 'view_all_pages_button' } do
+ = link_button_to wiki_path(@wiki, action: :pages), data: { qa_selector: 'view_all_pages_button' }, block: true do
= s_("Wiki|View All Pages")
diff --git a/app/views/shared/wikis/diff.html.haml b/app/views/shared/wikis/diff.html.haml
index ee6c7f307a7d212111845591e109afe111cd963c..67772ec40c1fdb714fefe7ca9a10ca85bf460717 100644
--- a/app/views/shared/wikis/diff.html.haml
+++ b/app/views/shared/wikis/diff.html.haml
@@ -12,7 +12,7 @@
= _('Changes')
.nav-controls.pb-md-3.pb-lg-0
- = link_to wiki_page_path(@wiki, @page, action: :history), class: 'btn gl-button', role: 'button', data: { qa_selector: 'page_history_button' } do
+ = link_button_to wiki_page_path(@wiki, @page, action: :history), role: 'button', data: { qa_selector: 'page_history_button' } do
= s_('Wiki|Page history')
.page-content-header
diff --git a/app/views/shared/wikis/pages.html.haml b/app/views/shared/wikis/pages.html.haml
index f35649d031cf79bfe53b12b0248970981d1afaa8..4656bb8d453a70fec22deaaa8b490eee87c60bc7 100644
--- a/app/views/shared/wikis/pages.html.haml
+++ b/app/views/shared/wikis/pages.html.haml
@@ -8,8 +8,7 @@
= s_("Wiki|Wiki Pages")
.nav-controls.pb-md-3.pb-lg-0
- = link_to wiki_path(@wiki, action: :git_access), class: 'btn gl-button' do
- = sprite_icon('download')
+ = link_button_to wiki_path(@wiki, action: :git_access), icon: 'download' do
= _("Clone repository")
.dropdown.inline.wiki-sort-dropdown
diff --git a/ee/app/views/admin/geo/projects/_all.html.haml b/ee/app/views/admin/geo/projects/_all.html.haml
index 334a27e6aa91abb56a6b58e7a27ff0da13cbc2f1..08630cfd9dea7efbc70de609c3aac47a0326a876 100644
--- a/ee/app/views/admin/geo/projects/_all.html.haml
+++ b/ee/app/views/admin/geo/projects/_all.html.haml
@@ -9,10 +9,10 @@
%strong.text-truncate.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
- unless project_registry.pending_verification?
- = link_to(reverify_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default btn-sm gl-mr-3') do
+ = link_button_to reverify_admin_geo_project_path(project_registry), method: :post, class: 'gl-mr-3', size: :small do
= s_('Geo|Reverify')
- unless project_registry.resync_repository?
- = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default-primary btn-sm') do
+ = link_button_to resync_admin_geo_project_path(project_registry), method: :post, size: :small do
= s_('Geo|Resync')
= render partial: "registry_#{project_registry.synchronization_state}", locals: { project_registry: project_registry }
diff --git a/ee/app/views/admin/geo/projects/_failed.html.haml b/ee/app/views/admin/geo/projects/_failed.html.haml
index d1d858c4f3009666c71b2f0c0b43843d7ecbfe99..70a5d9e1a91f9c77b967dac9db9a1ba73f444fd4 100644
--- a/ee/app/views/admin/geo/projects/_failed.html.haml
+++ b/ee/app/views/admin/geo/projects/_failed.html.haml
@@ -9,9 +9,9 @@
%strong.text-truncate.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
- if project_registry.candidate_for_redownload?
- = link_to(force_redownload_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default btn-sm gl-mr-3') do
+ = link_button_to force_redownload_admin_geo_project_path(project_registry), method: :post, class: 'gl-mr-3', size: :small do
= s_('Geo|Redownload')
- = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default-primary btn-sm') do
+ = link_button_to resync_admin_geo_project_path(project_registry), method: :post, size: :small do
= s_('Geo|Resync')
= render partial: 'registry_failed', locals: { project_registry: project_registry }
diff --git a/ee/app/views/admin/geo/projects/_pending.html.haml b/ee/app/views/admin/geo/projects/_pending.html.haml
index 611eccccdf65f9539b635c7932580029e7551486..239d0df71486f02c3a4486d584fd1c9c0702a1f0 100644
--- a/ee/app/views/admin/geo/projects/_pending.html.haml
+++ b/ee/app/views/admin/geo/projects/_pending.html.haml
@@ -9,10 +9,10 @@
%strong.text-truncate.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
- unless project_registry.pending_verification?
- = link_to(reverify_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default btn-sm gl-mr-3') do
+ = link_button_to reverify_admin_geo_project_path(project_registry), method: :post, class: 'gl-mr-3', size: :small do
= s_('Geo|Reverify')
- unless project_registry.resync_repository?
- = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default-primary btn-sm') do
+ = link_button_to resync_admin_geo_project_path(project_registry), method: :post, size: :small do
= s_('Geo|Resync')
= render partial: 'registry_pending', locals: { project_registry: project_registry }
diff --git a/ee/app/views/admin/geo/projects/_synced.html.haml b/ee/app/views/admin/geo/projects/_synced.html.haml
index 913d3c7e8b211c10c14eb373dfbc72d08eacb1fa..182b93910101441bb055c667dd965e295327bd3d 100644
--- a/ee/app/views/admin/geo/projects/_synced.html.haml
+++ b/ee/app/views/admin/geo/projects/_synced.html.haml
@@ -8,9 +8,9 @@
- else
%strong.text-truncate.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
- = link_to(reverify_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default btn-sm gl-mr-3') do
+ = link_button_to reverify_admin_geo_project_path(project_registry), method: :post, class: 'gl-mr-3', size: :small do
= s_('Geo|Reverify')
- = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'gl-button btn btn-default-primary btn-sm') do
+ = link_button_to resync_admin_geo_project_path(project_registry), method: :post, size: :small do
= s_('Geo|Resync')
= render partial: 'registry_synced', locals: { project_registry: project_registry }
diff --git a/ee/app/views/admin/projects/_geo_status_widget.html.haml b/ee/app/views/admin/projects/_geo_status_widget.html.haml
index fb837d4babcae2799208be362caa4be9243f679f..3cfb1c789bb272eb46aa41d00c450f850d07c2d3 100644
--- a/ee/app/views/admin/projects/_geo_status_widget.html.haml
+++ b/ee/app/views/admin/projects/_geo_status_widget.html.haml
@@ -3,8 +3,8 @@
.card-header
= s_('Geo|Geo Status')
.float-right
- = link_to(reverify_admin_geo_project_path(@project.project_registry), method: :post, class: 'gl-button btn btn-default btn-sm mr-2') do
+ = link_button_to reverify_admin_geo_project_path(@project.project_registry), method: :post, class: 'mr-2', size: :small do
= s_('Geo|Reverify')
- = link_to(resync_admin_geo_project_path(@project.project_registry), method: :post, class: 'gl-button btn btn-default-primary btn-sm') do
+ = link_button_to resync_admin_geo_project_path(@project.project_registry), method: :post, size: :small do
= s_('Geo|Resync')
= render partial: "admin/geo/projects/registry_#{@project.project_registry.synchronization_state}", locals: { project_registry: @project.project_registry }
diff --git a/ee/app/views/admin/users/_admin_email_users.html.haml b/ee/app/views/admin/users/_admin_email_users.html.haml
index d15efafe4ce737f65d8a13decde5937e6599e3ad..c74676c1d2cf22a9970b42afb833ccab70da1a45 100644
--- a/ee/app/views/admin/users/_admin_email_users.html.haml
+++ b/ee/app/views/admin/users/_admin_email_users.html.haml
@@ -1,4 +1,3 @@
- return unless send_emails_from_admin_area_feature_available?
-= link_to admin_email_path, { class: 'gl-button btn btn-default btn-icon', data: { toggle: "tooltip", placement: "top", container: "body" }, title: s_("AdminUsers|Send email to users") } do
- = sprite_icon('mail')
+= link_button_to nil, admin_email_path, data: { toggle: "tooltip", placement: "top", container: "body" }, title: s_("AdminUsers|Send email to users"), icon: 'mail'
diff --git a/ee/app/views/admin/users/_admin_export_user_permissions.html.haml b/ee/app/views/admin/users/_admin_export_user_permissions.html.haml
index cd23ce0997708f241981a3090b2e62ec1403b96e..e8e9592e85070b25edfc532719a42fb3c52e2ce5 100644
--- a/ee/app/views/admin/users/_admin_export_user_permissions.html.haml
+++ b/ee/app/views/admin/users/_admin_export_user_permissions.html.haml
@@ -1,4 +1,3 @@
- return unless current_user&.can?(:export_user_permissions)
-= link_to admin_user_permission_exports_path(format: :csv), { class: 'gl-button btn btn-default btn-icon', data: { toggle: "tooltip", placement: "top", container: "body" }, title: s_("AdminUsers|Export permissions as CSV (max 100,000 users)") } do
- = sprite_icon('upload')
+= link_button_to nil, admin_user_permission_exports_path(format: :csv), data: { toggle: "tooltip", placement: "top", container: "body" }, title: s_("AdminUsers|Export permissions as CSV (max 100,000 users)"), icon: 'upload'
diff --git a/ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml b/ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml
index af491402ef8c10a0936a162c8f40636656c005fb..bd02844a684ce046469c0c06b19e819c038988c1 100644
--- a/ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml
+++ b/ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml
@@ -7,5 +7,5 @@
= _('Unlock more features with GitLab Ultimate')
%p
= _('GitLab is free to use. Many features for larger teams are part of our %{link_start}paid products%{link_end}. You can try Ultimate for free without any obligation or payment details.').html_safe % { link_start: ''.html_safe, link_end: ''.html_safe }
- = link_to new_trial_url, class: "gl-button btn btn-confirm" do
+ = link_button_to new_trial_url, variant: :confirm do
= _('Start free trial')
diff --git a/ee/app/views/ldap_group_links/_ldap_group_link.html.haml b/ee/app/views/ldap_group_links/_ldap_group_link.html.haml
index 9505f997ee78cf17f08915b75aa5d46d3a8565ce..209fc017cff64dda7ab778bcc8039069882446c1 100644
--- a/ee/app/views/ldap_group_links/_ldap_group_link.html.haml
+++ b/ee/app/views/ldap_group_links/_ldap_group_link.html.haml
@@ -1,8 +1,7 @@
%li
.float-right
- = link_to group_ldap_group_link_path(group, ldap_group_link), method: :delete, class: 'gl-button btn btn-danger btn-sm' do
- = sprite_icon('unlink', size: 12, css_class: 'gl-m-0!')
- %span= _('Remove')
+ = link_button_to group_ldap_group_link_path(group, ldap_group_link), method: :delete, variant: :danger, size: :small, icon: 'unlink' do
+ = _('Remove')
%strong= ldap_group_link.cn ? "Group: #{ldap_group_link.cn}" : "Filter: #{truncate(ldap_group_link.filter, length: 70)}"
- if ldap_group_link.config
diff --git a/ee/app/views/projects/mirrors/_table_pull_row.html.haml b/ee/app/views/projects/mirrors/_table_pull_row.html.haml
index 8fe6e2e9c361e58b87d54a2594929175a7d55e32..09e7a5509e721756ad0739622909d3ebd389ee92 100644
--- a/ee/app/views/projects/mirrors/_table_pull_row.html.haml
+++ b/ee/app/views/projects/mirrors/_table_pull_row.html.haml
@@ -31,8 +31,7 @@
button_options: { class: 'disabled', title: _('This Project is currently archived and read-only. Please unarchive the project first if you want to resume Pull mirroring'), data: { container: 'body', toggle: 'tooltip', qa_selector: 'update_now_button', testid: 'update-now-button' } },
icon_classes: 'spin')
- else
- = link_to update_now_project_mirror_path(@project), method: :post, class: 'btn gl-button btn-icon btn-default js-force-update-mirror', data: { container: 'body', toggle: 'tooltip', qa_selector: 'update_now_button', testid: 'update-now-button' }, title: _('Update now') do
- = sprite_icon("retry")
+ = link_button_to nil, update_now_project_mirror_path(@project), method: :post, class: 'js-force-update-mirror', data: { container: 'body', toggle: 'tooltip', qa_selector: 'update_now_button', testid: 'update-now-button' }, title: _('Update now'), icon: 'retry'
= render Pajamas::ButtonComponent.new(variant: :danger,
icon: 'remove',
button_options: { class: 'js-delete-mirror js-delete-pull-mirror', title: _('Remove'), data: { toggle: 'tooltip', container: 'body' } })
diff --git a/ee/app/views/projects/path_locks/_path_lock.html.haml b/ee/app/views/projects/path_locks/_path_lock.html.haml
index d0b4272b540d96882575a11e36a79512b4db84a8..d7ec21a7acfd27c162a2be32ae68ecd533b5bc7a 100644
--- a/ee/app/views/projects/path_locks/_path_lock.html.haml
+++ b/ee/app/views/projects/path_locks/_path_lock.html.haml
@@ -6,7 +6,7 @@
.controls
- if can_unlock?(path_lock)
- = link_to project_path_lock_path(@project, path_lock), class: 'btn gl-button btn-default js-remove-row', title: _("Unlock"), method: :delete, data: { confirm: _("Are you sure you want to unlock %{path_lock_path}?") % { path_lock_path: path_lock.path }, container: 'body', qa_selector: 'unlock_button' }, remote: true do
+ = link_button_to project_path_lock_path(@project, path_lock), class: 'js-remove-row', title: _("Unlock"), method: :delete, data: { confirm: _("Are you sure you want to unlock %{path_lock_path}?") % { path_lock_path: path_lock.path }, container: 'body', qa_selector: 'unlock_button' }, remote: true do
= _('Unlock')
= _("locked by %{path_lock_user_name} %{created_at}").html_safe % { path_lock_user_name: path_lock.user.name, created_at: time_ago_with_tooltip(path_lock.created_at) }
diff --git a/ee/app/views/projects/settings/subscriptions/_project.html.haml b/ee/app/views/projects/settings/subscriptions/_project.html.haml
index d42913d116b8f2296ad5f7fd1d110af2b324981a..31f9effc2ff5628e822a04db7dda314066e10d98 100644
--- a/ee/app/views/projects/settings/subscriptions/_project.html.haml
+++ b/ee/app/views/projects/settings/subscriptions/_project.html.haml
@@ -9,7 +9,6 @@
= project.namespace.name
- if is_upstream_mode
%td.gl-text-right
- = link_to project_subscription_path(@project, subscription.id), method: :delete, data: { toggle: 'tooltip', title: tooltip, container: 'body', testid: 'delete-subscription' }, class: "gl-button btn btn-danger" do
- = sprite_icon('close', size: 16, css_class: 'gl-icon')
+ = link_button_to nil, project_subscription_path(@project, subscription.id), method: :delete, data: { toggle: 'tooltip', title: tooltip, container: 'body', testid: 'delete-subscription' }, variant: :danger, icon: 'close'
- else
%td
diff --git a/ee/app/views/shared/_mirror_update_button.html.haml b/ee/app/views/shared/_mirror_update_button.html.haml
index 7aaa4a99f972fa72c7b3b9224429388ddf238e28..f154b7500d48bebfa9d17261302c458ba9ce2d39 100644
--- a/ee/app/views/shared/_mirror_update_button.html.haml
+++ b/ee/app/views/shared/_mirror_update_button.html.haml
@@ -9,8 +9,7 @@
= sprite_icon('retry', css_class: 'spin gl-mr-3')
= _('Updating…')
- elsif can?(current_user, :admin_project, @project)
- = link_to update_now_project_mirror_path(@project), method: :post, class: 'gl-button btn btn-default' do
- = sprite_icon('retry', css_class: 'gl-mr-3')
+ = link_button_to update_now_project_mirror_path(@project), method: :post, icon: 'retry' do
= _('Update Now')
- else
%span.btn.gl-button.btn-default.disabled
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e04b4de3e145783b658e9ce265ea5b2c801abd39..26e76f23d9f2959e3df293cb958968879241de4f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16529,6 +16529,9 @@ msgstr ""
msgid "Download artifacts"
msgstr ""
+msgid "Download artifacts archive"
+msgstr ""
+
msgid "Download codes"
msgstr ""
@@ -54137,7 +54140,9 @@ msgid "closed %{timeago}"
msgstr ""
msgid "closed issue"
-msgstr ""
+msgid_plural "closed issues"
+msgstr[0] ""
+msgstr[1] ""
msgid "collect usage information"
msgstr ""
@@ -55195,7 +55200,9 @@ msgid "only supports valid HTTP(S) URLs"
msgstr ""
msgid "open issue"
-msgstr ""
+msgid_plural "open issues"
+msgstr[0] ""
+msgstr[1] ""
msgid "or"
msgstr ""
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
index 8a5669867bf049ae035db8d1a63f3b07a587796c..a59f172061e73edb2f13dec4000df3f476134712 100644
--- a/spec/helpers/button_helper_spec.rb
+++ b/spec/helpers/button_helper_spec.rb
@@ -223,4 +223,123 @@ def element(data = {})
end
end
end
+
+ describe '#link_button_to', feature_category: :design_system do
+ let(:content) { 'Button content' }
+ let(:href) { '#' }
+ let(:options) { {} }
+
+ RSpec.shared_examples 'basic behavior' do
+ it 'renders a basic link button' do
+ expect(subject.name).to eq('a')
+ expect(subject.classes).to include(*%w[gl-button btn btn-md btn-default])
+ expect(subject.attr('href')).to eq(href)
+ expect(subject.content.strip).to eq(content)
+ end
+
+ describe 'variant option' do
+ let(:options) { { variant: :danger } }
+
+ it 'renders the variant class' do
+ expect(subject.classes).to include('btn-danger')
+ end
+ end
+
+ describe 'category option' do
+ let(:options) { { category: :tertiary } }
+
+ it 'renders the category class' do
+ expect(subject.classes).to include('btn-default-tertiary')
+ end
+ end
+
+ describe 'size option' do
+ let(:options) { { size: :small } }
+
+ it 'renders the small class' do
+ expect(subject.classes).to include('btn-sm')
+ end
+ end
+
+ describe 'block option' do
+ let(:options) { { block: true } }
+
+ it 'renders the block class' do
+ expect(subject.classes).to include('btn-block')
+ end
+ end
+
+ describe 'selected option' do
+ let(:options) { { selected: true } }
+
+ it 'renders the selected class' do
+ expect(subject.classes).to include('selected')
+ end
+ end
+
+ describe 'target option' do
+ let(:options) { { target: '_blank' } }
+
+ it 'renders the target attribute' do
+ expect(subject.attr('target')).to eq('_blank')
+ end
+ end
+
+ describe 'method option' do
+ let(:options) { { method: :post } }
+
+ it 'renders the data-method attribute' do
+ expect(subject.attr('data-method')).to eq('post')
+ end
+ end
+
+ describe 'icon option' do
+ let(:options) { { icon: 'remove' } }
+
+ it 'renders the icon' do
+ icon = subject.at_css('svg.gl-icon')
+ expect(icon.attr('data-testid')).to eq('remove-icon')
+ end
+ end
+
+ describe 'icon only' do
+ let(:content) { nil }
+ let(:options) { { icon: 'remove' } }
+
+ it 'renders the icon-only class' do
+ expect(subject.classes).to include('btn-icon')
+ end
+ end
+
+ describe 'arbitrary html options' do
+ let(:content) { nil }
+ let(:options) { { data: { foo: true }, aria: { labelledby: 'foo' } } }
+
+ it 'renders the attributes' do
+ expect(subject.attr('data-foo')).to eq('true')
+ expect(subject.attr('aria-labelledby')).to eq('foo')
+ end
+ end
+ end
+
+ describe 'without block' do
+ subject do
+ tag = helper.link_button_to content, href, options
+ Nokogiri::HTML.fragment(tag).first_element_child
+ end
+
+ include_examples 'basic behavior'
+ end
+
+ describe 'with block' do
+ subject do
+ tag = helper.link_button_to href, options do
+ content
+ end
+ Nokogiri::HTML.fragment(tag).first_element_child
+ end
+
+ include_examples 'basic behavior'
+ end
+ end
end