From 2702b158d812ca5c884dfbeb8d8b21e694832152 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 6 Jun 2026 12:57:00 +0530 Subject: [PATCH] refactor(replay-ui): extract metrics formatters into lib module --- replay-ui/src/lib/metrics-format.ts | 43 +++++++++++++++++++++++ replay-ui/src/panels/MetricsChart.tsx | 50 ++++----------------------- 2 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 replay-ui/src/lib/metrics-format.ts diff --git a/replay-ui/src/lib/metrics-format.ts b/replay-ui/src/lib/metrics-format.ts new file mode 100644 index 0000000..cf3b344 --- /dev/null +++ b/replay-ui/src/lib/metrics-format.ts @@ -0,0 +1,43 @@ +const MB = 1024 * 1024; + +export function formatHeap(bytes: number): string { + if (bytes <= 0) return "0B"; + if (bytes < MB) return `${Math.round(bytes / 1024)}K`; + if (bytes < 1024 * MB) return `${Math.round(bytes / MB)}M`; + return `${(bytes / (1024 * MB)).toFixed(1)}G`; +} + +export function formatTime(millis: number): string { + const safe = Math.max(0, Math.floor(millis)); + const seconds = Math.floor(safe / 1000); + const mm = String(Math.floor(seconds / 60)).padStart(2, "0"); + const ss = String(seconds % 60).padStart(2, "0"); + return `${mm}:${ss}`; +} + +export function fractionFor(index: number, count: number): number { + if (count <= 1) return 0.5; + return index / (count - 1); +} + +export function buildPath( + samples: T[], + getValue: (sample: T) => number | undefined, + ceiling: number, +): string { + const segments: string[] = []; + let pendingCommand = "M"; + samples.forEach((sample, index) => { + const value = getValue(sample); + if (value === undefined) { + pendingCommand = "M"; + return; + } + const x = fractionFor(index, samples.length); + const ratio = ceiling === 0 ? 0 : Math.min(value / ceiling, 1); + const y = 1 - ratio; + segments.push(`${pendingCommand}${x.toFixed(4)},${y.toFixed(4)}`); + pendingCommand = "L"; + }); + return segments.join(" "); +} diff --git a/replay-ui/src/panels/MetricsChart.tsx b/replay-ui/src/panels/MetricsChart.tsx index 730ebe8..ffa0d3e 100644 --- a/replay-ui/src/panels/MetricsChart.tsx +++ b/replay-ui/src/panels/MetricsChart.tsx @@ -1,5 +1,11 @@ import { useState } from "react"; import type { Metrics } from "../types"; +import { + buildPath, + formatHeap, + formatTime, + fractionFor, +} from "../lib/metrics-format"; import "./MetricsChart.css"; export interface MetricsSample { @@ -15,50 +21,6 @@ export interface MetricsChartProps { runStartMillis?: number; } -const MB = 1024 * 1024; - -function formatHeap(bytes: number): string { - if (bytes <= 0) return "0B"; - if (bytes < MB) return `${Math.round(bytes / 1024)}K`; - if (bytes < 1024 * MB) return `${Math.round(bytes / MB)}M`; - return `${(bytes / (1024 * MB)).toFixed(1)}G`; -} - -function formatTime(millis: number): string { - const safe = Math.max(0, Math.floor(millis)); - const seconds = Math.floor(safe / 1000); - const mm = String(Math.floor(seconds / 60)).padStart(2, "0"); - const ss = String(seconds % 60).padStart(2, "0"); - return `${mm}:${ss}`; -} - -function fractionFor(index: number, count: number): number { - if (count <= 1) return 0.5; - return index / (count - 1); -} - -function buildPath( - samples: MetricsSample[], - getValue: (sample: MetricsSample) => number | undefined, - ceiling: number, -): string { - const segments: string[] = []; - let pendingCommand = "M"; - samples.forEach((sample, index) => { - const value = getValue(sample); - if (value === undefined) { - pendingCommand = "M"; - return; - } - const x = fractionFor(index, samples.length); - const ratio = ceiling === 0 ? 0 : Math.min(value / ceiling, 1); - const y = 1 - ratio; - segments.push(`${pendingCommand}${x.toFixed(4)},${y.toFixed(4)}`); - pendingCommand = "L"; - }); - return segments.join(" "); -} - interface LaneDot { key: number | string; x: number;