From 6d2e7e3bc40f75467d6d8e78d6190911c6cde6d4 Mon Sep 17 00:00:00 2001 From: Ammar Alakkad Date: Fri, 29 Aug 2025 17:23:56 +0300 Subject: [PATCH 1/2] Add formatted-date-range component to usage_billing --- .../components/formatted_date_range.vue | 26 ++++++++++ .../usage_quotas/usage_billing/utils.js | 33 +++++++++++++ .../components/formatted_date_range_spec.js | 47 +++++++++++++++++++ .../usage_quotas/usage_billing/utils_spec.js | 38 +++++++++++++++ locale/gitlab.pot | 3 ++ 5 files changed, 147 insertions(+) create mode 100644 ee/app/assets/javascripts/usage_quotas/usage_billing/components/formatted_date_range.vue create mode 100644 ee/app/assets/javascripts/usage_quotas/usage_billing/utils.js create mode 100644 ee/spec/frontend/usage_quotas/usage_billing/components/formatted_date_range_spec.js create mode 100644 ee/spec/frontend/usage_quotas/usage_billing/utils_spec.js diff --git a/ee/app/assets/javascripts/usage_quotas/usage_billing/components/formatted_date_range.vue b/ee/app/assets/javascripts/usage_quotas/usage_billing/components/formatted_date_range.vue new file mode 100644 index 00000000000000..edddedd8737f6f --- /dev/null +++ b/ee/app/assets/javascripts/usage_quotas/usage_billing/components/formatted_date_range.vue @@ -0,0 +1,26 @@ + + + diff --git a/ee/app/assets/javascripts/usage_quotas/usage_billing/utils.js b/ee/app/assets/javascripts/usage_quotas/usage_billing/utils.js new file mode 100644 index 00000000000000..f8e1c95384318c --- /dev/null +++ b/ee/app/assets/javascripts/usage_quotas/usage_billing/utils.js @@ -0,0 +1,33 @@ +import { s__ } from '~/locale'; + +/** + * Formats two ISO dates into a date range + * + * @param {String} start + * @param {String} end + * @returns Formatted range, i.e. 1 Jul - 31 Jul, 2025 + */ +export function dateRangeFormatted(start, end) { + const startDate = new Date(start); + const endDate = new Date(end); + + if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) { + throw new Error(s__('UsageBilling|Invalid date provided')); + } + + const sameYear = startDate.getFullYear() === endDate.getFullYear(); + + const formatDate = (date, includeYear = true) => { + const day = date.getDate(); + const month = date.toLocaleDateString('en-US', { month: 'short' }); + const year = date.getFullYear(); + + return includeYear ? `${day} ${month}, ${year}` : `${day} ${month}`; + }; + + if (sameYear) { + return `${formatDate(startDate, false)} - ${formatDate(endDate, true)}`; + } + + return `${formatDate(startDate, true)} - ${formatDate(endDate, true)}`; +} diff --git a/ee/spec/frontend/usage_quotas/usage_billing/components/formatted_date_range_spec.js b/ee/spec/frontend/usage_quotas/usage_billing/components/formatted_date_range_spec.js new file mode 100644 index 00000000000000..0093e6fb7f3960 --- /dev/null +++ b/ee/spec/frontend/usage_quotas/usage_billing/components/formatted_date_range_spec.js @@ -0,0 +1,47 @@ +import { shallowMount } from '@vue/test-utils'; +import FormattedDateRange from 'ee/usage_quotas/usage_billing/components/formatted_date_range.vue'; + +describe('FormattedDateRange', () => { + let wrapper; + + const defaultProps = { + start: '2024-01-01', + end: '2024-01-31', + }; + + const createComponent = (props = {}) => { + wrapper = shallowMount(FormattedDateRange, { + propsData: { ...defaultProps, ...props }, + }); + }; + + beforeAll(() => { + jest.useFakeTimers({ legacyFakeTimers: false }); + + jest.setSystemTime(new Date('2024-01-15')); + }); + + it('renders the formatted date range', () => { + createComponent(); + + expect(wrapper.text()).toBe('1 Jan - 31 Jan, 2024'); + }); + + it('renders different date range when props change', () => { + createComponent({ + start: '2024-02-01', + end: '2024-02-29', + }); + + expect(wrapper.text()).toBe('1 Feb - 29 Feb, 2024'); + }); + + it('handles cross-year date ranges', () => { + createComponent({ + start: '2023-12-01', + end: '2024-01-31', + }); + + expect(wrapper.text()).toBe('1 Dec, 2023 - 31 Jan, 2024'); + }); +}); diff --git a/ee/spec/frontend/usage_quotas/usage_billing/utils_spec.js b/ee/spec/frontend/usage_quotas/usage_billing/utils_spec.js new file mode 100644 index 00000000000000..bd04057d71b025 --- /dev/null +++ b/ee/spec/frontend/usage_quotas/usage_billing/utils_spec.js @@ -0,0 +1,38 @@ +import { dateRangeFormatted } from 'ee/usage_quotas/usage_billing/utils'; + +describe('dateRangeFormatted', () => { + it('formats date range within the same year', () => { + const start = '2025-07-01'; + const end = '2025-07-31'; + + expect(dateRangeFormatted(start, end)).toBe('1 Jul - 31 Jul, 2025'); + }); + + it('formats date range across different years', () => { + const start = '2024-12-15'; + const end = '2025-01-15'; + + expect(dateRangeFormatted(start, end)).toBe('15 Dec, 2024 - 15 Jan, 2025'); + }); + + it('formats date range with single digit dates', () => { + const start = '2025-01-01'; + const end = '2025-12-31'; + + expect(dateRangeFormatted(start, end)).toBe('1 Jan - 31 Dec, 2025'); + }); + + it('formats date range with same start and end date', () => { + const start = '2025-06-15'; + const end = '2025-06-15'; + + expect(dateRangeFormatted(start, end)).toBe('15 Jun - 15 Jun, 2025'); + }); + + it('throws an error if the rovided dates are invalid', () => { + const start = 'invalid-date'; + const end = '2025-06-15'; + + expect(() => dateRangeFormatted(start, end)).toThrow('Invalid date provided'); + }); +}); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 832b217bcd352a..f401473e76ccd5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -68786,6 +68786,9 @@ msgstr "" msgid "UsageBilling|Current month usage" msgstr "" +msgid "UsageBilling|Invalid date provided" +msgstr "" + msgid "UsageBilling|Purchase a monthly commitment" msgstr "" -- GitLab From 83de57964361d466cf6b0a6fdca2ce25a0040b91 Mon Sep 17 00:00:00 2001 From: Ammar Alakkad Date: Wed, 3 Sep 2025 14:26:34 +0300 Subject: [PATCH 2/2] Clean-up usage app initialization --- .../pages/admin/gitlab_duo/usage/index.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/ee/app/assets/javascripts/pages/admin/gitlab_duo/usage/index.js b/ee/app/assets/javascripts/pages/admin/gitlab_duo/usage/index.js index c1d00af3b4132b..174bc61b72f391 100644 --- a/ee/app/assets/javascripts/pages/admin/gitlab_duo/usage/index.js +++ b/ee/app/assets/javascripts/pages/admin/gitlab_duo/usage/index.js @@ -1,21 +1,18 @@ import Vue from 'vue'; -import AdminUsageDashboard from 'ee/usage_quotas/usage_billing/components/app.vue'; +import UsageBillingDashboard from 'ee/usage_quotas/usage_billing/components/app.vue'; -function initAdminUsageDashboard() { +function initUsageBillingDashboard() { const el = document.getElementById('js-instance-usage-billing-dashboard'); - if (!el) { - return null; - } + if (!el) return null; return new Vue({ el, - name: 'AdminUsageBillingDashboardApp', - provide: {}, + name: 'AdminUsageBillingDashboardView', render(createElement) { - return createElement(AdminUsageDashboard); + return createElement(UsageBillingDashboard); }, }); } -initAdminUsageDashboard(); +initUsageBillingDashboard(); -- GitLab