feat(analytics): add formatDurationMs function for improved duration formatting
This commit is contained in:
parent
a1c3de04d5
commit
48455d94e8
3 changed files with 28 additions and 5 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { Show, createMemo, createResource, createSignal, type Component } from 'solid-js';
|
import { Show, createMemo, createResource, createSignal, type Component } from 'solid-js';
|
||||||
import { api } from '../api/client';
|
import { api } from '../api/client';
|
||||||
import { Layout } from '../components/Layout';
|
import { Layout } from '../components/Layout';
|
||||||
|
import { formatDurationMs } from '../ui/lib/format';
|
||||||
import {
|
import {
|
||||||
BoxPlotChart,
|
BoxPlotChart,
|
||||||
ChartLegend,
|
ChartLegend,
|
||||||
|
|
@ -142,7 +143,7 @@ export const Analytics: Component = () => {
|
||||||
return [
|
return [
|
||||||
{ label: 'Requests', value: formatInteger.format(totals.requests), hint: `Last ${days()} days` },
|
{ label: 'Requests', value: formatInteger.format(totals.requests), hint: `Last ${days()} days` },
|
||||||
{ label: 'Tokens', value: formatInteger.format(totals.tokens), hint: `Selected ${days()}-day window total` },
|
{ label: 'Tokens', value: formatInteger.format(totals.tokens), hint: `Selected ${days()}-day window total` },
|
||||||
{ label: 'Avg Response', value: `${avgLatency.toFixed(1)}ms`, hint: 'Across visible backend series' },
|
{ label: 'Avg Response', value: formatDurationMs(avgLatency), hint: 'Across visible backend series' },
|
||||||
{ label: 'Errors', value: formatInteger.format(errorCount), hint: 'Absolute backend error count' },
|
{ label: 'Errors', value: formatInteger.format(errorCount), hint: 'Absolute backend error count' },
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
@ -252,8 +253,8 @@ export const Analytics: Component = () => {
|
||||||
showLegend={false}
|
showLegend={false}
|
||||||
hiddenKeys={hiddenResponseSeries()}
|
hiddenKeys={hiddenResponseSeries()}
|
||||||
onToggleLegend={(key) => toggleHiddenKey(setHiddenResponseSeries, key)}
|
onToggleLegend={(key) => toggleHiddenKey(setHiddenResponseSeries, key)}
|
||||||
yLeftLabel="Milliseconds"
|
yLeftLabel="Response time"
|
||||||
formatLeftValue={(value) => `${value.toFixed(0)}ms`}
|
formatLeftValue={formatDurationMs}
|
||||||
tooltipTitle="Average backend response time"
|
tooltipTitle="Average backend response time"
|
||||||
/>
|
/>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import RefreshCcw from 'lucide-solid/icons/refresh-ccw';
|
||||||
import { Show, createMemo, createResource, createSignal, type Component } from 'solid-js';
|
import { Show, createMemo, createResource, createSignal, type Component } from 'solid-js';
|
||||||
import { api } from '../api/client';
|
import { api } from '../api/client';
|
||||||
import { Layout } from '../components/Layout';
|
import { Layout } from '../components/Layout';
|
||||||
|
import { formatDurationMs } from '../ui/lib/format';
|
||||||
import {
|
import {
|
||||||
ChartLegend,
|
ChartLegend,
|
||||||
ComboChart,
|
ComboChart,
|
||||||
|
|
@ -248,8 +249,8 @@ export const Dashboard: Component = () => {
|
||||||
showLegend={false}
|
showLegend={false}
|
||||||
hiddenKeys={hiddenLatencySeries()}
|
hiddenKeys={hiddenLatencySeries()}
|
||||||
onToggleLegend={(key) => toggleHiddenKey(setHiddenLatencySeries, key)}
|
onToggleLegend={(key) => toggleHiddenKey(setHiddenLatencySeries, key)}
|
||||||
yLeftLabel="Milliseconds"
|
yLeftLabel="Latency"
|
||||||
formatLeftValue={(value) => `${value.toFixed(0)}ms`}
|
formatLeftValue={formatDurationMs}
|
||||||
tooltipTitle="Backend latency"
|
tooltipTitle="Backend latency"
|
||||||
/>
|
/>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
|
||||||
21
client/src/ui/lib/format.ts
Normal file
21
client/src/ui/lib/format.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
const durationFormatters = {
|
||||||
|
seconds: new Intl.NumberFormat('en-US', { maximumFractionDigits: 1 }),
|
||||||
|
minutes: new Intl.NumberFormat('en-US', { maximumFractionDigits: 1 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export function formatDurationMs(value: number): string {
|
||||||
|
if (!Number.isFinite(value)) {
|
||||||
|
return '0ms';
|
||||||
|
}
|
||||||
|
|
||||||
|
const absoluteValue = Math.abs(value);
|
||||||
|
if (absoluteValue < 1000) {
|
||||||
|
return `${Math.round(value)}ms`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (absoluteValue < 60_000) {
|
||||||
|
return `${durationFormatters.seconds.format(value / 1000)}s`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${durationFormatters.minutes.format(value / 60_000)}m`;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue