From 80a985b77083fa1387521accca6c5273ed26278c Mon Sep 17 00:00:00 2001 From: Bernd Storath Date: Mon, 22 Jun 2026 15:47:26 +0200 Subject: [PATCH] configure quota --- src/app/components/Form/QuotaField.vue | 45 ++++++++++++++++++++++++++ src/app/pages/clients/[id].vue | 20 ++++++++++++ src/app/utils/math.ts | 14 ++++++++ src/i18n/locales/en.json | 5 +++ src/test/tsconfig.json | 4 ++- src/test/unit/math.app.spec.ts | 32 ++++++++++++++++++ src/vitest.config.ts | 1 + 7 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/app/components/Form/QuotaField.vue create mode 100644 src/test/unit/math.app.spec.ts diff --git a/src/app/components/Form/QuotaField.vue b/src/app/components/Form/QuotaField.vue new file mode 100644 index 00000000..4331839f --- /dev/null +++ b/src/app/components/Form/QuotaField.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/app/pages/clients/[id].vue b/src/app/pages/clients/[id].vue index 6694c284..fa63ed59 100644 --- a/src/app/pages/clients/[id].vue +++ b/src/app/pages/clients/[id].vue @@ -29,6 +29,26 @@ :label="$t('client.expireDate')" /> + + + {{ $t('client.trafficQuotas') }} + + + + + {{ $t('client.address') }} { + test('keeps disabled quotas null', () => { + expect(quotaBytesToGiB(null)).toBeNull(); + expect(quotaGiBToBytes(null)).toBeNull(); + expect(quotaGiBToBytes(0)).toBeNull(); + }); + + test('converts whole and fractional GiB to bytes', () => { + expect(quotaGiBToBytes(1)).toBe(GIBIBYTE_IN_BYTES); + expect(quotaGiBToBytes(0.5)).toBe(GIBIBYTE_IN_BYTES / 2); + expect(quotaGiBToBytes(1 / GIBIBYTE_IN_BYTES)).toBe(1); + }); + + test('rounds edited GiB values to the nearest byte', () => { + expect(quotaGiBToBytes(1.5 / GIBIBYTE_IN_BYTES)).toBe(2); + }); + + test.each([1, 150, GIBIBYTE_IN_BYTES, Number.MAX_SAFE_INTEGER])( + 'round-trips the exact byte value %s', + (bytes) => { + expect(quotaGiBToBytes(quotaBytesToGiB(bytes))).toBe(bytes); + } + ); +}); diff --git a/src/vitest.config.ts b/src/vitest.config.ts index 2c56bf49..45ca83e4 100644 --- a/src/vitest.config.ts +++ b/src/vitest.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ alias: { '#server': fileURLToPath(new URL('./server', import.meta.url)), '#shared': fileURLToPath(new URL('./shared', import.meta.url)), + '#app': fileURLToPath(new URL('./app', import.meta.url)), }, }, test: {