238 lines
7.4 KiB
TypeScript
238 lines
7.4 KiB
TypeScript
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<string, unknown>;
|
|
show_when_source_type?: Record<string, string[]>;
|
|
show_when_widget_value?: Record<string, unknown[]>;
|
|
show_when_input_visible?: string | string[];
|
|
hide_when_input_connected?: string | string[];
|
|
choices_by_source_type?: Record<string, string[]>;
|
|
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<string, InputSpec>;
|
|
optional: Record<string, InputSpec>;
|
|
};
|
|
output: string[];
|
|
output_name: string[];
|
|
output_paths?: string[];
|
|
output_accepted_types?: string[][];
|
|
category: string;
|
|
manual_trigger?: boolean;
|
|
}
|
|
|
|
export type NodeDefsRegistry = Record<string, NodeDefinition>;
|
|
|
|
// ── 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<string, unknown> {
|
|
label: string;
|
|
className: string;
|
|
definition?: NodeDefinition | null;
|
|
widgetValues: Record<string, unknown>;
|
|
runtimeValues?: Record<string, unknown>;
|
|
|
|
// Execution results
|
|
previewImage?: PreviewImage | null;
|
|
tableRows?: Array<Record<string, unknown>> | 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<string, unknown>;
|
|
output?: string[];
|
|
output_name?: string[];
|
|
}
|
|
|
|
// ── ReactFlow Node & Edge ────────────────────────────────────────────
|
|
|
|
export type TonoNode = Node<NodeData, 'custom'>;
|
|
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<string, unknown>;
|
|
runtimeValues?: Record<string, unknown>;
|
|
extraData?: Record<string, unknown>;
|
|
output?: string[];
|
|
output_name?: string[];
|
|
};
|
|
}
|
|
|
|
export interface SerializedEdge {
|
|
id: string;
|
|
source: string;
|
|
sourceHandle?: string;
|
|
target: string;
|
|
targetHandle?: string;
|
|
style?: CSSProperties;
|
|
hidden?: boolean;
|
|
data?: Record<string, unknown>;
|
|
}
|
|
|
|
export interface SerializedWorkflow {
|
|
version: number;
|
|
nodes: SerializedNode[];
|
|
edges: SerializedEdge[];
|
|
packed?: boolean;
|
|
packedFiles?: Record<string, { filename: string; data: string }>;
|
|
}
|
|
|
|
// ── 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<Record<string, unknown>> } }
|
|
| { 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<string, never> };
|
|
|
|
// ── 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[];
|
|
}
|