Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
/**
* ╔═══════════════════════════════════════════════════════════════════════════╗
* β•‘ FLOWCHART VIEW COMPONENT β•‘
* ║═══════════════════════════════════════════════════════════════════════════║
* β•‘ Business process and decision flow visualization β•‘
* β•‘ Part of the Visual Cortex Layer β•‘
* β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
*/
import { useMemo } from 'react';
import { MermaidDiagram } from './MermaidDiagram';
import { cn } from '@/lib/utils';
export interface FlowNode {
id: string;
label: string;
type?: 'start' | 'end' | 'process' | 'decision' | 'data' | 'subprocess' | 'custom';
style?: string;
}
export interface FlowEdge {
from: string;
to: string;
label?: string;
style?: 'solid' | 'dashed' | 'thick';
}
export interface FlowSubgraph {
id: string;
label: string;
nodes: string[];
direction?: 'TB' | 'LR';
}
export interface FlowchartViewProps {
/** Flowchart title */
title?: string;
/** Nodes in the flowchart */
nodes: FlowNode[];
/** Edges connecting nodes */
edges: FlowEdge[];
/** Optional subgraphs for grouping */
subgraphs?: FlowSubgraph[];
/** Flow direction: TB (top-bottom), LR (left-right), BT, RL */
direction?: 'TB' | 'LR' | 'BT' | 'RL';
/** Custom class */
className?: string;
/** Callback when rendered */
onRender?: (svg: string) => void;
}
// Node type to Mermaid shape
const NODE_SHAPES: Record<string, { prefix: string; suffix: string }> = {
start: { prefix: '([', suffix: '])' }, // Stadium (rounded)
end: { prefix: '([', suffix: '])' }, // Stadium
process: { prefix: '[', suffix: ']' }, // Rectangle
decision: { prefix: '{', suffix: '}' }, // Diamond
data: { prefix: '[/', suffix: '/]' }, // Parallelogram
subprocess: { prefix: '[[', suffix: ']]' }, // Subroutine
custom: { prefix: '[', suffix: ']' }, // Rectangle
};
// Edge style to arrow
const EDGE_STYLES: Record<string, string> = {
solid: '-->',
dashed: '-.->',
thick: '==>',
};
export function FlowchartView({
title,
nodes,
edges,
subgraphs = [],
direction = 'TB',
className,
onRender,
}: FlowchartViewProps) {
const mermaidCode = useMemo(() => {
const lines: string[] = [`flowchart ${direction}`];
// Track nodes in subgraphs
const nodesInSubgraphs = new Set<string>();
subgraphs.forEach(sg => sg.nodes.forEach(n => nodesInSubgraphs.add(n)));
// Generate subgraphs
subgraphs.forEach(sg => {
const subDir = sg.direction ? ` direction ${sg.direction}` : '';
lines.push(` subgraph ${sg.id}["${sg.label}"]${subDir}`);
sg.nodes.forEach(nodeId => {
const node = nodes.find(n => n.id === nodeId);
if (node) {
const shape = NODE_SHAPES[node.type || 'process'];
lines.push(` ${node.id}${shape.prefix}"${node.label}"${shape.suffix}`);
}
});
lines.push(' end');
});
// Generate standalone nodes
nodes.forEach(node => {
if (!nodesInSubgraphs.has(node.id)) {
const shape = NODE_SHAPES[node.type || 'process'];
lines.push(` ${node.id}${shape.prefix}"${node.label}"${shape.suffix}`);
}
});
// Generate edges
edges.forEach(edge => {
const arrow = EDGE_STYLES[edge.style || 'solid'];
if (edge.label) {
lines.push(` ${edge.from} ${arrow}|"${edge.label}"| ${edge.to}`);
} else {
lines.push(` ${edge.from} ${arrow} ${edge.to}`);
}
});
// Add styling
lines.push('');
lines.push(' %% Styling');
// Style start/end nodes
const startNodes = nodes.filter(n => n.type === 'start').map(n => n.id);
const endNodes = nodes.filter(n => n.type === 'end').map(n => n.id);
const decisionNodes = nodes.filter(n => n.type === 'decision').map(n => n.id);
if (startNodes.length > 0) {
lines.push(` style ${startNodes.join(',')} fill:#22c55e,stroke:#16a34a,color:#fff`);
}
if (endNodes.length > 0) {
lines.push(` style ${endNodes.join(',')} fill:#ef4444,stroke:#dc2626,color:#fff`);
}
if (decisionNodes.length > 0) {
lines.push(` style ${decisionNodes.join(',')} fill:#f59e0b,stroke:#d97706,color:#000`);
}
return lines.join('\n');
}, [nodes, edges, subgraphs, direction]);
return (
<div className={cn('flowchart-view', className)}>
<MermaidDiagram
code={mermaidCode}
title={title}
theme="dark"
zoomable={true}
onRender={onRender}
/>
</div>
);
}
export default FlowchartView;