41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
import type { UiMetricValue } from "./types";
|
|
|
|
const byteUnits = ["B", "KB", "MB", "GB", "TB"];
|
|
|
|
export function formatMetricValue(metric: UiMetricValue): string {
|
|
if (metric.kind === "text") return String(metric.value);
|
|
|
|
const value = typeof metric.value === "number" ? metric.value : Number(metric.value);
|
|
const precision = metric.precision ?? inferPrecision(value);
|
|
const unit = metric.unit ?? defaultUnit(metric.kind);
|
|
|
|
if (metric.kind === "bytes") return formatBytes(value, precision);
|
|
return `${value.toFixed(precision)}${unit ? ` ${unit}` : ""}`;
|
|
}
|
|
|
|
export function clampPercent(value = 0): number {
|
|
if (!Number.isFinite(value)) return 0;
|
|
return Math.max(0, Math.min(100, value));
|
|
}
|
|
|
|
function defaultUnit(kind: UiMetricValue["kind"]): string {
|
|
if (kind === "percent") return "%";
|
|
if (kind === "temperature") return "C";
|
|
if (kind === "latency") return "ms";
|
|
return "";
|
|
}
|
|
|
|
function inferPrecision(value: number): number {
|
|
return Number.isInteger(value) ? 0 : 1;
|
|
}
|
|
|
|
function formatBytes(value: number, precision: number): string {
|
|
let size = value;
|
|
let index = 0;
|
|
while (size >= 1024 && index < byteUnits.length - 1) {
|
|
size /= 1024;
|
|
index += 1;
|
|
}
|
|
|
|
return `${size.toFixed(precision)} ${byteUnits[index]}`;
|
|
}
|