From 5b07bd488748c0c9b18621002ef66b90ba94e2b6 Mon Sep 17 00:00:00 2001 From: dtoro Date: Sat, 7 Mar 2026 22:13:12 +0100 Subject: [PATCH] eventual rendfering --- src/components/graph/RenderingNode.tsx | 76 +++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/src/components/graph/RenderingNode.tsx b/src/components/graph/RenderingNode.tsx index 6fe64f8..ba2f358 100644 --- a/src/components/graph/RenderingNode.tsx +++ b/src/components/graph/RenderingNode.tsx @@ -88,40 +88,102 @@ export const RenderingNode = memo(function RenderingNode({ id, width, height }: const plantumlText = srcNode && srcNode.type === 'config' ? srcNode?.data?.plantuml ?? '' : '' const srcData = srcNode?.data ?? {} + /** Set of node IDs that can affect this render node (configs in the chain + variables/functions feeding them) */ + const connectedNodeIds = useMemo(() => { + const out = new Set() + const isReachable = (startId: string, targetId: string) => { + const q: string[] = [startId] + const seen = new Set([startId]) + while (q.length) { + const cur = q.shift()! + if (cur === targetId) return true + for (const e of edges) { + if (e.source === cur && !seen.has(e.target)) { + seen.add(e.target) + q.push(e.target) + } + } + } + return false + } + const resolveRef = (name: string) => { + const refName = name.replace(/\.(puml|html)$/, '').trim() + return nodes.find((n: any) => n.id === refName || n.data?.title === refName)?.id ?? refName + } + const getTemplateRefs = (content: string): string[] => { + const refs: string[] = [] + const extendMatch = content.match(/\{\%\s*extends\s+["']([^"']+)["']\s*\%\}/) + if (extendMatch) refs.push(extendMatch[1].trim()) + const includeRegex = /\{\%\s*include\s+["']([^"']+)["']\s*\%\}/g + let m + while ((m = includeRegex.exec(content)) !== null) refs.push(m[1].trim()) + const importRegex = /\{\%\s*import\s+["']([^"']+)["']\s+as\s+\w+\s*\%\}/g + while ((m = importRegex.exec(content)) !== null) refs.push(m[1].trim()) + return refs + } + const addConfigRefs = (nodeId: string, visited: Set) => { + if (visited.has(nodeId)) return + const node = nodes.find((n: any) => n.id === nodeId && n.type === 'config') + if (!node) return + visited.add(nodeId) + out.add(nodeId) + const content = String(node.data?.plantuml ?? '') + for (const ref of getTemplateRefs(content)) { + const refId = resolveRef(ref) + if (refId && nodes.some((n: any) => n.id === refId && n.type === 'config') && isReachable(refId, id)) + addConfigRefs(refId, visited) + } + } + const configVisited = new Set() + for (const nid of incomingIds) { + const node = nodes.find((n: any) => n.id === nid) + if (node?.type === 'config') addConfigRefs(nid, configVisited) + else out.add(nid) + } + for (const e of edges) { + if (out.has(e.target)) out.add(e.source) + } + return out + }, [nodes, edges, id, incomingIds]) + const configSignature = useMemo( () => nodes - .filter((n: any) => n.type === 'config') + .filter((n: any) => n.type === 'config' && connectedNodeIds.has(n.id)) .map((n: any) => `${n.id}:${n.data?.title ?? ''}:${n.data?.plantuml ?? ''}`) + .sort() .join('|'), - [nodes] + [nodes, connectedNodeIds] ) const edgesSignature = useMemo( () => edges + .filter((e: any) => connectedNodeIds.has(e.source) && (connectedNodeIds.has(e.target) || e.target === id)) .map((e: any) => `${e.source}->${e.target}`) .sort() .join('|'), - [edges] + [edges, connectedNodeIds, id] ) const variablesSignature = useMemo( () => nodes - .filter((n: any) => n.type === 'variable') + .filter((n: any) => n.type === 'variable' && connectedNodeIds.has(n.id)) .map((n: any) => `${n.id}:${n.data?.value}`) + .sort() .join('|'), - [nodes] + [nodes, connectedNodeIds] ) const functionsSignature = useMemo( () => nodes - .filter((n: any) => n.type === 'function') + .filter((n: any) => n.type === 'function' && connectedNodeIds.has(n.id)) .map((n: any) => `${n.id}:${n.data?.body ?? ''}`) + .sort() .join('|'), - [nodes] + [nodes, connectedNodeIds] ) useEffect(() => {