Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/cli-duration-axis-tick-compact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@hyperdx/cli': patch
---

fix: use compact duration labels on terminal chart axis ticks

`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.
23 changes: 23 additions & 0 deletions packages/cli/src/__tests__/formatNumber.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,27 @@ describe('axisTickFormatter', () => {
axisTickFormatter({ output: 'throughput', mantissa: 2 })?.(1234567),
).toBe('1234567');
});

describe('duration output', () => {
Comment thread
arj22 marked this conversation as resolved.
Resolved
Comment thread
arj22 marked this conversation as resolved.
Resolved
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');
});
});
});
28 changes: 28 additions & 0 deletions packages/cli/src/shared/formatNumber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment thread
arj22 marked this conversation as resolved.
Resolved
*/
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.
Expand Down Expand Up @@ -506,6 +527,13 @@ export function axisTickFormatter(
return undefined;
}
return (value: number) => {
// 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);
}

const displayed = numberFormat.output === 'percent' ? value * 100 : value;
return formatNumber(value, {
...numberFormat,
Expand Down
Loading