Files
mission-control-v2/frontend/src/lib/uebersicht.ts
T

83 lines
3.4 KiB
TypeScript

import { systemBaustein, appBaustein } from "@/lib/homelab"
import type { BausteinStand, ZielStand } from "@/lib/typen"
// Die Kurzform für die Übersicht: wer hat wo welche Updates — in einer Zeile je Gerät.
export interface KurzZeile {
id: string
name: string
teile: string[]
/** Etwas davon lässt sich per Knopf einspielen. */
knopf: boolean
}
/** Warum ein Update keinen Knopf hat, in zwei, drei Worten. */
function wartetText(b: BausteinStand): string | null {
if (b.aktion) return null
const g = b.grund ?? ""
const ab = g.match(/erst ab (\d{2}\.\d{2}\.(?:\d{4})? ?\d{2}:\d{2})/)?.[1]
if (ab) return `ab ${ab}`
if (/eigene Oberfläche|eigenen Oberfläche|eigenes Update/i.test(g)) return "über die App"
return null
}
/** „App → 0.79.0 (ab 26.09. 08:06)“, „48 Pakete“, „11 Images“ — was an einem Gerät ansteht. */
export function kurzform(ziel: ZielStand): KurzZeile | null {
const neu = ziel.bausteine.filter((b) => b.zustand === "neu")
if (neu.length === 0) return null
const teile: string[] = []
const app = appBaustein(ziel)
if (app?.zustand === "neu") {
const w = wartetText(app)
teile.push(`App → ${app.verfuegbar ?? "neu"}${w ? ` (${w})` : ""}`)
}
const sys = systemBaustein(ziel)
if (sys?.zustand === "neu") teile.push(sys.kurz || (sys.id === "docker" ? "Images" : "Pakete"))
// KI-Box: Bausteine heißen selbst (Betriebssystem, Hermes, Motor …).
for (const b of neu) {
if (b === app || b === sys) continue
teile.push(`${b.name}${b.kurz ? ` · ${b.kurz}` : ""}`)
}
return { id: ziel.id, name: ziel.name, teile, knopf: neu.some((b) => !!b.aktion) }
}
/** Die KI-Box ist ein Gerät mit mehreren Bausteinen — dort steht je Baustein eine Zeile. */
function bausteinZeilen(ziel: ZielStand): KurzZeile[] {
return ziel.bausteine
.filter((b) => b.zustand === "neu")
.map((b) => ({ id: `${ziel.id}-${b.id}`, name: b.name, teile: [b.kurz || b.verfuegbar || "neu"], knopf: !!b.aktion }))
}
/** Alle Kurzzeilen eines Bereichs: erst, was per Knopf geht, dann der Rest. */
export function kurzformen(ziele: ZielStand[]): KurzZeile[] {
const zeilen = ziele.flatMap((z) => (z.art === "ki-box" ? bausteinZeilen(z) : [kurzform(z)]))
.filter((z): z is KurzZeile => z !== null)
return [...zeilen.filter((z) => z.knopf), ...zeilen.filter((z) => !z.knopf)]
}
export type Lagestufe = "ok" | "info" | "gelb" | "rot"
/** Die Gesamtlage über beide Bereiche — Störung vor Hinweis vor offenen Updates. */
export function gesamtlage(e: {
getrennt: string[]
stumm: string[]
hinweiseRot: number
hinweise: number
updates: number
}): { stufe: Lagestufe; titel: string; text: string } {
if (e.getrennt.length > 0) {
return { stufe: "rot", titel: "Verbindung weg", text: `${e.getrennt.join(" und ")} antwortet nicht.` }
}
if (e.stumm.length > 0 || e.hinweiseRot > 0) {
const was = e.stumm.length > 0 ? `${e.stumm.join(", ")} antwortet nicht` : "Ein roter Hinweis wartet"
return { stufe: "rot", titel: "Störung", text: `${was}.` }
}
if (e.hinweise > 0) {
return { stufe: "gelb", titel: e.hinweise === 1 ? "1 Hinweis" : `${e.hinweise} Hinweise`, text: "Bei Gelegenheit ansehen." }
}
if (e.updates > 0) {
return { stufe: "info", titel: "Alles läuft", text: `${e.updates} ${e.updates === 1 ? "Update steht" : "Updates stehen"} bereit.` }
}
return { stufe: "ok", titel: "Alles läuft", text: "Keine Hinweise, keine offenen Updates." }
}