ultisuite-client/components/admin/settings/admin-runtime-panel.tsx
2026-06-07 21:55:42 +02:00

112 lines
4.5 KiB
TypeScript

"use client"
import { useState } from "react"
import { ChevronDown, ChevronRight, Container, Lock } from "lucide-react"
import { useOrgSettingsStore } from "@/lib/admin-settings/org-settings-store"
import { envGroupLabel, groupEnvVars } from "@/lib/admin/deploy-runtime"
import { Badge } from "@/components/ui/badge"
import { cn } from "@/lib/utils"
export function AdminRuntimePanel() {
const meta = useOrgSettingsStore((s) => s.meta)
const synced = useOrgSettingsStore((s) => s.apiSynced)
const [envOpen, setEnvOpen] = useState(false)
if (!synced || !meta) return null
const eff = meta.effective
const envGroups = groupEnvVars(meta.envVars ?? [])
const setCount = (meta.envVars ?? []).filter((v) => v.set).length
return (
<div className="mb-4 space-y-3 rounded-lg border border-border bg-muted/30 p-4 text-xs">
<div className="flex items-start gap-2">
<Container className="mt-0.5 size-4 shrink-0 text-muted-foreground" aria-hidden />
<div className="min-w-0 flex-1 space-y-1">
<p className="font-medium text-foreground">Configuration runtime (Docker Compose)</p>
<p className="text-muted-foreground">
Les services ci-dessous sont pilotés par les variables d&apos;environnement du
déploiement. Les interrupteurs correspondants dans l&apos;administration sont en
lecture seule.
</p>
<p className="text-muted-foreground">
Recherche <span className="font-medium text-foreground">{eff.search.suite_engine}</span>
{" · "}
Nextcloud {eff.nextcloud.enabled ? "actif" : "inactif"}
{" · "}
OnlyOffice {eff.onlyoffice.enabled ? "actif" : "inactif"}
{eff.immich ? (
<>
{" · "}
Immich {eff.immich.enabled ? "actif" : "inactif"}
</>
) : null}
{eff.jitsi ? (
<>
{" · "}
Jitsi {eff.jitsi.enabled ? "actif" : "inactif"}
</>
) : null}
</p>
</div>
<Badge variant="outline" className="shrink-0 gap-1">
<Lock className="size-3" aria-hidden />
Compose
</Badge>
</div>
<button
type="button"
className="flex w-full items-center gap-1.5 text-left font-medium text-foreground hover:underline"
onClick={() => setEnvOpen((v) => !v)}
>
{envOpen ? (
<ChevronDown className="size-4" aria-hidden />
) : (
<ChevronRight className="size-4" aria-hidden />
)}
Variables d&apos;environnement ({setCount} définies)
</button>
{envOpen ? (
<div className="space-y-4 border-t border-border/60 pt-3">
{Object.entries(envGroups).map(([group, vars]) => (
<div key={group}>
<p className="mb-2 font-medium text-foreground">{envGroupLabel(group)}</p>
<div className="overflow-x-auto rounded-md border bg-background/80">
<table className="w-full text-left">
<thead>
<tr className="border-b text-muted-foreground">
<th className="px-2 py-1.5 font-medium">Variable</th>
<th className="px-2 py-1.5 font-medium">Définie</th>
<th className="px-2 py-1.5 font-medium">Valeur</th>
</tr>
</thead>
<tbody>
{vars.map((v) => (
<tr key={v.name} className="border-b border-border/40 last:border-0">
<td className="px-2 py-1.5 font-mono text-[11px]">{v.name}</td>
<td className="px-2 py-1.5">
<Badge
variant={v.set ? "default" : "secondary"}
className={cn("text-[10px]", !v.set && "opacity-70")}
>
{v.set ? "oui" : "non"}
</Badge>
</td>
<td className="max-w-[200px] truncate px-2 py-1.5 font-mono text-[11px] text-muted-foreground">
{v.secret ? (v.set ? "••••••••" : "—") : (v.value ?? "—")}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
))}
</div>
) : null}
</div>
)
}