35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
export function knownMetric(value: number | null | undefined): number | "unavailable" {
|
|
return typeof value === "number" && Number.isFinite(value) ? value : "unavailable";
|
|
}
|
|
|
|
export function knownQueueDepthTotal(depths: Record<string, number | null | undefined>): number | null {
|
|
const values = Object.values(depths).filter((value): value is number => typeof value === "number" && Number.isFinite(value));
|
|
return values.length ? values.reduce((total, value) => total + value, 0) : null;
|
|
}
|
|
|
|
export function runtimeWorkTone(state: string): "good" | "info" | "warning" | "danger" | "neutral" {
|
|
if (state === "healthy" || state === "idle") return "good";
|
|
if (state === "busy") return "info";
|
|
if (state === "starting" || state === "degraded" || state === "unconfigured") return "warning";
|
|
if (state === "stale" || state === "unreachable") return "danger";
|
|
return "neutral";
|
|
}
|
|
|
|
export function heartbeatAgeSeconds(now: number, value?: string | null): number | null {
|
|
if (!value) return null;
|
|
const timestamp = Date.parse(value);
|
|
if (!Number.isFinite(timestamp)) return null;
|
|
return Math.max(0, Math.floor((now - timestamp) / 1000));
|
|
}
|
|
|
|
export function heartbeatAgeLabel(ageSeconds: number | null): string {
|
|
if (ageSeconds === null) return "unavailable";
|
|
if (ageSeconds < 60) return `${ageSeconds}s ago`;
|
|
if (ageSeconds < 3600) return `${Math.floor(ageSeconds / 60)}m ago`;
|
|
return `${Math.floor(ageSeconds / 3600)}h ago`;
|
|
}
|
|
|
|
export function shouldPollRuntimeStatus(hidden: boolean, requestInFlight: boolean): boolean {
|
|
return !hidden && !requestInFlight;
|
|
}
|