import type { ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { RefreshCw, AlertTriangle, Search } from "lucide-react"; import { Button } from "@/components/button"; import { MetricCard } from "@/components/metric-card"; export interface ManagerCardError { message: string; code?: string; } /** The frame a host manager card draws: title, refresh, error and empty states. */ export function ManagerCardShell({ title, icon, loading, error, onRefresh, empty, emptyMessage, children, headerExtra, }: { title: string; icon: ReactNode; loading: boolean; error: ManagerCardError | null; onRefresh: () => void; empty?: boolean; emptyMessage?: string; children: ReactNode; headerExtra?: ReactNode; }) { const { t } = useTranslation(); return ( {headerExtra} } > {error ? (
{error.message} {error.code === "SUDO_REQUIRED" && ( {t("managerCard.sudoHint")} )}
) : empty ? (
{emptyMessage ?? t("managerCard.noData")}
) : ( children )}
); } /** The filter box above a manager card's list. */ export function ManagerSearch({ value, onChange, placeholder, count, extra, }: { value: string; onChange: (value: string) => void; placeholder?: string; count?: number; extra?: ReactNode; }) { const { t } = useTranslation(); return (
onChange(e.target.value)} placeholder={placeholder ?? t("managerCard.filter")} className="h-7 w-full border border-border bg-background pl-7 pr-2 text-xs outline-none focus:ring-1 focus:ring-ring" />
{count != null && ( {count} )} {extra}
); }