import type { Node, Edge } from '@xyflow/react'; import type { CSSProperties } from 'react'; // ── Input Specifications ───────────────────────────────────────────── export interface InputOptions { label?: string; hidden?: boolean; socket_only?: boolean; accepted_types?: string[]; default?: unknown; placeholder?: string; min?: number; max?: number; step?: number; slider?: boolean; min_widget?: string; max_widget?: string; text_input?: boolean; color_picker?: boolean; colormap_stops?: boolean; top_socket_input?: string | string[]; set_widgets?: Record; show_when_source_type?: Record; show_when_widget_value?: Record; show_when_input_visible?: string | string[]; hide_when_input_connected?: string | string[]; choices_by_source_type?: Record; choices_from_table_input?: string; choices_from_measure_input?: string; inline_with_input?: string | [string]; source_type_input?: string; placement?: 'top'; } /** An input spec is either a bare type string, or a [type, opts] tuple. */ export type InputSpec = string | [type: string | string[], opts?: InputOptions]; // ── Node Definition (from GET /nodes) ──────────────────────────────── export interface NodeDefinition { input: { required: Record; optional: Record; }; output: string[]; output_name: string[]; output_paths?: string[]; output_accepted_types?: string[][]; category: string; manual_trigger?: boolean; } export type NodeDefsRegistry = Record; // ── Overlay Types ──────────────────────────────────────────────────── export interface OverlayData { kind: string; image?: string; image_width?: number; image_height?: number; x1?: number; y1?: number; x2?: number; y2?: number; xm?: number; ym?: number; a_locked?: boolean; b_locked?: boolean; section_title?: string; line?: number[]; shape?: string; stroke_color?: string; stroke_width?: number; angle_deg?: number; color?: string; label_dx?: number; label_dy?: number; line_thickness?: number; histogram?: unknown; } // ── Preview Image Types ────────────────────────────────────────────── export interface PreviewPanel { kind: 'image' | 'line_plot'; title?: string; image?: string; line?: number[]; fallback_image?: string; } export interface PreviewPayload { kind: 'image' | 'line_plot' | 'layer_gallery' | 'panels'; image?: string; line?: number[]; layers?: Array<{ name?: string; image: string }>; fallback_image?: string; panels?: PreviewPanel[]; } export type PreviewImage = string | PreviewPayload; // ── Node Data (attached to each ReactFlow node) ────────────────────── export interface GroupProxy { handleId: string; type: string; label: string; name: string; } export interface NodeData extends Record { label: string; className: string; definition?: NodeDefinition | null; widgetValues: Record; runtimeValues?: Record; // Execution results previewImage?: PreviewImage | null; tableRows?: Array> | null; scalarValue?: number | { value: number | string; unit?: string } | null; meshData?: unknown; overlay?: OverlayData | null; // Status error?: string | null; warning?: string | null; processingTimeMs?: number | null; // Group node fields proxyInputs?: GroupProxy[]; proxyOutputs?: GroupProxy[]; childCount?: number; collapsed?: boolean; expandedSize?: { width: number; height: number }; // Serialization extras extraData?: Record; output?: string[]; output_name?: string[]; } // ── ReactFlow Node & Edge ──────────────────────────────────────────── export type TonoNode = Node; export type TonoEdge = Edge<{ groupProxyOwner?: string; groupProxyOriginal?: { source?: string; sourceHandle?: string; target?: string; targetHandle?: string; }; }>; // ── Serialized Workflow ────────────────────────────────────────────── export interface SerializedNode { id: string; type?: string; position: { x: number; y: number }; width?: number; height?: number; className?: string; parentId?: string; extent?: [[number, number], [number, number]]; hidden?: boolean; style?: CSSProperties; dragHandle?: string; data: { label: string; className: string; widgetValues: Record; runtimeValues?: Record; extraData?: Record; output?: string[]; output_name?: string[]; }; } export interface SerializedEdge { id: string; source: string; sourceHandle?: string; target: string; targetHandle?: string; style?: CSSProperties; hidden?: boolean; data?: Record; } export interface SerializedWorkflow { version: number; nodes: SerializedNode[]; edges: SerializedEdge[]; packed?: boolean; packedFiles?: Record; } // ── WebSocket Messages ─────────────────────────────────────────────── export type WsMessage = | { type: 'execution_start'; data: { prompt_id: string } } | { type: 'executing'; data: { node: string; prompt_id: string } } | { type: 'execution_complete'; data: { prompt_id: string } } | { type: 'execution_error'; data: { node_id: string; message: string } } | { type: 'preview'; data: { node_id: string; image: PreviewImage } } | { type: 'table'; data: { node_id: string; rows: Array> } } | { type: 'scalar'; data: { node_id: string; value: number | string; unit?: string } } | { type: 'node_timing'; data: { node_id: string; elapsed_ms: number } } | { type: 'mesh3d'; data: { node_id: string; mesh: unknown } } | { type: 'overlay'; data: { node_id: string; overlay: OverlayData } } | { type: 'node_warning'; data: { node_id: string; message: string } } | { type: 'nodes_updated'; data: Record }; // ── Widget description (used by nodeWidgetLayout) ──────────────────── export interface WidgetDescriptor { name: string; type: string | string[]; opts: InputOptions; socketType?: string; } // ── Node Context (provided by App to CustomNode) ───────────────────── export interface NodeContextValue { executingNodeId: string | null; onWidgetChange: (nodeId: string, name: string, value: unknown) => void; openFileBrowser: (callback: (files: File[]) => void, options?: unknown) => void; openHelp: (label: string) => void; getTableColumns: (nodeId: string, inputName: string) => string[]; getMeasurementChoices: (nodeId: string, inputName: string) => string[]; }