import { useState } from "preact/hooks"; import { createClient } from "@connectrpc/connect"; import { createConnectTransport } from "@connectrpc/connect-web"; import { Container, Server } from "lucide-preact"; import type { Service } from "../gen/homelab/v1/homelab_pb"; import { HomelabService, ServiceKind, ServiceOp } from "../gen/homelab/v1/homelab_pb"; const client = createClient(HomelabService, createConnectTransport({ baseUrl: "" })); /** Бейдж статуса: system d — active/failed/выключен (not-found = намеренно disabled, не ошибка), docker — агрегат проекта. */ function badge(s: Service) { if (s.error) return ошибка; if (s.kind === ServiceKind.DOCKER) { if (s.state === "active") return работает {s.substate}; if (s.state === "partial") return частично {s.substate}; return остановлен; } if (s.loadState === "not-found") return выключен; if (s.state === "active") return {s.substate || "активен"}; if (s.state === "failed") return сбой; return остановлен; } /** Карточка сервиса: systemd-юнит или docker-проект, start/stop/restart через ServiceAction. */ export function ServiceCard({ s, refresh }: { s: Service; refresh: () => void }) { const [busy, setBusy] = useState(false); const [error, setError] = useState(""); const act = async (op: ServiceOp) => { setBusy(true); setError(""); try { await client.serviceAction({ name: s.name, kind: s.kind, op }); refresh(); // не ждём 3s поллинга } catch (e) { setError(String(e).replace(/^.*real error: /, "")); } finally { setBusy(false); } }; const disabled = s.kind === ServiceKind.SYSTEMD && s.loadState === "not-found"; const btn = (op: ServiceOp, label: string, title?: string) => ( ); return (
{s.containers.join(", ")}
)}