diff --git a/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_app.vue b/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_app.vue index f2c0f2349f45ff0ef61f73e034debda226d7e4f1..096bdd0740c389ef9312b0c800c97fed866b6a16 100644 --- a/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_app.vue +++ b/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_app.vue @@ -52,6 +52,11 @@ export default { }; }, i18n, + computed: { + changelog() { + return this.plan?.limits_history || {}; + }, + }, created() { this.fetchPlanData(); }, @@ -142,6 +147,7 @@ export default { :description="$options.i18n.notificationsLimitDescription" :error-message="notificationsLimitError" :modal-body="$options.i18n.notificationsLimitModalBody" + :changelog-entries="changelog.notification_limit" data-testid="notifications-limit-section" @limit-change="handleNotificationsLimitChange" /> @@ -153,6 +159,7 @@ export default { :description="$options.i18n.enforcementLimitDescription" :error-message="enforcementLimitError" :modal-body="$options.i18n.enforcementLimitModalBody" + :changelog-entries="changelog.enforcement_limit" data-testid="enforcement-limit-section" @limit-change="handleEnforcementLimitChange" /> @@ -164,6 +171,7 @@ export default { :description="$options.i18n.dashboardLimitDescription" :error-message="dashboardLimitError" :modal-body="$options.i18n.dashboardLimitModalBody" + :changelog-entries="changelog.storage_size_limit" data-testid="dashboard-limit-section" @limit-change="handleDashboardLimitChange" /> diff --git a/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_changelog.vue b/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_changelog.vue new file mode 100644 index 0000000000000000000000000000000000000000..112bc6f4645b8549f2c11ed3c00855d29f592538 --- /dev/null +++ b/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_changelog.vue @@ -0,0 +1,57 @@ +<script> +import { GlSprintf, GlLink } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import dateFormat from '~/lib/dateformat'; +import { joinPaths } from '~/lib/utils/url_utility'; + +export default { + components: { + GlSprintf, + GlLink, + }, + props: { + entries: { + type: Array, + required: false, + default: () => [], + }, + }, + computed: { + transformedEntries() { + return this.entries.map(({ username, value, timestamp }) => ({ + url: joinPaths(gon.gitlab_url, username), + username, + limit: !value ? s__('NamespaceLimits|NONE') : `${value} MiB`, + date: dateFormat(new Date(timestamp * 1000), 'yyyy-mm-dd HH:mm:ss'), // Converting timestamp to ms + })); + }, + }, + i18n: { + changelogEntry: s__( + 'NamespaceLimits|%{date} %{linkStart}%{username}%{linkEnd} changed the limit to %{limit}', + ), + }, +}; +</script> +<template> + <div> + <p v-if="transformedEntries.length" class="gl-mt-4 gl-mb-2 gl-font-weight-bold"> + {{ __('Changelog') }} + </p> + <ul v-if="transformedEntries.length" data-testid="changelog-entries"> + <li v-for="(entry, index) in transformedEntries" :key="index"> + <gl-sprintf :message="$options.i18n.changelogEntry"> + <template #link> + <gl-link :href="entry.url">{{ entry.username }}</gl-link> + </template> + <template #limit> + <strong>{{ entry.limit }}</strong> + </template> + <template #date> + <code>{{ entry.date }}</code> + </template> + </gl-sprintf> + </li> + </ul> + </div> +</template> diff --git a/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_section.vue b/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_section.vue index d71653dd4340cba0dcb18b4b7ced6a0dade9fc74..be328ba80802d8cfd10da33aabf3f8e417702852 100644 --- a/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_section.vue +++ b/ee/app/assets/javascripts/pages/admin/namespace_limits/components/namespace_limits_section.vue @@ -1,22 +1,10 @@ <script> -import { - GlAlert, - GlSprintf, - GlLink, - GlFormInput, - GlFormGroup, - GlButton, - GlModal, - GlModalDirective, -} from '@gitlab/ui'; +import { GlAlert, GlFormInput, GlFormGroup, GlButton, GlModal, GlModalDirective } from '@gitlab/ui'; import { uniqueId } from 'lodash'; import { __, s__ } from '~/locale'; +import NamespaceLimitsChangelog from './namespace_limits_changelog.vue'; const i18n = { - changelogTitle: __('Changelog'), - changelogEntry: s__( - 'NamespaceLimits|%{linkStart}%{username}%{linkEnd} changed the limit to %{limit} at %{date}', - ), updateLimitsButton: s__('NamespaceLimits|Update limit'), modalTitle: __('Are you sure?'), limitValidationError: s__('NamespaceLimits|Enter a valid number greater or equal to zero.'), @@ -36,7 +24,14 @@ const modalActionsProps = { export default { name: 'NamespaceLimitsSection', - components: { GlAlert, GlSprintf, GlLink, GlFormInput, GlFormGroup, GlButton, GlModal }, + components: { + GlAlert, + GlFormInput, + GlFormGroup, + GlButton, + GlModal, + NamespaceLimitsChangelog, + }, directives: { GlModal: GlModalDirective, }, @@ -127,23 +122,6 @@ export default { {{ modalBody }} </gl-modal> </div> - <template v-if="changelogEntries.length"> - <p class="gl-mt-4 gl-mb-2 gl-font-weight-bold">{{ $options.i18n.changelogTitle }}</p> - <ul data-testid="changelog-entries"> - <li v-for="(entry, index) in changelogEntries" :key="index"> - <gl-sprintf :message="$options.i18n.changelogEntry"> - <template #link> - <gl-link :href="entry.user_web_url">{{ entry.username }}</gl-link> - </template> - <template #limit> - {{ entry.limit }} - </template> - <template #date> - {{ entry.date }} - </template> - </gl-sprintf> - </li> - </ul> - </template> + <namespace-limits-changelog :entries="changelogEntries" /> </div> </template> diff --git a/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_changelog_spec.js b/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_changelog_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..2748bf43501bf5baf32a8d78c632a5ff06d15846 --- /dev/null +++ b/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_changelog_spec.js @@ -0,0 +1,83 @@ +import { GlLink } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import NamespaceLimitsChangelog from 'ee/pages/admin/namespace_limits/components/namespace_limits_changelog.vue'; + +const sampleChangelogEntries = [ + { + user_id: 1, + username: 'admin', + value: 150000, + timestamp: 1689069917, + }, + { + user_id: 2, + username: 'gitlab-bot', + value: 0, + timestamp: 1689067917, + }, +]; + +describe('NamespaceLimitsChangelog', () => { + let wrapper; + + const findChangelogEntries = () => wrapper.findByTestId('changelog-entries'); + const findChangelogHeader = () => wrapper.findByText('Changelog'); + + const createComponent = (props = {}) => { + wrapper = mountExtended(NamespaceLimitsChangelog, { + propsData: { entries: sampleChangelogEntries, ...props }, + stubs: { GlLink }, + }); + }; + const gitlabUrl = 'https://gitlab.com/'; + + beforeEach(() => { + gon.gitlab_url = gitlabUrl; + }); + + describe('when there are changelog entries', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders changelog entries links', () => { + const changelogLinks = findChangelogEntries() + .findAllComponents(GlLink) + .wrappers.map((w) => w.attributes('href')); + + expect(changelogLinks).toStrictEqual([ + 'https://gitlab.com/admin', + 'https://gitlab.com/gitlab-bot', + ]); + }); + + it('renders changelog entries interpolated text', () => { + const changelogTexts = findChangelogEntries() + .findAll('li') + .wrappers.map((w) => w.text().replace(/\s\s+/g, ' ')); + + expect(changelogTexts).toStrictEqual([ + '2023-07-11 10:07:17 admin changed the limit to 150000 MiB', + '2023-07-11 09:07:57 gitlab-bot changed the limit to NONE', + ]); + }); + + it('renders changelog header', () => { + expect(findChangelogHeader().exists()).toBe(true); + }); + }); + + describe('when there are no changelog entries', () => { + beforeEach(() => { + createComponent({ entries: [] }); + }); + + it('does not render changelog entries section', () => { + expect(findChangelogEntries().exists()).toBe(false); + }); + + it('does not render changelog header', () => { + expect(findChangelogHeader().exists()).toBe(false); + }); + }); +}); diff --git a/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_section_spec.js b/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_section_spec.js index e8cb20fc8994a6fd33134af48c4ef20723681530..34f1a0833a1de67d50d1af4cc99fb26412a12f4c 100644 --- a/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_section_spec.js +++ b/ee/spec/frontend/pages/admin/namespace_limits/components/namespace_limits_section_spec.js @@ -1,22 +1,8 @@ import { nextTick } from 'vue'; -import { GlFormInput, GlModal, GlAlert, GlLink } from '@gitlab/ui'; +import { GlFormInput, GlModal, GlAlert } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import NamespaceLimitsSection from 'ee/pages/admin/namespace_limits/components/namespace_limits_section.vue'; - -const sampleChangelogEntries = [ - { - user_web_url: 'https://gitlab.com/admin', - username: 'admin', - limit: '150 GiB', - date: '2023-04-05 19:14:00', - }, - { - user_web_url: 'https://gitlab.com/gitlab-bot', - username: 'gitlab-bot', - limit: '10 GiB', - date: '2023-04-06 19:14:00', - }, -]; +import NamespaceLimitsChangelog from 'ee/pages/admin/namespace_limits/components/namespace_limits_changelog.vue'; describe('NamespaceLimitsSection', () => { let wrapper; @@ -24,7 +10,8 @@ describe('NamespaceLimitsSection', () => { const defaultProps = { label: 'Set notifications limit', modalBody: 'Do you confirm changing notifications limits for all free namespaces?', - changelogEntries: sampleChangelogEntries, + changelogEntries: [], + limit: 10, }; const glModalDirective = jest.fn(); @@ -45,8 +32,7 @@ describe('NamespaceLimitsSection', () => { const findModal = () => wrapper.findComponent(GlModal); const findAlert = () => wrapper.findComponent(GlAlert); const findInput = () => wrapper.findComponent(GlFormInput); - const findChangelogEntries = () => wrapper.findByTestId('changelog-entries'); - const findChangelogHeader = () => wrapper.findByText('Changelog'); + const findChangelogComponent = () => wrapper.findComponent(NamespaceLimitsChangelog); describe('showing alert', () => { it('shows the alert if there is `errorMessage` passed to the component', () => { @@ -141,50 +127,10 @@ describe('NamespaceLimitsSection', () => { }); describe('changelog', () => { - describe('when there are changelog entries', () => { - beforeEach(() => { - createComponent(); - }); - - it('renders changelog entries links', () => { - const changelogLinks = findChangelogEntries() - .findAllComponents(GlLink) - .wrappers.map((w) => w.attributes('href')); - - expect(changelogLinks).toStrictEqual( - sampleChangelogEntries.map((item) => item.user_web_url), - ); - }); - - it('renders changelog entries interpolated text', () => { - const changelogTexts = findChangelogEntries() - .findAll('li') - .wrappers.map((w) => w.text().replace(/\s\s+/g, ' ')); - - const sampleChangelogInterpolatedText = sampleChangelogEntries.map( - (item) => `${item.username} changed the limit to ${item.limit} at ${item.date}`, - ); - - expect(changelogTexts).toStrictEqual(sampleChangelogInterpolatedText); - }); - - it('renders changelog header', () => { - expect(findChangelogHeader().exists()).toBe(true); - }); - }); - - describe('when there are no changelog entries', () => { - beforeEach(() => { - createComponent({ changelogEntries: [] }); - }); - - it('does not render changelog entries section', () => { - expect(findChangelogEntries().exists()).toBe(false); - }); - - it('does not render changelog header', () => { - expect(findChangelogHeader().exists()).toBe(false); - }); + it('renders <namespace-limits-changelog/>', () => { + createComponent(); + expect(findChangelogComponent().exists()).toBe(true); + expect(findChangelogComponent().props()).toEqual({ entries: [] }); }); }); }); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f9b4adb0efbfc278a09ac94fc813ed0d8bf347c0..53073162d2bf618fed7f447fc50e7f0a1f0b0e95 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -29992,7 +29992,7 @@ msgstr "" msgid "Namespace:" msgstr "" -msgid "NamespaceLimits|%{linkStart}%{username}%{linkEnd} changed the limit to %{limit} at %{date}" +msgid "NamespaceLimits|%{date} %{linkStart}%{username}%{linkEnd} changed the limit to %{limit}" msgstr "" msgid "NamespaceLimits|Add minimum free storage amount (in MiB) that will be used to enforce storage usage for namespaces on free plan. To remove the limit, set the value to 0 and click \"Update limit\" button." @@ -30052,6 +30052,9 @@ msgstr "" msgid "NamespaceLimits|Free Tier" msgstr "" +msgid "NamespaceLimits|NONE" +msgstr "" + msgid "NamespaceLimits|Namespace limits could not be loaded. Reload the page to try again." msgstr ""