Files
zui/frontend/src/app/canvas/canvasGraphUtils.ts
2026-03-12 21:01:43 +01:00

85 lines
2.7 KiB
TypeScript

/**
* Canvas graph: example graph and initial graph from storage.
* Used by useCanvasGraph and CanvasPage (e.g. Load example).
*/
import type { AppNode, AppEdge } from '@/lib/graph/nodeTypes'
import { DEFAULT_NODE_STYLE } from '@/lib/graph/flowUtils'
import { loadGraphFromStorage } from '@/app/pleroma/projectGraphStorage'
/** Ensure each edge has data.targetType from the target node (for labels without depending on nodes in edgesForFlow). */
export function backfillEdgeTargetTypes(
nodes: AppNode[],
edges: AppEdge[]
): AppEdge[] {
const typeById = new Map(nodes.map((n) => [n.id, n.type ?? '']))
return edges.map((e) => {
const targetType = typeById.get(e.target) ?? (e.data as Record<string, unknown>)?.targetType ?? ''
const data = typeof e.data === 'object' && e.data !== null ? (e.data as Record<string, unknown>) : {}
if (data.targetType === targetType) return e
return { ...e, data: { ...data, targetType } }
})
}
const NODE_GAP = 150
const EXAMPLE_NODES: AppNode[] = [
{
id: 'var_001',
position: { x: 50, y: 100 },
data: { value: 'Zoe', valueType: 'string' as const },
type: 'variable',
style: DEFAULT_NODE_STYLE.variable,
},
{
id: 'cfg_001',
position: { x: 50 + DEFAULT_NODE_STYLE.variable.width + NODE_GAP, y: 50 },
data: {
plantuml: '@startuml\nactor User\nparticipant "{{ var_001 }}" as R\nUser -> R : loves\n@enduml\n',
title: 'config-cfg_001',
},
type: 'config',
style: DEFAULT_NODE_STYLE.config,
},
{
id: 'rnd_001',
position: {
x: 50 + DEFAULT_NODE_STYLE.variable.width + NODE_GAP + DEFAULT_NODE_STYLE.config.width + NODE_GAP,
y: 50,
},
data: {},
type: 'render',
style: DEFAULT_NODE_STYLE.render,
},
]
const EXAMPLE_EDGES: AppEdge[] = [
{ id: 'e-var_001-cfg_001', source: 'var_001', target: 'cfg_001', type: 'animated' },
{ id: 'e-cfg_001-rnd_001', source: 'cfg_001', target: 'rnd_001', type: 'animated' },
]
export function getExampleGraph(): { nodes: AppNode[]; edges: AppEdge[] } {
const nodes = EXAMPLE_NODES.map((n) => ({
...n,
data: n.data && typeof n.data === 'object' ? { ...(n.data as object) } : n.data,
}))
const edges = backfillEdgeTargetTypes(
nodes,
EXAMPLE_EDGES.map((e) => ({ ...e }))
)
return { nodes, edges }
}
export function getInitialGraph(projectId: string | undefined): { nodes: AppNode[]; edges: AppEdge[] } {
if (projectId) {
const stored = loadGraphFromStorage(projectId)
if (stored && (stored.nodes.length > 0 || stored.edges.length > 0)) {
const nodes = stored.nodes as AppNode[]
const edges = backfillEdgeTargetTypes(nodes, stored.edges as AppEdge[])
return { nodes, edges }
}
return { nodes: [], edges: [] }
}
return getExampleGraph()
}