Python 51.6%
TypeScript 46.7%
CSS 1.7%
1import Link from "next/link";2import { apiSafe } from "@/lib/api";3import { cls, dateTimeFr } from "@/lib/format";45interface Status { components: Record<string, string>; latestRun: { id: number; completedAt: string | null } | null; serverTime: string }67const LABELS: Record<string, string> = { pollWatcher: "Poll watcher", forecastEngine: "Forecast engine", electionFeed: "Election feed", documentWatcher: "Document watcher", officialData: "Données officielles", signals: "Signaux" };89export async function StatusStrip() {10 const st = await apiSafe<Status>("/api/status", { revalidate: 60 });11 return (12 <div className="border-t border-border">13 <div className="mx-auto max-w-[1280px] px-4 md:px-6 py-3 flex flex-wrap items-center gap-x-5 gap-y-2 text-[11.5px] text-ink-3">14 <Link href="/statut" className="eyebrow !text-[10.5px] hover:text-ink">QC26 · statut des données</Link>15 {st ? Object.entries(st.components).map(([k, v]) => (16 <span key={k} className="inline-flex items-center gap-1.5">17 <span className={cls("w-1.5 h-1.5 rounded-full", v === "operational" ? "bg-ok" : v === "ready" ? "bg-accent" : "bg-warn")} aria-hidden />18 {LABELS[k] ?? k} <span className="text-ink-2">{v === "operational" ? "operational" : v === "ready" ? "ready" : "degraded"}</span>19 </span>20 )) : <span>moteur injoignable</span>}21 {st?.latestRun?.completedAt && <span className="ml-auto num">Modèle recalculé {dateTimeFr(st.latestRun.completedAt)}</span>}22 <span className="num">© QC26 {new Date().getFullYear()}</span>23 </div>24 </div>25 );26}27