"use client"; import { useState, type KeyboardEvent, type MouseEvent, type ReactNode, type SyntheticEvent, } from "react"; import { IconX } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger, } from "@kandev/ui/drawer"; import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip"; import { useTouchDrawer } from "@/hooks/use-compact-task-chrome"; import { getExecutorStatusIcon } from "@/lib/executor-icons"; import { t } from "@/lib/i18n"; import { useRemoteExecutorStatus } from "@/hooks/domains/session/use-remote-executor-status"; import type { RemoteExecutorStatusData } from "@/hooks/domains/session/remote-executor-status-resource"; import { cn } from "@/lib/utils"; import { RemoteExecutorTaskStatusSummary } from "./remote-executor-task-status-summary"; import { useTaskIconTooltipState } from "./use-task-icon-tooltip-state"; type RemoteCloudTooltipProps = { taskId: string; sessionId?: string | null; executorId?: string | null; executorType?: string | null; fallbackName?: string | null; iconClassName?: string; /** When provided, uses this data directly instead of fetching via WS on hover. */ status?: RemoteExecutorStatusData | null; }; const CONNECTED_THRESHOLD_MS = 2 * 60 * 1000; function getCloudState(status: RemoteExecutorStatusData | null): "connected" | "error" | "stale" { if (status?.remote_status_error) return "error"; if (!status?.remote_checked_at) return "stale"; const elapsed = Date.now() - new Date(status.remote_checked_at).getTime(); if (elapsed < CONNECTED_THRESHOLD_MS) return "connected"; return "stale"; } const CLOUD_STATE_CLASSES: Record, string> = { error: "text-destructive", connected: "text-emerald-500", stale: "text-muted-foreground", }; type StatusTriggerProps = { touch: boolean; expanded: boolean; label: string; icon: ReturnType; iconClassName: string; cloudState: ReturnType; onPointerEnter?: ReturnType["onPointerEnter"]; onPointerLeave?: ReturnType["onPointerLeave"]; onFocus?: ReturnType["onFocus"]; onBlur?: ReturnType["onBlur"]; onTouchClick?: (event: MouseEvent) => void; onTouchKeyDown?: (event: KeyboardEvent) => void; }; function StatusTrigger({ touch, expanded, label, icon, iconClassName, cloudState, onPointerEnter, onPointerLeave, onFocus, onBlur, onTouchClick, onTouchKeyDown, }: StatusTriggerProps) { const Icon = icon.Icon; return ( ); } type StatusDisclosureProps = { label: string; remoteName: string; summary: ReactNode; icon: ReturnType; iconClassName: string; cloudState: ReturnType; onRefresh: () => void; }; function stopTaskRowInteraction(event: SyntheticEvent) { event.stopPropagation(); } function TouchStatusDisclosure({ label, remoteName, summary, icon, iconClassName, cloudState, onRefresh, }: StatusDisclosureProps) { const [open, setOpen] = useState(false); function show(event: MouseEvent | KeyboardEvent) { event.preventDefault(); event.stopPropagation(); setOpen(true); onRefresh(); } function handleKeyDown(event: KeyboardEvent) { if ((event.key === "Enter" || event.key === " ") && !event.repeat) show(event); } return (
{remoteName} {label}
{summary}
); } function FinePointerStatusTooltip({ label, summary, icon, iconClassName, cloudState, onRefresh, }: StatusDisclosureProps) { const tooltip = useTaskIconTooltipState(onRefresh); return ( {summary} ); } export function RemoteCloudTooltip({ taskId, sessionId, executorId, executorType, fallbackName, iconClassName = "h-3.5 w-3.5", status: externalStatus, }: RemoteCloudTooltipProps) { const hasExternalStatus = externalStatus !== undefined; const usesTouchDrawer = useTouchDrawer(); const live = useRemoteExecutorStatus( { executorId, executorType, taskId, sessionId: sessionId ?? "", }, !hasExternalStatus, ); const status = hasExternalStatus ? (externalStatus ?? null) : live.status; const remoteName = status?.remote_name ?? fallbackName ?? t("task:remoteExecutor"); const cloudState = getCloudState(status); const loading = live.loading; const icon = getExecutorStatusIcon(executorType, cloudState === "error"); const label = t("task:remoteExecutorStatus", { name: remoteName }); const summary = ( ); if (usesTouchDrawer) { return ( void live.refresh()} /> ); } return ( void live.refresh()} /> ); }