diff --git a/app/assets/javascripts/access_tokens/components/access_token_table_app.vue b/app/assets/javascripts/access_tokens/components/access_token_table_app.vue index 974cbeee5f94cbbc406bafa2e39c216a997b59f9..181ad1c390457eb7c8eb39bda8991e18efe363dc 100644 --- a/app/assets/javascripts/access_tokens/components/access_token_table_app.vue +++ b/app/assets/javascripts/access_tokens/components/access_token_table_app.vue @@ -6,6 +6,7 @@ import { __, sprintf } from '~/locale'; import DomElementListener from '~/vue_shared/components/dom_element_listener.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import UserDate from '~/vue_shared/components/user_date.vue'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { EVENT_SUCCESS, FIELDS, FORM_SELECTOR, INITIAL_PAGE, PAGE_SIZE } from './constants'; export default { @@ -26,6 +27,7 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, + mixins: [glFeatureFlagsMixin()], lastUsedHelpLink: helpPagePath('/user/profile/personal_access_tokens.md', { anchor: 'view-the-last-time-a-token-was-used', }), @@ -69,7 +71,9 @@ export default { if (!this.showRole) { ignoredFields.push('role'); } - + if (!this.glFeatures.advancedTokenScopes) { + ignoredFields.push('personalAccessTokenAdvancedScopes'); + } return FIELDS.filter(({ key }) => !ignoredFields.includes(key)); }, showPagination() { diff --git a/app/assets/javascripts/access_tokens/components/constants.js b/app/assets/javascripts/access_tokens/components/constants.js index 9cd7cb5bb3a401fbed72ec30b00d63dc9cc6afb1..cf3106ae785d10b69ba08d74483c4108b7219b23 100644 --- a/app/assets/javascripts/access_tokens/components/constants.js +++ b/app/assets/javascripts/access_tokens/components/constants.js @@ -21,6 +21,11 @@ export const FIELDS = [ label: __('Scopes'), sortable: true, }, + { + key: 'personalAccessTokenAdvancedScopes', + label: s__('AccessTokens|Advanced scopes'), + tdClass: 'gl-py-3!', + }, { key: 'createdAt', label: s__('AccessTokens|Created'), diff --git a/app/views/shared/access_tokens/_form.html.haml b/app/views/shared/access_tokens/_form.html.haml index 79c4bfca63072fe18a3d725180046fb6736bef78..1296018d1e60fecebefd6e441f5a8e199d383a15 100644 --- a/app/views/shared/access_tokens/_form.html.haml +++ b/app/views/shared/access_tokens/_form.html.haml @@ -41,6 +41,12 @@ = link_to _("Learn more."), help_path, target: '_blank', rel: 'noopener noreferrer' = render 'shared/tokens/scopes_form', prefix: prefix, description_prefix: description_prefix, token: token, scopes: scopes, f: f + - if Feature.enabled?(:advanced_token_scopes, current_user) && !resource + .form-group + = f.label :name, _('Advanced scopes'), class: 'label-bold' + = f.text_area :personal_access_token_advanced_scopes, class: 'form-control gl-form-input gl-form-input-xl', required: false, 'aria-describedby': 'access_token_help_text' + %span.form-text.text-muted#access_token_help_text= _("Set advanced scopes for the access token") + .gl-mt-3 = f.submit s_('AccessTokens|Create %{type}') % { type: type }, data: { testid: 'create-token-button' }, pajamas_button: true = render Pajamas::ButtonComponent.new(button_options: { type: 'reset', class: 'gl-ml-2 js-toggle-button' }) do diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 55106685d626f61efb5d6964e7c511c714587cd1..0bb05d655511b6f7c42a1cae84a810cfae64a1a8 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2678,6 +2678,9 @@ msgstr "" msgid "AccessTokens|Add a %{type}" msgstr "" +msgid "AccessTokens|Advanced scopes" +msgstr "" + msgid "AccessTokens|Are you sure?" msgstr "" @@ -4622,6 +4625,9 @@ msgstr "" msgid "Advanced export options" msgstr "" +msgid "Advanced scopes" +msgstr "" + msgid "AdvancedSearch|Could not fetch index entities. Please try again later." msgstr "" @@ -48765,6 +48771,9 @@ msgstr "" msgid "Set a password on your account to pull or push via %{protocol}." msgstr "" +msgid "Set advanced scopes for the access token" +msgstr "" + msgid "Set due date" msgstr "" diff --git a/spec/frontend/access_tokens/components/access_token_table_app_spec.js b/spec/frontend/access_tokens/components/access_token_table_app_spec.js index 09b269bbcdd62dfcf385241e67f4f8acd6901b60..5aa800c0442491a30b962c4c5260c53a641e071e 100644 --- a/spec/frontend/access_tokens/components/access_token_table_app_spec.js +++ b/spec/frontend/access_tokens/components/access_token_table_app_spec.js @@ -51,6 +51,7 @@ describe('~/access_tokens/components/access_token_table_app', () => { initialActiveAccessTokens: defaultActiveAccessTokens, noActiveTokensMessage, showRole, + glFeatures: { advancedTokenScopes: false }, ...props, }, }); @@ -269,4 +270,20 @@ describe('~/access_tokens/components/access_token_table_app', () => { expect(findPagination().exists()).toBe(true); }); }); + + describe('when advancedTokenScopes feature flag is enabled', () => { + it('should include the advanced token scopes header', () => { + createComponent({ glFeatures: { advancedTokenScopes: true } }); + const headers = findHeaders(); + expect(headers.wrappers.map((header) => header.text())).toStrictEqual([ + __('Token name'), + __('Scopes'), + s__('AccessTokens|Advanced scopes'), + s__('AccessTokens|Created'), + 'Last Used', + __('Expires'), + __('Action'), + ]); + }); + }); });