Public source validation / validate (push) Failing after 3m8s
58 lines
2.4 KiB
TypeScript
58 lines
2.4 KiB
TypeScript
export type SignalTone = 'healthy' | 'attention' | 'critical' | 'stale' | 'unknown';
|
|
|
|
export type SignalSource = {
|
|
state?: string;
|
|
freshness?: string;
|
|
};
|
|
|
|
export type SignalContainer = {
|
|
state?: string;
|
|
health?: string;
|
|
intentionalStop?: boolean;
|
|
};
|
|
|
|
export const signalToneRank: Record<SignalTone, number> = {
|
|
critical: 0,
|
|
attention: 1,
|
|
stale: 2,
|
|
unknown: 3,
|
|
healthy: 4,
|
|
};
|
|
|
|
export function signalToneFromState(state: string | undefined): SignalTone {
|
|
const normalized = state?.trim().toLowerCase();
|
|
if (normalized === 'critical' || normalized === 'faulted' || normalized === 'down' || normalized === 'failed' || normalized === 'error') return 'critical';
|
|
if (normalized === 'attention' || normalized === 'degraded' || normalized === 'warning' || normalized === 'restarting' || normalized === 'paused' || normalized === 'removing') return 'attention';
|
|
if (normalized === 'stale') return 'stale';
|
|
if (normalized === 'healthy' || normalized === 'normal' || normalized === 'up' || normalized === 'running' || normalized === 'fresh') return 'healthy';
|
|
return 'unknown';
|
|
}
|
|
|
|
export function worstSignalTone(tones: SignalTone[]): SignalTone {
|
|
if (tones.length === 0) return 'unknown';
|
|
return tones.reduce<SignalTone>((worst, tone) => signalToneRank[tone] < signalToneRank[worst] ? tone : worst, 'healthy');
|
|
}
|
|
|
|
/** A successful HTTP response is not healthy when its provenance is stale or unknown. */
|
|
export function sourceSignalTone(source: SignalSource | undefined): SignalTone {
|
|
if (!source) return 'unknown';
|
|
const freshness = source.freshness?.trim().toLowerCase();
|
|
if (freshness === 'stale') return 'stale';
|
|
if (freshness !== 'fresh') return 'unknown';
|
|
return signalToneFromState(source.state);
|
|
}
|
|
|
|
/** Mirrors the backend application-state projection without treating an intentional stop as a failure. */
|
|
export function containerSignalTone(container: SignalContainer): SignalTone {
|
|
const state = container.state?.trim().toLowerCase();
|
|
const health = container.health?.trim().toLowerCase();
|
|
if (state === 'running') {
|
|
if (health === 'healthy') return 'healthy';
|
|
if (health === 'unhealthy') return 'attention';
|
|
return 'unknown';
|
|
}
|
|
if (state === 'restarting' || state === 'paused' || state === 'removing') return 'attention';
|
|
if (state === 'exited' || state === 'dead' || state === 'stopped') return container.intentionalStop ? 'unknown' : 'critical';
|
|
return 'unknown';
|
|
}
|