diff --git a/docs/PLAN.md b/docs/PLAN.md index ff11e9c..5d8c780 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -49,3 +49,4 @@ Updated: 2026-04-02 32. Restored proxy-link copying for plain-`http` deployments by falling back from the Clipboard API to `execCommand('copy')`, and added regression coverage for both clipboard paths. 33. Replaced stale startup mock values with explicit skeleton loading states so the shell no longer flashes fallback dashboard/users/settings data before the first live snapshot arrives. 34. Renamed the tracked Docker Compose file to `compose.example.yml` and ignored local `compose.yml` so production-specific compose settings no longer get overwritten by pulls. +35. Expanded byte formatting to cover `KB` through `PB`, improving dashboard totals, user usage, and quota remainder readability for both small and very large traffic values. diff --git a/docs/PROJECT_INDEX.md b/docs/PROJECT_INDEX.md index d623745..96c65fe 100644 --- a/docs/PROJECT_INDEX.md +++ b/docs/PROJECT_INDEX.md @@ -28,8 +28,8 @@ Updated: 2026-04-02 - `src/App.test.tsx`: login-gate, startup skeleton, preferences persistence, hash-tab restoration, websocket-sync safety, reconnect/logout fallback handling, clipboard fallback coverage, generated-credential/create-edit modal flows, runtime stop, pause/resume, delete-confirm, and settings-save UI tests - `src/app.css`: full panel styling including fixed-width icon action buttons, busy-state treatment, startup skeleton shimmer states, and connection banner styling - `src/data/mockDashboard.ts`: default panel state and frontend fallback snapshot -- `src/lib/3proxy.ts`: formatting and status helpers -- `src/lib/3proxy.test.ts`: paranoia-oriented tests for core domain rules +- `src/lib/3proxy.ts`: formatting and status helpers, including byte scaling from `B` through `PB` +- `src/lib/3proxy.test.ts`: paranoia-oriented tests for core domain rules and byte-format scaling boundaries - `src/lib/panelPreferences.ts`: `localStorage`-backed panel language/theme preferences plus theme application helpers with `system` as the default theme - `src/lib/panelText.ts`: English/Russian UI text catalog for the panel shell, user-edit actions, runtime controls, last-seen labels, and connection recovery notices - `src/shared/contracts.ts`: shared panel, service, user, and API data contracts including per-user last-seen metadata diff --git a/src/lib/3proxy.test.ts b/src/lib/3proxy.test.ts index 27e9819..0b7c655 100644 --- a/src/lib/3proxy.test.ts +++ b/src/lib/3proxy.test.ts @@ -13,10 +13,16 @@ describe('formatBytes', () => { expect(formatBytes(-50)).toBe('0 B'); }); - it('formats megabytes and gigabytes with stable precision', () => { + it('formats kilobytes, megabytes, and gigabytes with stable precision', () => { + expect(formatBytes(122589)).toBe('119.7 KB'); expect(formatBytes(10 * 1024 * 1024)).toBe('10.0 MB'); expect(formatBytes(2.5 * 1024 * 1024 * 1024)).toBe('2.50 GB'); }); + + it('scales cleanly through terabytes and petabytes', () => { + expect(formatBytes(3.2 * 1024 ** 4)).toBe('3.20 TB'); + expect(formatBytes(1.25 * 1024 ** 5)).toBe('1.25 PB'); + }); }); describe('buildProxyLink', () => { diff --git a/src/lib/3proxy.ts b/src/lib/3proxy.ts index ebfc0d3..55e5cc9 100644 --- a/src/lib/3proxy.ts +++ b/src/lib/3proxy.ts @@ -1,5 +1,4 @@ -const MB = 1024 * 1024; -const GB = MB * 1024; +const BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] as const; export type ServiceState = 'live' | 'warn' | 'fail' | 'idle' | 'paused'; @@ -8,15 +7,20 @@ export function formatBytes(value: number): string { return '0 B'; } - if (value >= GB) { - return `${(value / GB).toFixed(2)} GB`; + if (value < 1024) { + return `${Math.round(value)} B`; } - if (value >= MB) { - return `${(value / MB).toFixed(1)} MB`; + let unitIndex = 0; + let scaled = value; + + while (scaled >= 1024 && unitIndex < BYTE_UNITS.length - 1) { + scaled /= 1024; + unitIndex += 1; } - return `${Math.round(value)} B`; + const decimals = scaled >= 10 ? 1 : 2; + return `${scaled.toFixed(decimals)} ${BYTE_UNITS[unitIndex]}`; } export function buildProxyLink(