import { thisComputerReady, type ThisComputerPlatform, type ThisComputerStatus, } from "@opengeni/sdk/this-computer"; import { LaptopIcon, XIcon } from "lucide-react"; import { useCallback, useEffect, useState, type ReactNode } from "react"; import { useOpenGeniText } from "../../messages/runtime"; import { defaultThisComputerLabels, type ThisComputerLabels } from "./labels"; import type { UseThisComputerResult } from "./use-this-computer"; /** What the status pieces show for a computer, in order of what matters. */ export type ThisComputerView = | "hidden" | "off" | "setting_up" | "finish_setup" | "ready" | "reconnecting" | "paused" | "resuming"; export function thisComputerView(status: ThisComputerStatus | null): ThisComputerView { if (!status || status.state === "unavailable") return "hidden"; if (status.state === "paused") return status.busy ? "resuming" : "paused"; if (status.state === "connected") { if (!thisComputerReady(status)) return "finish_setup"; return status.reconnecting ? "reconnecting" : "ready"; } return status.busy ? "setting_up" : "off"; } function percent(status: ThisComputerStatus | null): string { return status?.setupProgress === undefined ? "" : ` ${Math.round(status.setupProgress * 100)}%`; } function storageKey(workspaceId: string) { return `opengeni.desktop.thisComputer.dismissed.${workspaceId}`; } /** "Not now" on the offer, remembered per workspace on this device. */ export function useThisComputerOfferDismissed(workspaceId: string): [boolean, () => void] { const read = useCallback(() => { try { return window.localStorage.getItem(storageKey(workspaceId)) === "1"; } catch { return false; } }, [workspaceId]); const [dismissed, setDismissed] = useState(read); useEffect(() => setDismissed(read()), [read]); const dismiss = useCallback(() => { try { window.localStorage.setItem(storageKey(workspaceId), "1"); } catch { // Hidden for this page only. } setDismissed(true); }, [workspaceId]); return [dismissed, dismiss]; } export interface ThisComputerOfferProps { computer: UseThisComputerResult; labels?: ThisComputerLabels; /** Opens `ThisComputerSetup`. */ onSetup(): void; /** The person chose "Not now" earlier; the offer stays away until set up. */ dismissed?: boolean; onDismiss?(): void; /** The mark beside the title; a laptop by default. */ icon?: ReactNode; className?: string | undefined; } /** * A small card for a sidebar or panel, only while there's something to do: * the offer to set up, setup in progress, finishing the permissions, or * resuming a paused computer. Shows nothing once it's ready. */ export function ThisComputerOffer({ computer, labels: given, onSetup, dismissed = false, onDismiss, icon, className, }: ThisComputerOfferProps) { const catalogText = useOpenGeniText(); const labels = given ?? defaultThisComputerLabels(catalogText); const { status } = computer; const view = thisComputerView(status); const machineName = status?.machineName ?? ""; const mark = icon ?? ; const classes = ["og-tc-offer", className].filter(Boolean).join(" "); if (view === "setting_up" || view === "resuming" || view === "reconnecting") { return (
{view === "resuming" ? labels.resuming : view === "reconnecting" ? labels.reconnecting(machineName) : `${labels.settingUp(machineName)}${percent(status)}`}
); } if (view === "paused") { return (
{mark} {labels.paused(machineName)}
); } if (view === "finish_setup") { return (
{mark}

{labels.finishSetup}

{labels.finishSetupDetail}

); } if (view !== "off" || dismissed) return null; return (
{mark}

{labels.title}

{labels.offer(machineName)}

{onDismiss ? ( ) : null}
); } export interface ThisComputerPanelProps { computer: UseThisComputerResult; platform: ThisComputerPlatform; labels?: ThisComputerLabels; /** Opens `ThisComputerSetup`. */ onSetup(): void; icon?: ReactNode; className?: string | undefined; } /** * The full control for a settings page: whether agents can use this * computer, and turning it on, finishing setup, pausing, resuming and * turning it off (after a confirmation). */ export function ThisComputerPanel({ computer, platform, labels: given, onSetup, icon, className, }: ThisComputerPanelProps) { const catalogText = useOpenGeniText(); const labels = given ?? defaultThisComputerLabels(catalogText); const { status } = computer; const view = thisComputerView(status); const [confirmingOff, setConfirmingOff] = useState(false); useEffect(() => { if (view !== "ready" && view !== "reconnecting" && view !== "paused" && view !== "finish_setup") setConfirmingOff(false); }, [view]); if (view === "hidden") return null; const machineName = status?.machineName ?? ""; const error = computer.actionError !== null || status?.error ? labels.error(status?.errorCode ?? null, status?.error || computer.actionError || null) : null; let line: string; let actions: ReactNode; switch (view) { case "ready": case "reconnecting": line = view === "ready" ? labels.ready(machineName) : labels.reconnecting(machineName); actions = ( ); break; case "paused": line = labels.paused(machineName); actions = ( ); break; case "resuming": line = labels.resuming; actions = ; break; case "finish_setup": line = labels.finishSetupDetail; actions = ( ); break; case "setting_up": line = `${labels.settingUp(machineName)}${percent(status)}`; actions = ; break; default: line = labels.offer(machineName); actions = ( ); } const connected = view === "ready" || view === "reconnecting" || view === "paused" || view === "finish_setup"; return (
{icon ?? }

{labels.title}

{line}

{actions}
{error ? (

{error}

) : null} {connected && computer.canDisconnect ? ( confirmingOff ? (

{labels.turnOffConfirm(machineName)}

) : (

{status?.management === "service" ? catalogText("thisComputer.servicePauseHint") : view === "paused" ? labels.resumeHint(platform) : labels.pauseHint(platform)}

) ) : null} {!connected && status?.management === "service" ? (

{catalogText("thisComputer.existingService")}

) : null}
); }