// Shared display strings + colors for connection health. Several surfaces (the // AccountRow status dot, the "Check now" result, the health-check editor preview) // render the same `HealthStatus`, so the labels and indicator colors live here: // a rename or palette change happens in one place. Mirrors the convention of // `policy-display.ts`. import type { HealthStatus } from "@executor-js/sdk/shared"; /** State form: badge text, indicator tooltips, "what is the current state". * `misconfigured` reads "API disabled": the one concrete cause it detects * today (an upstream API not enabled in the OAuth client's project), named * plainly so the user looks at the provider console, not the credential. */ export const HEALTH_STATUS_LABEL: Record = { healthy: "Healthy", expired: "Expired", misconfigured: "API disabled", degraded: "Degraded", unknown: "Unchecked", }; /** Text tone per status, for verdict lines and previews. Same per-status color * decision as the indicator dots below; change them together. `misconfigured` * shares degraded's amber: it needs attention, but the credential is fine, so * it must not carry expired's destructive red. */ export const HEALTH_TEXT_CLASS: Record = { healthy: "text-emerald-600 dark:text-emerald-400", expired: "text-destructive", misconfigured: "text-amber-600 dark:text-amber-500", degraded: "text-amber-600 dark:text-amber-500", unknown: "text-muted-foreground", }; /** Dot + ring color classes for the per-connection indicator. `unknown` is the * neutral never-probed state; `expired` reuses the destructive token so it reads * the same as a blocked policy. */ export const HEALTH_INDICATOR_COLOR: Record< HealthStatus, { readonly dot: string; readonly ring: string } > = { healthy: { dot: "bg-emerald-500", ring: "ring-emerald-500/70" }, expired: { dot: "bg-destructive", ring: "ring-destructive/70" }, misconfigured: { dot: "bg-amber-500", ring: "ring-amber-500/70" }, degraded: { dot: "bg-amber-500", ring: "ring-amber-500/70" }, unknown: { dot: "bg-muted-foreground/40", ring: "ring-muted-foreground/40" }, }; /** Severity for worst-of aggregation. `unknown` is excluded on purpose: a * never-probed connection carries no signal, so it must not drag a group * verdict in either direction. `misconfigured` outranks `degraded` (a named * configuration break beats a generic error) but not `expired` (a dead * credential blocks everything). */ const HEALTH_SEVERITY: Record, number> = { healthy: 1, degraded: 2, misconfigured: 3, expired: 4, }; /** Collapse many connection statuses to the group's worst: expired > * misconfigured > degraded > healthy. `unknown` entries are ignored; when * nothing else remains (empty input or all unknown) there is no verdict and * the caller renders nothing. */ export const worstHealthStatus = (statuses: readonly HealthStatus[]): HealthStatus | null => { let worst: Exclude | null = null; for (const status of statuses) { if (status === "unknown") continue; if (worst === null || HEALTH_SEVERITY[status] > HEALTH_SEVERITY[worst]) worst = status; } return worst; }; /** Badge variant per status: semantic color via the Badge component. */ export const HEALTH_BADGE_VARIANT: Record< HealthStatus, "default" | "secondary" | "outline" | "destructive" > = { healthy: "secondary", expired: "destructive", misconfigured: "outline", degraded: "outline", unknown: "outline", };