From ac12a3d9b9bae524c42b1f7a5d1f73c975dd4887 Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Thu, 26 Feb 2026 09:37:03 -0800 Subject: [PATCH] fix: preserve refill date slashes in subscription credits label (#9251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Motivation - Subscription credit labels were rendering the refill date with HTML-escaped separators (`/`) because `vue-i18n` parameter escaping was applied to the date interpolation. - The goal is to render date-only parameters like `MM/DD/YY` with literal slashes so the UI shows a human-readable date string. ### Description - Disabled `vue-i18n` parameter escaping for the `subscription.creditsRemainingThisMonth` and `subscription.creditsRemainingThisYear` lookups in both subscription panels by passing `{ escapeParameter: false }` to `t()` in `SubscriptionPanelContentLegacy.vue` and `SubscriptionPanelContentWorkspace.vue`. - Adjusted the unit test i18n setup in `SubscriptionPanel.test.ts` to include `escapeParameter: true` in the test `i18n` instance and updated the test messages to use `Included (Refills {date})`. - Added a regression unit test in `SubscriptionPanel.test.ts` asserting the rendered label contains `Included (Refills 12/31/24)` and does not contain the escaped entity `/`. ### Testing - Ran formatting with `pnpm format` which completed successfully. - Ran lint via `pnpm lint` which passed with pre-existing warnings only (no new errors). - Ran type checking with `pnpm typecheck` (via `vue-tsc --noEmit`) which completed successfully. - Ran the modified unit tests with `pnpm vitest run src/platform/cloud/subscription/components/SubscriptionPanel.test.ts` and the test file passed (10 passed, 5 skipped). - Attempted a Playwright-based visual capture of the running app but Chromium crashed in this environment (SIGSEGV) before navigation, so no screenshot was produced. ------ [Codex Task](https://chatgpt.com/codex/tasks/task_e_69a0175f58788330b2256329a500e14b) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9251-fix-preserve-refill-date-slashes-in-subscription-credits-label-3136d73d36508182b770f5719a52d189) by [Unito](https://www.unito.io) --- .../components/SubscriptionPanel.test.ts | 11 ++++++++- .../SubscriptionPanelContentLegacy.vue | 24 ++++++++++++++----- .../SubscriptionPanelContentWorkspace.vue | 24 ++++++++++++++----- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/platform/cloud/subscription/components/SubscriptionPanel.test.ts b/src/platform/cloud/subscription/components/SubscriptionPanel.test.ts index b366ceb0c5..7810a56dcd 100644 --- a/src/platform/cloud/subscription/components/SubscriptionPanel.test.ts +++ b/src/platform/cloud/subscription/components/SubscriptionPanel.test.ts @@ -101,6 +101,7 @@ vi.mock('@/composables/billing/useBillingContext', () => ({ const i18n = createI18n({ legacy: false, locale: 'en', + escapeParameter: true, messages: { en: { subscription: { @@ -112,7 +113,8 @@ const i18n = createI18n({ partnerNodesBalance: 'Partner Nodes Balance', partnerNodesDescription: 'Credits for partner nodes', totalCredits: 'Total Credits', - creditsRemainingThisMonth: 'Credits remaining this month', + creditsRemainingThisMonth: 'Included (Refills {date})', + creditsRemainingThisYear: 'Included (Refills {date})', creditsYouveAdded: "Credits you've added", monthlyBonusDescription: 'Monthly bonus', prepaidDescription: 'Prepaid credits', @@ -286,6 +288,13 @@ describe('SubscriptionPanel', () => { const wrapper = createWrapper() expect(wrapper.findAll('.skeleton').length).toBe(0) }) + + it('renders refill date with literal slashes', () => { + mockIsActiveSubscription.value = true + const wrapper = createWrapper() + expect(wrapper.text()).toContain('Included (Refills 12/31/24)') + expect(wrapper.text()).not.toContain('/') + }) }) // TODO: Re-enable when migrating to VTL so we can find by user visible content. diff --git a/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue b/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue index e7098e5336..c32e00c729 100644 --- a/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue +++ b/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue @@ -256,12 +256,24 @@ const refillsDate = computed(() => { const creditsRemainingLabel = computed(() => isYearlySubscription.value - ? t('subscription.creditsRemainingThisYear', { - date: refillsDate.value - }) - : t('subscription.creditsRemainingThisMonth', { - date: refillsDate.value - }) + ? t( + 'subscription.creditsRemainingThisYear', + { + date: refillsDate.value + }, + { + escapeParameter: false + } + ) + : t( + 'subscription.creditsRemainingThisMonth', + { + date: refillsDate.value + }, + { + escapeParameter: false + } + ) ) const planTotalCredits = computed(() => { diff --git a/src/platform/workspace/components/SubscriptionPanelContentWorkspace.vue b/src/platform/workspace/components/SubscriptionPanelContentWorkspace.vue index 6ab7b083d0..d4c0d068e9 100644 --- a/src/platform/workspace/components/SubscriptionPanelContentWorkspace.vue +++ b/src/platform/workspace/components/SubscriptionPanelContentWorkspace.vue @@ -534,12 +534,24 @@ const refillsDate = computed(() => { const creditsRemainingLabel = computed(() => isYearlySubscription.value - ? t('subscription.creditsRemainingThisYear', { - date: refillsDate.value - }) - : t('subscription.creditsRemainingThisMonth', { - date: refillsDate.value - }) + ? t( + 'subscription.creditsRemainingThisYear', + { + date: refillsDate.value + }, + { + escapeParameter: false + } + ) + : t( + 'subscription.creditsRemainingThisMonth', + { + date: refillsDate.value + }, + { + escapeParameter: false + } + ) ) const planTotalCredits = computed(() => {