"use client"; import type { ReactNode } from "react"; import { IconDatabase, IconEdit, IconExternalLink, IconLayoutGrid, IconListDetails, IconShare3, IconSparkles, } from "@tabler/icons-react"; import { useTranslation } from "react-i18next"; import { controlSizingClassName } from "@kandev/ui/control-sizing"; import { Button } from "@kandev/ui/button"; import { MobilePickerSheet } from "@/components/task/mobile/mobile-picker-sheet"; import { PanelHeaderBarSplit } from "@/components/task/panel-primitives"; import { CanvasPage } from "@/components/plugins/canvas-page"; import { canvasCanEnableWorkspaceData, canvasHref, type Canvas, } from "@/lib/api/domains/canvas-api"; import { CanvasMobileActionsButton } from "./canvas-host-actions"; import { canvasLockHelp, canvasPromotionHelp } from "./canvas-host-desktop-actions"; export { CanvasHostDialogs, CanvasMobileActionsButton } from "./canvas-host-actions"; export { CanvasDesktopActions, CanvasDesktopOverflowActions, CanvasDesktopOverflowMenuItems, CanvasDesktopPrimaryAction, } from "./canvas-host-desktop-actions"; export type CanvasHostState = | "loading_metadata" | "pending_first_release" | "pending_permission" | "loading_runtime" | "ready" | "offline" | "invalid_release" | "unavailable" | "archived"; const STATE_COPY: Record = { loading_metadata: { title: "canvases:loadingCanvas", description: "canvases:loadingCanvasDescription", }, pending_first_release: { title: "canvases:pendingFirstRelease", description: "canvases:pendingFirstReleaseDescription", }, pending_permission: { title: "canvases:pendingPermission", description: "canvases:pendingPermissionDescription", }, loading_runtime: { title: "canvases:loadingRuntime", description: "canvases:loadingRuntimeDescription", }, ready: { title: "canvases:ready", description: "canvases:readyDescription" }, offline: { title: "canvases:offline", description: "canvases:offlineDescription" }, invalid_release: { title: "canvases:invalidRelease", description: "canvases:invalidReleaseDescription", }, unavailable: { title: "canvases:unavailable", description: "canvases:unavailableDescription" }, archived: { title: "canvases:archived", description: "canvases:archivedDescription" }, }; function MobileCanvasAction({ description, children, testId, }: { description: string; children: ReactNode; testId: string; }) { return (
{children}

{description}

); } export function CanvasHostBody({ canvasId, title, state, runtimeUrl, error, onRuntimeReady, onRuntimeError, onRetry, }: { canvasId: string; title: string; state: CanvasHostState; runtimeUrl: string | null; error: string | null; onRuntimeReady: () => void; onRuntimeError: () => void; onRetry: () => void; }) { const { t } = useTranslation(); return (
{(state === "loading_runtime" || state === "ready") && runtimeUrl ? ( <> {state === "ready" && ( {t(STATE_COPY.ready.title)} )} ) : ( )}
); } export function CanvasHostHeader({ title, dataScopeLabel, isMobile, menuOpen, onOpenActions, actions, renameAction, overflowActions, }: { title: string; dataScopeLabel?: string; isMobile: boolean; menuOpen: boolean; onOpenActions: () => void; actions?: ReactNode; renameAction?: ReactNode; overflowActions?: ReactNode; }) { return ( {title} {dataScopeLabel && ( {dataScopeLabel} )} {renameAction} } right={ <> {actions} {isMobile && ( )} } overflow={!isMobile ? overflowActions : undefined} overflowAt={520} /> ); } export function CanvasHostStatePanel({ state, error, onRetry, }: { state: CanvasHostState; error: string | null; onRetry: () => void; }) { const { t } = useTranslation(); const copy = STATE_COPY[state]; return (

{t(copy.title)}

{error || t(copy.description)}

{state !== "loading_metadata" && state !== "loading_runtime" && ( )}
); } function MobileCanvasPicker({ canvases, canvas, onSelectCanvas, t, }: { canvases: Canvas[]; canvas: Canvas | null; onSelectCanvas: (canvas: Canvas) => void; t: (key: string) => string; }) { return (

{t("canvases:canvases")}

{canvases.map((candidate) => ( ))}
); } function MobileCanvasEditAction({ canvas, editing, onEdit, t, }: { canvas: Canvas; editing: boolean; onEdit: () => void; t: (key: string) => string; }) { const lifecycleLocked = canvas.status === "archived" || canvas.status === "disabled"; return ( ); } function MobileCanvasReleasesAction({ onReleases, t, }: { onReleases: () => void; t: (key: string) => string; }) { return ( ); } function MobileCanvasPromoteAction({ canvas, lifecycleLocked, onPromote, t, }: { canvas: Canvas; lifecycleLocked: boolean; onPromote: () => void; t: (key: string) => string; }) { const promoteDisabled = lifecycleLocked || canvas.active_release_status !== "valid"; return ( ); } function MobileCanvasWorkspaceDataAction({ canvas, onEnable, t, }: { canvas: Canvas | null; onEnable?: () => void; t: (key: string) => string; }) { if (!canvas || !onEnable || !canvasCanEnableWorkspaceData(canvas)) return null; return ( ); } function MobileCanvasShareAction({ onShare, t, }: { onShare: () => void; t: (key: string) => string; }) { return ( ); } function MobileCanvasNewTabAction({ canvas, t }: { canvas: Canvas; t: (key: string) => string }) { return ( ); } export function MobileCanvasActions({ canvas, canvases, open, onOpenChange, onEdit, onPromote, onReleases, onShare, onRename, onEnableWorkspaceData, onSelectCanvas, editing, }: { canvas: Canvas | null; canvases: Canvas[]; open: boolean; onOpenChange: (open: boolean) => void; onEdit: () => void; onPromote: () => void; onReleases: () => void; onShare: () => void; onRename: () => void; onEnableWorkspaceData?: () => void; onSelectCanvas: (canvas: Canvas) => void; editing: boolean; }) { const { t } = useTranslation(); const lifecycleLocked = canvas?.status === "archived" || canvas?.status === "disabled"; return (
{canvases.length > 0 && ( )} {canvas && ( )} {canvas?.scope_kind === "workspace" && ( )} {canvas && } {canvas?.scope_kind === "task" && ( )} {canvas && }
); }