feat(service-storage-harness): slice 2 — qbit widgets + LineSeriesChart extract
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { SectionCard } from "../components/SectionCard";
|
||||
import { useWidgetData } from "../hooks/useWidgets";
|
||||
import type { WidgetInstance } from "../types";
|
||||
|
||||
interface Props {
|
||||
widget: WidgetInstance;
|
||||
refreshIntervalMs: number;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function QbittorrentTotalsWidget({
|
||||
widget,
|
||||
refreshIntervalMs,
|
||||
description,
|
||||
}: Props) {
|
||||
const { data, isLoading } = useWidgetData(widget.id, refreshIntervalMs);
|
||||
const payload = data?.data as
|
||||
| { total?: number; by_state?: Record<string, number> }
|
||||
| undefined;
|
||||
|
||||
return (
|
||||
<SectionCard title={widget.title} description={description}>
|
||||
{isLoading && !data ? (
|
||||
<Skeleton className="h-20 w-full" />
|
||||
) : data?.error ? (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{data.error}</AlertDescription>
|
||||
</Alert>
|
||||
) : payload ? (
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<div className="text-3xl font-semibold">{payload.total ?? 0}</div>
|
||||
<div className="text-xs text-muted-foreground">Total torrents</div>
|
||||
</div>
|
||||
{payload.by_state && Object.keys(payload.by_state).length > 0 ? (
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{Object.entries(payload.by_state).map(([state, count]) => (
|
||||
<Badge key={state} variant="secondary">
|
||||
{state}: {count}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</SectionCard>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user