/* Copyright 2026 Marimo. All rights reserved. */ import { useAtomValue } from "jotai"; import { HourglassIcon, LockIcon, UnlinkIcon } from "lucide-react"; import React from "react"; import { Tooltip } from "@/components/ui/tooltip"; import { notebookScrollToRunning } from "@/core/cells/actions"; import { onlyScratchpadIsRunningAtom } from "@/core/cells/cells"; import { viewStateAtom } from "@/core/mode"; import { type ConnectionStatus, WebSocketClosedReason, WebSocketState, } from "@/core/websocket/types"; import { cn } from "@/utils/cn"; export const StatusOverlay: React.FC<{ connection: ConnectionStatus; isRunning: boolean; onReconnect?: () => void; }> = ({ connection, isRunning, onReconnect }) => { const { mode } = useAtomValue(viewStateAtom); const isClosed = connection.state === WebSocketState.CLOSED; const isOpen = connection.state === WebSocketState.OPEN; // Only KERNEL_DISCONNECTED is recoverable by a retry. Other terminal // reasons (MALFORMED_QUERY, KERNEL_STARTUP_ERROR) would deterministically // fail the same way; ALREADY_RUNNING is handled by `LockedIcon` below. const canReconnect = isClosed && connection.code === WebSocketClosedReason.KERNEL_DISCONNECTED; return ( <> {isClosed && !connection.canTakeover && }
{isOpen && isRunning && } {isClosed && !connection.canTakeover && ( )} {isClosed && connection.canTakeover && }
); }; const topLeftStatus = "print:hidden pointer-events-auto hover:cursor-pointer"; const DisconnectedIcon: React.FC<{ onReconnect?: () => void }> = ({ onReconnect, }) => { const disabled = !onReconnect; return ( {/* Wrapper span keeps the tooltip reachable when the button is disabled — a disabled ); }; const LockedIcon = () => (
); const RunningIcon = () => { const scratchpadOnly = useAtomValue(onlyScratchpadIsRunningAtom); const tooltip = scratchpadOnly ? "Scratchpad is running" : "Jump to running cell"; return (
); }; const NoiseBackground = () => ( <>
);