"use client"; /** * 裝置詳情 Client — /devices/[id] * * 對齊 pages.md §7 + flow-offline-handling.md §5。 * * F6 範圍: * - 頂部:返回 + 裝置名稱 + RemoteDeviceBadge + 操作按鈕 * - 離線 banner(remoteStatus=offline 時顯示) * - 裝置資訊 + 模型狀態 兩欄 Card * - 離線降級:燒錄 / 工作區按鈕 disabled * * F6 不做(保留 stub 或隱藏): * - FlashDialog(雲端版 flash 走 tunnel forward;F8 補完整流程) * - DeviceHealthCard / DeviceConnectionLog(Phase 1 完整化) * - DeviceSettingsCard(alias / notes — Phase 1 接後端) */ import { useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { AlertTriangle, ArrowLeft, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { RemoteDeviceBadge } from "@/components/cloud/remote-device-badge"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { useT } from "@/lib/i18n/context"; import { useDeviceStore } from "@/stores/device-store"; interface DeviceDetailClientProps { id: string; } export function DeviceDetailClient({ id }: DeviceDetailClientProps) { const t = useT(); const router = useRouter(); const selectedDevice = useDeviceStore((s) => s.selectedDevice); const isLoading = useDeviceStore((s) => s.isLoading); const fetchDevice = useDeviceStore((s) => s.fetchDevice); const unpairDevice = useDeviceStore((s) => s.unpairDevice); const isUnpairing = useDeviceStore((s) => s.unpairingId === id); useEffect(() => { if (id) void fetchDevice(id); }, [id, fetchDevice]); async function handleRemove() { const result = await unpairDevice(id); if (result.ok) { toast.success(t("devices.remove.toast.success")); router.push("/devices"); } else { // 用 backend code 對應 i18n;找不到對應 key 時退化到 unknown(對齊 model download toast)。 const key = `devices.remove.error.${result.code}`; const desc = t(key); toast.error(t("devices.remove.error.title"), { description: desc === key ? t("devices.remove.error.unknown") : desc, }); } } if (isLoading && !selectedDevice) { return (
{t("common.loading")}
{t("devices.detail.offlineBanner.title")}
{t("devices.detail.offlineBanner.description")}
{selectedDevice.name}
)}{t("devices.detail.readyForInference")}
{t("devices.detail.noModelFlashed")}
)}