diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-12 18:13:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-12 18:13:54 +0300 |
commit | 462b603802e45891ac5152aea8cbc9298d7d4a53 (patch) | |
tree | de7e03460744491c0d7dcc6e3340272f833fb3b7 /app | |
parent | da646aac6c559584f63d1fc06132d7351abcfac6 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
26 files changed, 127 insertions, 73 deletions
diff --git a/app/assets/javascripts/jobs/bridge/components/sidebar.vue b/app/assets/javascripts/jobs/bridge/components/sidebar.vue index 9c7ae1178ea..34cefb0d0e2 100644 --- a/app/assets/javascripts/jobs/bridge/components/sidebar.vue +++ b/app/assets/javascripts/jobs/bridge/components/sidebar.vue @@ -1,6 +1,7 @@ <script> import { GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { __ } from '~/locale'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; import { JOB_SIDEBAR } from '../../constants'; import CommitBlock from '../../components/commit_block.vue'; @@ -25,6 +26,7 @@ export default { GlDropdownItem, TooltipOnTruncate, }, + mixins: [glFeatureFlagsMixin()], props: { bridgeJob: { type: Object, @@ -54,7 +56,10 @@ export default { </h4> </tooltip-on-truncate> <!-- TODO: implement retry actions --> - <div class="gl-flex-grow-1 gl-flex-shrink-0 gl-text-right"> + <div + v-if="glFeatures.triggerJobRetryAction" + class="gl-flex-grow-1 gl-flex-shrink-0 gl-text-right" + > <gl-dropdown :text="$options.i18n.retryButton" category="primary" diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index cbe40d0bfbe..6363422259e 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -26,6 +26,7 @@ import trackShowInviteMemberLink from '~/sidebar/track_invite_members'; import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_vue/constants'; import LabelsSelectWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue'; import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants'; +import eventHub from '~/sidebar/event_hub'; import Translate from '../vue_shared/translate'; import SidebarAssignees from './components/assignees/sidebar_assignees.vue'; import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue'; @@ -600,6 +601,12 @@ export function mountSidebar(mediator, store) { mountTimeTrackingComponent(); mountSeverityComponent(); + + if (window.gon?.features?.mrAttentionRequests) { + eventHub.$on('removeCurrentUserAttentionRequested', () => + mediator.removeCurrentUserAttentionRequested(), + ); + } } export { getSidebarOptions }; diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js index a49ddac8c89..25468d4a697 100644 --- a/app/assets/javascripts/sidebar/sidebar_mediator.js +++ b/app/assets/javascripts/sidebar/sidebar_mediator.js @@ -30,7 +30,7 @@ export default class SidebarMediator { this.store.addAssignee(this.store.currentUser); } - saveAssignees(field) { + async saveAssignees(field) { const selected = this.store.assignees.map((u) => u.id); // If there are no ids, that means we have to unassign (which is id = 0) @@ -38,10 +38,22 @@ export default class SidebarMediator { const assignees = selected.length === 0 ? [0] : selected; const data = { assignee_ids: assignees }; - return this.service.update(field, data); + try { + const res = await this.service.update(field, data); + + this.store.overwrite('assignees', res.data.assignees); + + if (res.data.reviewers) { + this.store.overwrite('reviewers', res.data.reviewers); + } + + return Promise.resolve(res); + } catch (e) { + return Promise.reject(e); + } } - saveReviewers(field) { + async saveReviewers(field) { const selected = this.store.reviewers.map((u) => u.id); // If there are no ids, that means we have to unassign (which is id = 0) @@ -49,7 +61,16 @@ export default class SidebarMediator { const reviewers = selected.length === 0 ? [0] : selected; const data = { reviewer_ids: reviewers }; - return this.service.update(field, data); + try { + const res = await this.service.update(field, data); + + this.store.overwrite('reviewers', res.data.reviewers); + this.store.overwrite('assignees', res.data.assignees); + + return Promise.resolve(res); + } catch (e) { + return Promise.reject(); + } } requestReview({ userId, callback }) { @@ -63,6 +84,19 @@ export default class SidebarMediator { .catch(() => callback(userId, false)); } + removeCurrentUserAttentionRequested() { + const currentUserId = gon.current_user_id; + + const currentUserReviewer = this.store.findReviewer({ id: currentUserId }); + const currentUserAssignee = this.store.findAssignee({ id: currentUserId }); + + if (currentUserReviewer?.attention_requested || currentUserAssignee?.attention_requested) { + // Update current users attention_requested state + this.store.updateReviewer(currentUserId, 'attention_requested'); + this.store.updateAssignee(currentUserId, 'attention_requested'); + } + } + async toggleAttentionRequested(type, { user, callback }) { try { const isReviewer = type === 'reviewer'; @@ -82,15 +116,7 @@ export default class SidebarMediator { const currentUserId = gon.current_user_id; if (currentUserId !== user.id) { - const currentUserReviewerOrAssignee = isReviewer - ? this.store.findReviewer({ id: currentUserId }) - : this.store.findAssignee({ id: currentUserId }); - - if (currentUserReviewerOrAssignee?.attention_requested) { - // Update current users attention_requested state - this.store.updateReviewer(currentUserId, 'attention_requested'); - this.store.updateAssignee(currentUserId, 'attention_requested'); - } + this.removeCurrentUserAttentionRequested(); } toast(sprintf(__('Requested attention from @%{username}'), { username: user.username })); diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js index 5376791469e..2caa6f4f0a0 100644 --- a/app/assets/javascripts/sidebar/stores/sidebar_store.js +++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js @@ -98,6 +98,10 @@ export default class SidebarStore { } } + overwrite(key, newData) { + this[key] = newData; + } + findAssignee(findAssignee) { return this.assignees.find(({ id }) => id === findAssignee.id); } diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue index 386ba2e2d77..24cefd63ce3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue @@ -3,6 +3,7 @@ import { GlButton } from '@gitlab/ui'; import createFlash from '~/flash'; import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import { s__ } from '~/locale'; +import sidebarEventHub from '~/sidebar/event_hub'; import eventHub from '../../event_hub'; import approvalsMixin from '../../mixins/approvals'; import MrWidgetContainer from '../mr_widget_container.vue'; @@ -172,6 +173,7 @@ export default { this.mr.setApprovals(data); eventHub.$emit('MRWidgetUpdateRequested'); eventHub.$emit('ApprovalUpdated'); + sidebarEventHub.$emit('removeCurrentUserAttentionRequested'); this.$emit('updated'); }) .catch(errFn) diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb index 662b02010ba..fa9517c3545 100644 --- a/app/controllers/import/gitlab_controller.rb +++ b/app/controllers/import/gitlab_controller.rb @@ -41,7 +41,7 @@ class Import::GitlabController < Import::BaseController override :importable_repos def importable_repos - client.projects(starting_page: 1, page_limit: MAX_PROJECT_PAGES, per_page: PER_PAGE_PROJECTS) + client.projects(starting_page: 1, page_limit: MAX_PROJECT_PAGES, per_page: PER_PAGE_PROJECTS).to_a end override :incompatible_repos diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index fa7c62c34dd..bfc2fe6432d 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -19,6 +19,7 @@ class Projects::JobsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:infinitely_collapsible_sections, @project, default_enabled: :yaml) + push_frontend_feature_flag(:trigger_job_retry_action, @project, default_enabled: :yaml) end layout 'project' diff --git a/app/helpers/ssh_keys_helper.rb b/app/helpers/ssh_keys_helper.rb index f5a9bea482b..17a9fd6146d 100644 --- a/app/helpers/ssh_keys_helper.rb +++ b/app/helpers/ssh_keys_helper.rb @@ -18,4 +18,14 @@ module SshKeysHelper container: 'body' } end + + def ssh_key_allowed_algorithms + allowed_algorithms = Gitlab::CurrentSettings.allowed_key_types.flat_map do |ssh_key_type_name| + Gitlab::SSHPublicKey.supported_algorithms_for_name(ssh_key_type_name) + end + + quoted_allowed_algorithms = allowed_algorithms.map { |name| "'#{name}'" } + + Gitlab::Utils.to_exclusive_sentence(quoted_allowed_algorithms) + end end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index d11304e5285..7ae301cdf73 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -1292,6 +1292,12 @@ module Ci end end + def use_variables_builder_definitions? + strong_memoize(:use_variables_builder_definitions) do + ::Feature.enabled?(:ci_use_variables_builder_definitions, project, default_enabled: :yaml) + end + end + private def add_message(severity, content) diff --git a/app/models/concerns/ci/contextable.rb b/app/models/concerns/ci/contextable.rb index 12ddbc2cc40..ed3b422251f 100644 --- a/app/models/concerns/ci/contextable.rb +++ b/app/models/concerns/ci/contextable.rb @@ -13,6 +13,8 @@ module Ci track_duration do variables = pipeline.variables_builder.scoped_variables(self, environment: environment, dependencies: dependencies) + next variables if pipeline.use_variables_builder_definitions? + variables.concat(project.predefined_variables) variables.concat(pipeline.predefined_variables) variables.concat(runner.predefined_variables) if runnable? && runner @@ -60,49 +62,27 @@ module Ci end def user_variables - Gitlab::Ci::Variables::Collection.new.tap do |variables| - break variables if user.blank? - - variables.append(key: 'GITLAB_USER_ID', value: user.id.to_s) - variables.append(key: 'GITLAB_USER_EMAIL', value: user.email) - variables.append(key: 'GITLAB_USER_LOGIN', value: user.username) - variables.append(key: 'GITLAB_USER_NAME', value: user.name) - end + pipeline.variables_builder.user_variables(user) end def kubernetes_variables - ::Gitlab::Ci::Variables::Collection.new.tap do |collection| - # Should get merged with the cluster kubeconfig in deployment_variables, see - # https://gitlab.com/gitlab-org/gitlab/-/issues/335089 - template = ::Ci::GenerateKubeconfigService.new(self).execute - - if template.valid? - collection.append(key: 'KUBECONFIG', value: template.to_yaml, public: false, file: true) - end - end + pipeline.variables_builder.kubernetes_variables(self) end def deployment_variables(environment:) - return [] unless environment - - project.deployment_variables( - environment: environment, - kubernetes_namespace: expanded_kubernetes_namespace - ) + pipeline.variables_builder.deployment_variables(job: self, environment: environment) end def secret_instance_variables - project.ci_instance_variables_for(ref: git_ref) + pipeline.variables_builder.secret_instance_variables(ref: git_ref) end def secret_group_variables(environment: expanded_environment_name) - return [] unless project.group - - project.group.ci_variables_for(git_ref, project, environment: environment) + pipeline.variables_builder.secret_group_variables(environment: environment, ref: git_ref) end def secret_project_variables(environment: expanded_environment_name) - project.ci_variables_for(ref: git_ref, environment: environment) + pipeline.variables_builder.secret_project_variables(environment: environment, ref: git_ref) end end end diff --git a/app/models/group.rb b/app/models/group.rb index 28b945f7c03..cacfe202fd2 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -627,14 +627,13 @@ class Group < Namespace end end - def group_member(user) + def member(user) if group_members.loaded? group_members.find { |gm| gm.user_id == user.id } else group_members.find_by(user_id: user) end end - alias_method :resource_member, :group_member def highest_group_member(user) GroupMember.where(source_id: self_and_ancestors_ids, user_id: user.id).order(:access_level).last diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb index 3ed525f34c7..9f0f49e729c 100644 --- a/app/models/namespaces/traversal/linear_scopes.rb +++ b/app/models/namespaces/traversal/linear_scopes.rb @@ -22,7 +22,7 @@ module Namespaces unscoped.where(id: root_ids) end - def self_and_ancestors(include_self: true, hierarchy_order: nil) + def self_and_ancestors(include_self: true, upto: nil, hierarchy_order: nil) return super unless use_traversal_ids_for_ancestor_scopes? ancestors_cte, base_cte = ancestor_ctes @@ -35,11 +35,15 @@ module Namespaces .where(namespaces[:id].eq(ancestors_cte.table[:ancestor_id])) .order_by_depth(hierarchy_order) - if include_self - records - else - records.where(ancestors_cte.table[:base_id].not_eq(ancestors_cte.table[:ancestor_id])) + unless include_self + records = records.where(ancestors_cte.table[:base_id].not_eq(ancestors_cte.table[:ancestor_id])) end + + if upto + records = records.where.not(id: unscoped.where(id: upto).select('unnest(traversal_ids)')) + end + + records end def self_and_ancestor_ids(include_self: true) diff --git a/app/models/namespaces/traversal/recursive_scopes.rb b/app/models/namespaces/traversal/recursive_scopes.rb index 925d9b8bb0c..583c53f8221 100644 --- a/app/models/namespaces/traversal/recursive_scopes.rb +++ b/app/models/namespaces/traversal/recursive_scopes.rb @@ -17,8 +17,8 @@ module Namespaces .where(namespaces: { parent_id: nil }) end - def self_and_ancestors(include_self: true, hierarchy_order: nil) - records = Gitlab::ObjectHierarchy.new(all).base_and_ancestors(hierarchy_order: hierarchy_order) + def self_and_ancestors(include_self: true, upto: nil, hierarchy_order: nil) + records = Gitlab::ObjectHierarchy.new(all).base_and_ancestors(upto: upto, hierarchy_order: hierarchy_order) if include_self records diff --git a/app/models/project.rb b/app/models/project.rb index fa5e84ee83e..7e2c98c85b3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1661,14 +1661,13 @@ class Project < ApplicationRecord attrs end - def project_member(user) + def member(user) if project_members.loaded? project_members.find { |member| member.user_id == user.id } else project_members.find_by(user_id: user) end end - alias_method :resource_member, :project_member def membership_locked? false diff --git a/app/models/user.rb b/app/models/user.rb index 3dacff4a989..fec37172284 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1336,7 +1336,7 @@ class User < ApplicationRecord def can_leave_project?(project) project.namespace != namespace && - project.project_member(self) + project.member(self) end def full_website_url diff --git a/app/serializers/merge_request_sidebar_basic_entity.rb b/app/serializers/merge_request_sidebar_basic_entity.rb index 3c911bbe4c8..a0832655563 100644 --- a/app/serializers/merge_request_sidebar_basic_entity.rb +++ b/app/serializers/merge_request_sidebar_basic_entity.rb @@ -5,5 +5,9 @@ class MergeRequestSidebarBasicEntity < IssuableSidebarBasicEntity expose :can_merge do |merge_request| merge_request.can_be_merged_by?(current_user) end + + expose :can_update_merge_request do |merge_request| + current_user.can?(:update_merge_request, merge_request) + end end end diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index d744881549a..b0d0c32abd1 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -59,7 +59,9 @@ module MergeRequests merge_request_activity_counter.track_users_review_requested(users: new_reviewers) merge_request_activity_counter.track_reviewers_changed_action(user: current_user) - remove_attention_requested(merge_request, current_user) + unless new_reviewers.include?(current_user) + remove_attention_requested(merge_request, current_user) + end end def cleanup_environments(merge_request) diff --git a/app/services/merge_requests/handle_assignees_change_service.rb b/app/services/merge_requests/handle_assignees_change_service.rb index 1d9f7ab59f4..97be9fe8d9f 100644 --- a/app/services/merge_requests/handle_assignees_change_service.rb +++ b/app/services/merge_requests/handle_assignees_change_service.rb @@ -23,7 +23,9 @@ module MergeRequests execute_assignees_hooks(merge_request, old_assignees) if options[:execute_hooks] - remove_attention_requested(merge_request, current_user) + unless new_assignees.include?(current_user) + remove_attention_requested(merge_request, current_user) + end end private diff --git a/app/services/merge_requests/remove_approval_service.rb b/app/services/merge_requests/remove_approval_service.rb index 872e7e0c89c..198a21884b8 100644 --- a/app/services/merge_requests/remove_approval_service.rb +++ b/app/services/merge_requests/remove_approval_service.rb @@ -17,6 +17,7 @@ module MergeRequests reset_approvals_cache(merge_request) create_note(merge_request) merge_request_activity_counter.track_unapprove_mr_action(user: current_user) + remove_attention_requested(merge_request, current_user) end success diff --git a/app/services/resource_access_tokens/revoke_service.rb b/app/services/resource_access_tokens/revoke_service.rb index 9543ea4b68d..2aaf4cc31d2 100644 --- a/app/services/resource_access_tokens/revoke_service.rb +++ b/app/services/resource_access_tokens/revoke_service.rb @@ -43,13 +43,9 @@ module ResourceAccessTokens def find_member strong_memoize(:member) do - if resource.is_a?(Project) - resource.project_member(bot_user) - elsif resource.is_a?(Group) - resource.group_member(bot_user) - else - false - end + next false unless resource.is_a?(Project) || resource.is_a?(Group) + + resource.member(bot_user) end end diff --git a/app/views/groups/settings/_ip_restriction_registration_features_cta.html.haml b/app/views/groups/settings/_ip_restriction_registration_features_cta.html.haml new file mode 100644 index 00000000000..3067220ea8f --- /dev/null +++ b/app/views/groups/settings/_ip_restriction_registration_features_cta.html.haml @@ -0,0 +1,8 @@ +- return unless registration_features_can_be_prompted? + +.form-group + = f.label :disabled_ip_restriction_ranges, class: 'label-bold' do + = _('Allow access to the following IP addresses') + = f.text_field :disabled_ip_restriction_ranges, value: '', class: 'form-control', disabled: true + %span.form-text.text-muted + = render 'shared/registration_features_discovery_message' diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml index 59c47634c2d..9a7a7521cec 100644 --- a/app/views/groups/settings/_permissions.html.haml +++ b/app/views/groups/settings/_permissions.html.haml @@ -31,6 +31,7 @@ = render 'groups/settings/project_access_token_creation', f: f, group: @group = render_if_exists 'groups/settings/delayed_project_removal', f: f, group: @group + = render 'groups/settings/ip_restriction_registration_features_cta', f: f = render_if_exists 'groups/settings/ip_restriction', f: f, group: @group = render_if_exists 'groups/settings/allowed_email_domain', f: f, group: @group = render 'groups/settings/lfs', f: f diff --git a/app/views/profiles/gpg_keys/index.html.haml b/app/views/profiles/gpg_keys/index.html.haml index bf9c77cb3ec..91af6953ee1 100644 --- a/app/views/profiles/gpg_keys/index.html.haml +++ b/app/views/profiles/gpg_keys/index.html.haml @@ -12,7 +12,7 @@ = _('Add a GPG key') %p.profile-settings-content - help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/repository/gpg_signed_commits/index.md') } - = _('Before you can add a GPG key you need to %{help_link_start}Generate it.%{help_link_end}'.html_safe) % {help_link_start: help_link_start, help_link_end: '</a>'.html_safe } + = _('Add a GPG key for secure access to GitLab. %{help_link_start}Learn more.%{help_link_end}').html_safe % {help_link_start: help_link_start, help_link_end: '</a>'.html_safe } = render 'form' %hr %h5 diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml index 2b3109225a8..4b7dd42f5dc 100644 --- a/app/views/profiles/keys/_form.html.haml +++ b/app/views/profiles/keys/_form.html.haml @@ -5,8 +5,8 @@ .form-group = f.label :key, s_('Profiles|Key'), class: 'label-bold' - %p= _("Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity.") - = f.text_area :key, class: "form-control gl-form-input js-add-ssh-key-validation-input qa-key-public-key-field", rows: 8, required: true, placeholder: s_('Profiles|Typically starts with "ssh-ed25519 …" or "ssh-rsa …"') + = f.text_area :key, class: "form-control gl-form-input js-add-ssh-key-validation-input qa-key-public-key-field", rows: 8, required: true + %p.form-text.text-muted= s_('Profiles|Begins with %{ssh_key_algorithms}.') % { ssh_key_algorithms: ssh_key_allowed_algorithms } .form-row .col.form-group = f.label :title, _('Title'), class: 'label-bold' diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml index 584bd44e386..7d4c3b6115f 100644 --- a/app/views/profiles/keys/index.html.haml +++ b/app/views/profiles/keys/index.html.haml @@ -11,11 +11,8 @@ %h5.gl-mt-0 = _('Add an SSH key') %p.profile-settings-content - - generate_link_url = help_page_path("ssh/index", anchor: 'generate-an-ssh-key-pair') - - existing_link_url = help_page_path("ssh/index", anchor: 'see-if-you-have-an-existing-ssh-key-pair') - - generate_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: generate_link_url } - - existing_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: existing_link_url } - = _('To add an SSH key you need to %{generate_link_start}generate one%{link_end} or use an %{existing_link_start}existing key%{link_end}.').html_safe % { generate_link_start: generate_link_start, existing_link_start: existing_link_start, link_end: '</a>'.html_safe } + - help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('ssh/index.md') } + = _('Add an SSH key for secure access to GitLab. %{help_link_start}Learn more.%{help_link_end}').html_safe % {help_link_start: help_link_start, help_link_end: '</a>'.html_safe } = render 'form' %hr %h5 diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml index a6a063d75f8..1e3432ab08b 100644 --- a/app/views/shared/access_tokens/_table.html.haml +++ b/app/views/shared/access_tokens/_table.html.haml @@ -55,7 +55,7 @@ - else %span.token-never-expires-label= _('Never') - if project - %td= project.project_member(token.user).human_access + %td= project.member(token.user).human_access %td= link_to _('Revoke'), revoke_route_helper.call(token), method: :put, class: "gl-button btn btn-danger btn-sm float-right qa-revoke-button #{'btn-danger-secondary' unless token.expires?}", data: { confirm: _('Are you sure you want to revoke this %{type}? This action cannot be undone.') % { type: type } } - else .settings-message.text-center |