From 9bc05c4ac3f2119c10c3ada490558627f52a526e Mon Sep 17 00:00:00 2001 From: arj22 Date: Fri, 18 Sep 2026 19:30:54 -0500 Subject: [PATCH 1/2] fix(cli): keep duration axis ticks compact in terminal charts axisTickFormatter (the CLI's documented @source port of the web's formatAxisTick, fixed in #3148) still fell through to the wide formatDurationMs for duration-formatted charts, so hdx chart kept rendering "13.33min"-style labels in a terminal column even narrower than the browser's. Port formatDurationMsCompact into the CLI and use it for the same 'duration' branch, mirroring the app-side fix and its tests. Co-Authored-By: Claude Sonnet 5 --- .changeset/cli-duration-axis-tick-compact.md | 7 +++++ .../cli/src/__tests__/formatNumber.test.ts | 23 +++++++++++++++ packages/cli/src/shared/formatNumber.ts | 29 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 .changeset/cli-duration-axis-tick-compact.md diff --git a/.changeset/cli-duration-axis-tick-compact.md b/.changeset/cli-duration-axis-tick-compact.md new file mode 100644 index 0000000000..cbf5ebe8ab --- /dev/null +++ b/.changeset/cli-duration-axis-tick-compact.md @@ -0,0 +1,7 @@ +--- +'@hyperdx/cli': patch +--- + +fix: keep duration axis-tick labels compact in terminal charts + +`axisTickFormatter` (the CLI's documented port of the web's `formatAxisTick`, fixed in #3148) fell through to the wide `formatDurationMs` for duration-formatted charts instead of the compact formatter, so `hdx chart` still rendered labels like "13.33min" in a terminal column even narrower than the browser's. diff --git a/packages/cli/src/__tests__/formatNumber.test.ts b/packages/cli/src/__tests__/formatNumber.test.ts index 71f64140c3..6991ffa454 100644 --- a/packages/cli/src/__tests__/formatNumber.test.ts +++ b/packages/cli/src/__tests__/formatNumber.test.ts @@ -58,4 +58,27 @@ describe('axisTickFormatter', () => { axisTickFormatter({ output: 'throughput', mantissa: 2 })?.(1234567), ).toBe('1234567'); }); + + describe('duration output', () => { + it('renders minutes with a single-character unit, not "min"', () => { + expect(axisTickFormatter({ output: 'duration' })?.(799.8)).toBe('13m'); + }); + + it('renders seconds compactly', () => { + expect(axisTickFormatter({ output: 'duration' })?.(39.51)).toBe('39.5s'); + }); + + it('respects a configured factor, matching formatNumber`s own duration math', () => { + expect( + axisTickFormatter({ output: 'duration', factor: 0.001 })?.(442_800), + ).toBe('7.4m'); + }); + + it('renders sub-millisecond and hour-scale values compactly too', () => { + expect(axisTickFormatter({ output: 'duration' })?.(0.0000005)).toBe( + '500ns', + ); + expect(axisTickFormatter({ output: 'duration' })?.(7500)).toBe('2.1h'); + }); + }); }); diff --git a/packages/cli/src/shared/formatNumber.ts b/packages/cli/src/shared/formatNumber.ts index 97e750e17b..7f86dfda50 100644 --- a/packages/cli/src/shared/formatNumber.ts +++ b/packages/cli/src/shared/formatNumber.ts @@ -289,6 +289,27 @@ function formatDurationMs(ms: number): string { return `${parseFloat((ms / 3_600_000).toFixed(2))}h`; } +/** + * Compact duration labels for axis ticks — fewer decimals, shorter units. + * + * @source packages/app/src/utils.ts (formatDurationMsCompact) + */ +function formatDurationMsCompact(ms: number): string { + if (ms < 0) return `-${formatDurationMsCompact(-ms)}`; + if (ms === 0) return '0'; + if (ms < 0.001) return `${+(ms * 1e6).toPrecision(2)}ns`; + if (ms < 1) { + const µs = ms * 1000; + return µs < 10 ? `${+µs.toPrecision(2)}µs` : `${Math.round(µs)}µs`; + } + if (ms < 1000) { + return ms < 10 ? `${+ms.toPrecision(2)}ms` : `${Math.round(ms)}ms`; + } + if (ms < 120_000) return `${+(ms / 1000).toPrecision(3)}s`; + if (ms < 3_600_000) return `${+(ms / 60_000).toPrecision(2)}m`; + return `${+(ms / 3_600_000).toPrecision(2)}h`; +} + // ---- Number-format resolution (de-hooked from packages/app/src/source.ts) -- // Aggregate functions whose output preserves the unit of the input value. @@ -506,6 +527,14 @@ export function axisTickFormatter( return undefined; } return (value: number) => { + // formatNumber returns early for 'duration', before the mantissa/width + // safety below ever runs - use the compact formatter instead, matching + // packages/app/src/HDXMultiSeriesTimeChart.tsx's formatAxisTick. + if (numberFormat.output === 'duration') { + const factor = numberFormat.factor ?? 1; + return formatDurationMsCompact(value * factor * 1000); + } + const displayed = numberFormat.output === 'percent' ? value * 100 : value; return formatNumber(value, { ...numberFormat, From 86b0f591a1846f537ba06b5de7aaa519c8210583 Mon Sep 17 00:00:00 2001 From: arj22 Date: Fri, 18 Sep 2026 19:45:22 -0500 Subject: [PATCH 2/2] Trim comment length and correct changeset justification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comment trimmed to 2 lines per HyperDX's terse-comment convention. Changeset no longer claims a clipping bug — the CLI's 10-char axis gutter is wider than the web's ~5-char budget, so labels were never truncated; this is about label-format parity with the web instead. Co-Authored-By: Claude Sonnet 5 --- .changeset/cli-duration-axis-tick-compact.md | 4 ++-- packages/cli/src/shared/formatNumber.ts | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.changeset/cli-duration-axis-tick-compact.md b/.changeset/cli-duration-axis-tick-compact.md index cbf5ebe8ab..a665a68c13 100644 --- a/.changeset/cli-duration-axis-tick-compact.md +++ b/.changeset/cli-duration-axis-tick-compact.md @@ -2,6 +2,6 @@ '@hyperdx/cli': patch --- -fix: keep duration axis-tick labels compact in terminal charts +fix: use compact duration labels on terminal chart axis ticks -`axisTickFormatter` (the CLI's documented port of the web's `formatAxisTick`, fixed in #3148) fell through to the wide `formatDurationMs` for duration-formatted charts instead of the compact formatter, so `hdx chart` still rendered labels like "13.33min" in a terminal column even narrower than the browser's. +`axisTickFormatter` is a documented port of the web's `formatAxisTick` (fixed in #3148) and is expected to stay behaviorally in sync with it, but it fell through to the wide `formatDurationMs` instead of the compact formatter for duration-formatted charts. `hdx chart` now renders the same short labels (e.g. "13m" instead of "13.33min") as the web app. diff --git a/packages/cli/src/shared/formatNumber.ts b/packages/cli/src/shared/formatNumber.ts index 7f86dfda50..5b309e77fa 100644 --- a/packages/cli/src/shared/formatNumber.ts +++ b/packages/cli/src/shared/formatNumber.ts @@ -527,9 +527,8 @@ export function axisTickFormatter( return undefined; } return (value: number) => { - // formatNumber returns early for 'duration', before the mantissa/width - // safety below ever runs - use the compact formatter instead, matching - // packages/app/src/HDXMultiSeriesTimeChart.tsx's formatAxisTick. + // formatNumber returns early for 'duration' - use the compact formatter + // instead, matching the web's formatAxisTick. if (numberFormat.output === 'duration') { const factor = numberFormat.factor ?? 1; return formatDurationMsCompact(value * factor * 1000);