Pulse/frontend-modern/src/utils/status.ts
2025-11-14 12:42:08 +00:00

246 lines
7.1 KiB
TypeScript

import type {
Node,
VM,
Container,
PBSInstance,
Host,
DockerHost,
DockerContainer,
DockerService,
} from '@/types/api';
const ONLINE_STATUS = 'online';
const RUNNING_STATUS = 'running';
const normalize = (value?: string | null): string => (value || '').trim().toLowerCase();
const formatStatusLabel = (value?: string | null, fallback = 'Unknown'): string => {
if (!value) return fallback;
const normalized = value.trim();
if (!normalized) return fallback;
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
};
export type StatusIndicatorVariant = 'success' | 'warning' | 'danger' | 'muted';
export interface StatusIndicator {
variant: StatusIndicatorVariant;
label: string;
}
const defaultIndicator: StatusIndicator = { variant: 'muted', label: 'Unknown' };
export const OFFLINE_HEALTH_STATUSES = new Set([
'offline',
'error',
'failed',
'down',
'unreachable',
'disconnected',
'timeout',
'stopped',
'inactive',
]);
export const DEGRADED_HEALTH_STATUSES = new Set([
'degraded',
'warning',
'maintenance',
'syncing',
'initializing',
'starting',
'pending',
'partial',
'unknown',
'recovering',
'pausing',
'restarting',
]);
export const STOPPED_CONTAINER_STATES = new Set(['exited', 'stopped', 'created', 'paused']);
export const ERROR_CONTAINER_STATES = new Set([
'restarting',
'dead',
'removing',
'failed',
'error',
'oomkilled',
'unhealthy',
]);
export function isNodeOnline(node: Partial<Node> | undefined | null): boolean {
if (!node) return false;
if (node.status !== ONLINE_STATUS) return false;
if ((node.uptime ?? 0) <= 0) return false;
const connection = (node as Node).connectionHealth;
const normalizedConnection = normalize(connection);
if (normalizedConnection === 'offline' || normalizedConnection === 'error') return false;
return true;
}
export function isGuestRunning(
guest: Partial<VM | Container> | undefined | null,
parentNodeOnline = true,
): boolean {
if (!guest) return false;
if (!parentNodeOnline) return false;
return guest.status === RUNNING_STATUS;
}
export function getNodeStatusIndicator(node: Partial<Node> | undefined | null): StatusIndicator {
if (!node) return defaultIndicator;
const connection = normalize((node as Node).connectionHealth);
const status = normalize(node.status);
const uptime = node.uptime ?? 0;
if (OFFLINE_HEALTH_STATUSES.has(connection) || OFFLINE_HEALTH_STATUSES.has(status) || uptime <= 0) {
return { variant: 'danger', label: formatStatusLabel(connection || status, 'Offline') };
}
if (DEGRADED_HEALTH_STATUSES.has(connection) || DEGRADED_HEALTH_STATUSES.has(status)) {
return { variant: 'warning', label: formatStatusLabel(connection || status, 'Degraded') };
}
if (isNodeOnline(node)) {
return { variant: 'success', label: 'Online' };
}
return defaultIndicator;
}
export function getPBSStatusIndicator(
instance: Partial<PBSInstance> | undefined | null,
): StatusIndicator {
if (!instance) return defaultIndicator;
const connection = normalize(instance.connectionHealth);
const status = normalize(instance.status);
if (OFFLINE_HEALTH_STATUSES.has(connection) || OFFLINE_HEALTH_STATUSES.has(status)) {
return { variant: 'danger', label: formatStatusLabel(connection || status, 'Offline') };
}
if (status === 'healthy' || status === ONLINE_STATUS) {
return { variant: 'success', label: formatStatusLabel(status, 'Online') };
}
if (DEGRADED_HEALTH_STATUSES.has(connection) || DEGRADED_HEALTH_STATUSES.has(status)) {
return { variant: 'warning', label: formatStatusLabel(connection || status, 'Degraded') };
}
return defaultIndicator;
}
export function getGuestPowerIndicator(
guest: Partial<VM | Container> | undefined | null,
parentNodeOnline = true,
): StatusIndicator {
if (!guest) return defaultIndicator;
if (!parentNodeOnline) {
return { variant: 'danger', label: 'Node offline' };
}
return isGuestRunning(guest, parentNodeOnline)
? { variant: 'success', label: 'Running' }
: { variant: 'danger', label: 'Stopped' };
}
export function getHostStatusIndicator(host: Partial<Host> | undefined | null): StatusIndicator {
if (!host) return defaultIndicator;
const status = normalize(host.status);
if (OFFLINE_HEALTH_STATUSES.has(status)) {
return { variant: 'danger', label: formatStatusLabel(status, 'Offline') };
}
if (DEGRADED_HEALTH_STATUSES.has(status)) {
return { variant: 'warning', label: formatStatusLabel(status, 'Degraded') };
}
if (status === ONLINE_STATUS || status === RUNNING_STATUS) {
return { variant: 'success', label: 'Online' };
}
return status
? { variant: 'muted', label: formatStatusLabel(status, 'Unknown') }
: defaultIndicator;
}
export function getDockerHostStatusIndicator(
host: Partial<DockerHost> | string | undefined | null,
): StatusIndicator {
const rawStatus = typeof host === 'string' ? host : host?.status;
const status = normalize(rawStatus);
if (OFFLINE_HEALTH_STATUSES.has(status)) {
return { variant: 'danger', label: formatStatusLabel(status, 'Offline') };
}
if (DEGRADED_HEALTH_STATUSES.has(status)) {
return { variant: 'warning', label: formatStatusLabel(status, 'Degraded') };
}
if (status === ONLINE_STATUS || status === RUNNING_STATUS || status === 'healthy') {
return { variant: 'success', label: formatStatusLabel(status, 'Online') };
}
return status
? { variant: 'muted', label: formatStatusLabel(status, 'Unknown') }
: defaultIndicator;
}
export function getDockerContainerStatusIndicator(
container: Partial<DockerContainer> | undefined | null,
): StatusIndicator {
if (!container) return defaultIndicator;
const state = normalize(container.state);
const health = normalize(container.health);
if (state === RUNNING_STATUS && (!health || health === 'healthy')) {
return { variant: 'success', label: 'Running' };
}
if (ERROR_CONTAINER_STATES.has(state) || health === 'unhealthy') {
const label = health === 'unhealthy' ? 'Unhealthy' : formatStatusLabel(state, 'Error');
return { variant: 'danger', label };
}
if (STOPPED_CONTAINER_STATES.has(state)) {
return { variant: 'danger', label: formatStatusLabel(state, 'Stopped') };
}
if (!state && health) {
return { variant: 'warning', label: formatStatusLabel(health, 'Unknown') };
}
if (state) {
return { variant: 'warning', label: formatStatusLabel(state, 'Unknown') };
}
return defaultIndicator;
}
export function getDockerServiceStatusIndicator(
service: Partial<DockerService> | undefined | null,
): StatusIndicator {
if (!service) return defaultIndicator;
const desired = service.desiredTasks ?? 0;
const running = service.runningTasks ?? 0;
if (desired <= 0) {
if (running > 0) {
return { variant: 'warning', label: `Running ${running} task${running === 1 ? '' : 's'}` };
}
return { variant: 'muted', label: 'No tasks' };
}
if (running >= desired) {
return { variant: 'success', label: 'Healthy' };
}
if (running === 0) {
return { variant: 'danger', label: `Stopped (${running}/${desired})` };
}
return { variant: 'warning', label: `Degraded (${running}/${desired})` };
}