Commit 5c71c8ad authored by peterhegman's avatar peterhegman Committed by Peter Hegman

Update maximum allowable lifetime message for PAT

Admins can set a maximum allowable lifetime for personal access
tokens. When this setting is active a message is displayed to users
so they know what is the maximum date that can be set for expiration.
This commit updates the copy and styling of this message.

Changelog: changed
EE: true
parent 29a9ebfa
<script>
import { GlDatepicker, GlFormInput } from '@gitlab/ui';
import { GlDatepicker, GlFormInput, GlFormGroup } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
name: 'ExpiresAtField',
components: { GlDatepicker, GlFormInput },
i18n: {
label: __('Expiration date'),
},
components: {
GlDatepicker,
GlFormInput,
GlFormGroup,
MaxExpirationDateMessage: () =>
import('ee_component/access_tokens/components/max_expiration_date_message.vue'),
},
props: {
inputAttrs: {
type: Object,
required: false,
default: () => ({}),
},
maxDate: {
type: Date,
required: false,
default: () => null,
},
},
data() {
return {
......@@ -20,13 +36,18 @@ export default {
</script>
<template>
<gl-datepicker :target="null" :min-date="minDate">
<gl-form-input
v-bind="inputAttrs"
class="datepicker gl-datepicker-input"
autocomplete="off"
inputmode="none"
data-qa-selector="expiry_date_field"
/>
</gl-datepicker>
<gl-form-group :label="$options.i18n.label" :label-for="inputAttrs.id">
<gl-datepicker :target="null" :min-date="minDate" :max-date="maxDate">
<gl-form-input
v-bind="inputAttrs"
class="datepicker gl-datepicker-input"
autocomplete="off"
inputmode="none"
data-qa-selector="expiry_date_field"
/>
</gl-datepicker>
<template #description>
<max-expiration-date-message :max-date="maxDate" />
</template>
</gl-form-group>
</template>
......@@ -17,6 +17,7 @@ export const initExpiresAtField = () => {
}
const { expiresAt: inputAttrs } = parseRailsFormFields(el);
const { maxDate } = el.dataset;
return new Vue({
el,
......@@ -24,6 +25,7 @@ export const initExpiresAtField = () => {
return h(ExpiresAtField, {
props: {
inputAttrs,
maxDate: maxDate ? new Date(maxDate) : undefined,
},
});
},
......
......@@ -27,4 +27,10 @@ module AccessTokensHelper
}
}.to_json
end
def expires_at_field_data
{}
end
end
AccessTokensHelper.prepend_mod
......@@ -24,14 +24,9 @@
%span.form-text.text-muted.col-md-12#access_token_help_text= _("For example, the application using the token or the purpose of the token. Do not give sensitive information for the name of the token, as it will be visible to all %{resource_type} members.") % { resource_type: resource_type }
.row
.form-group.col-md-6
= f.label :expires_at, _('Expiration date'), class: 'label-bold'
.input-icon-wrapper
= render_if_exists 'personal_access_tokens/callout_max_personal_access_token_lifetime'
.js-access-tokens-expires-at
= f.text_field :expires_at, class: 'datepicker gl-datepicker-input form-control gl-form-input', placeholder: 'YYYY-MM-DD', autocomplete: 'off', data: { js_name: 'expiresAt' }
.col
.js-access-tokens-expires-at{ data: expires_at_field_data }
= f.text_field :expires_at, class: 'datepicker gl-datepicker-input form-control gl-form-input', placeholder: 'YYYY-MM-DD', autocomplete: 'off', data: { js_name: 'expiresAt' }
- if resource
.row
......
<script>
import { GlSprintf, GlLink } from '@gitlab/ui';
import { __ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import { formatDate } from '~/lib/utils/datetime_utility';
export default {
i18n: {
message: __(
'An Administrator has set the maximum expiration date to %{maxDate}. %{helpLinkStart}Learn more%{helpLinkEnd}.',
),
},
components: { GlSprintf, GlLink },
props: {
maxDate: {
type: Date,
required: false,
default: () => null,
},
},
computed: {
formattedMaxDate() {
if (!this.maxDate) {
return '';
}
return formatDate(this.maxDate, 'isoDate');
},
},
methods: { helpPagePath },
};
</script>
<template>
<span v-if="maxDate">
<gl-sprintf :message="$options.i18n.message">
<template #maxDate>{{ formattedMaxDate }}</template>
<template #helpLink="{ content }"
><gl-link
:href="
helpPagePath('user/admin_area/settings/account_and_limit_settings', {
anchor: 'limit-the-lifetime-of-personal-access-tokens',
})
"
target="_blank"
>{{ content }}</gl-link
></template
>
</gl-sprintf>
</span>
</template>
# frozen_string_literal: true
module EE
module AccessTokensHelper
extend ::Gitlab::Utils::Override
override :expires_at_field_data
def expires_at_field_data
{
max_date: personal_access_token_max_expiry_date&.iso8601
}
end
end
end
- return unless personal_access_token_expiration_policy_enabled?
.bs-callout.bs-callout-danger
= _('Maximum lifetime allowable for Personal Access Tokens is active, your expire date must be set before %{maximum_allowable_date}.') % { maximum_allowable_date: personal_access_token_max_expiry_date.to_date }
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MaxExpirationDateMessage when \`maxDate\` is set renders max date expiration message 1`] = `
<span>
An Administrator has set the maximum expiration date to 2022-03-02.
<a
class="gl-link"
href="/help/user/admin_area/settings/account_and_limit_settings#limit-the-lifetime-of-personal-access-tokens"
rel="noopener"
target="_blank"
>
Learn more
</a>
.
</span>
`;
import { mount } from '@vue/test-utils';
import { GlDatepicker } from '@gitlab/ui';
import ExpiresAtField from '~/access_tokens/components/expires_at_field.vue';
import MaxExpirationDateMessage from 'ee/access_tokens/components/max_expiration_date_message.vue';
describe('~/access_tokens/components/expires_at_field', () => {
let wrapper;
const defaultPropsData = {
inputAttrs: {
id: 'personal_access_token_expires_at',
name: 'personal_access_token[expires_at]',
placeholder: 'YYYY-MM-DD',
},
maxDate: new Date('2022-3-2'),
};
const createComponent = (propsData = defaultPropsData) => {
wrapper = mount(ExpiresAtField, {
propsData,
});
};
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('renders `MaxExpirationDateMessage` message component', () => {
expect(wrapper.findComponent(MaxExpirationDateMessage).exists()).toBe(true);
});
it('sets `GlDatepicker` `maxDate` prop', () => {
expect(wrapper.findComponent(GlDatepicker).props('maxDate')).toEqual(defaultPropsData.maxDate);
});
});
import MaxExpirationDateMessage from 'ee/access_tokens/components/max_expiration_date_message.vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
describe('MaxExpirationDateMessage', () => {
let wrapper;
const defaultPropsData = {
maxDate: new Date('2022-3-2'),
};
const createComponent = (propsData = defaultPropsData) => {
wrapper = mountExtended(MaxExpirationDateMessage, {
propsData,
});
};
describe('when `maxDate` is set', () => {
beforeEach(() => {
createComponent();
});
it('renders max date expiration message', () => {
expect(wrapper.element).toMatchSnapshot();
});
});
describe('when `maxDate` is not set', () => {
beforeEach(() => {
createComponent({});
});
it('does not render anything', () => {
expect(wrapper.text()).toBe('');
});
});
});
# frozen_string_literal: true
require "spec_helper"
RSpec.describe EE::AccessTokensHelper do
describe '#expires_at_field_data' do
it 'returns expected hash' do
expect(helper).to receive(:personal_access_token_max_expiry_date).and_return(Time.new(2022, 3, 2, 10, 30, 45, 'UTC'))
expect(helper.expires_at_field_data).to eq({
max_date: '2022-03-02T10:30:45Z'
})
end
end
end
......@@ -3702,6 +3702,9 @@ msgstr ""
msgid "An %{link_start}alert%{link_end} with the same fingerprint is already open. To change the status of this alert, resolve the linked alert."
msgstr ""
msgid "An Administrator has set the maximum expiration date to %{maxDate}. %{helpLinkStart}Learn more%{helpLinkEnd}."
msgstr ""
msgid "An Enterprise User GitLab account has been created for you by your organization:"
msgstr ""
......@@ -22656,9 +22659,6 @@ msgstr ""
msgid "Maximum job timeout has a value which could not be accepted"
msgstr ""
msgid "Maximum lifetime allowable for Personal Access Tokens is active, your expire date must be set before %{maximum_allowable_date}."
msgstr ""
msgid "Maximum lines in a diff"
msgstr ""
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`~/access_tokens/components/expires_at_field should render datepicker with input info 1`] = `
<gl-datepicker-stub
ariallabel=""
autocomplete=""
container=""
displayfield="true"
firstday="0"
inputlabel="Enter date"
mindate="Mon Jul 06 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"
placeholder="YYYY-MM-DD"
theme=""
<gl-form-group-stub
label="Expiration date"
label-for="personal_access_token_expires_at"
labeldescription=""
optionaltext="(optional)"
>
<gl-form-input-stub
autocomplete="off"
class="datepicker gl-datepicker-input"
data-qa-selector="expiry_date_field"
id="personal_access_token_expires_at"
inputmode="none"
name="personal_access_token[expires_at]"
<gl-datepicker-stub
ariallabel=""
autocomplete=""
container=""
displayfield="true"
firstday="0"
inputlabel="Enter date"
mindate="Mon Jul 06 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"
placeholder="YYYY-MM-DD"
/>
</gl-datepicker-stub>
theme=""
>
<gl-form-input-stub
autocomplete="off"
class="datepicker gl-datepicker-input"
data-qa-selector="expiry_date_field"
id="personal_access_token_expires_at"
inputmode="none"
name="personal_access_token[expires_at]"
placeholder="YYYY-MM-DD"
/>
</gl-datepicker-stub>
</gl-form-group-stub>
`;
......@@ -4,15 +4,17 @@ import ExpiresAtField from '~/access_tokens/components/expires_at_field.vue';
describe('~/access_tokens/components/expires_at_field', () => {
let wrapper;
const createComponent = () => {
const defaultPropsData = {
inputAttrs: {
id: 'personal_access_token_expires_at',
name: 'personal_access_token[expires_at]',
placeholder: 'YYYY-MM-DD',
},
};
const createComponent = (propsData = defaultPropsData) => {
wrapper = shallowMount(ExpiresAtField, {
propsData: {
inputAttrs: {
id: 'personal_access_token_expires_at',
name: 'personal_access_token[expires_at]',
placeholder: 'YYYY-MM-DD',
},
},
propsData,
});
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment