diff --git a/server/src/dashboard.html b/server/src/dashboard.html index b3cb711..9864acd 100644 --- a/server/src/dashboard.html +++ b/server/src/dashboard.html @@ -62,10 +62,7 @@
- - - -
+

Omni-Search

@@ -105,45 +102,54 @@ network.fit({ animation: { duration: 500, easingFunction: 'easeInOutQuad' } }); } - // Graph Initialization + // Graph Initialization let network = null; + let nodesData = new vis.DataSet(); + let edgesData = new vis.DataSet(); + async function loadGraph() { try { const res = await fetch('/api/graph'); const data = await res.json(); - const nodes = []; - const edges = []; + const newNodes = []; + const newEdges = []; const nodeIds = new Set(); for (const [name, entity] of Object.entries(data.entities)) { - nodes.push({ id: name, label: name, title: entity.observations.join('\n') }); + newNodes.push({ id: name, label: name, title: entity.observations.join('\n') }); nodeIds.add(name); } data.relations.forEach(r => { if (nodeIds.has(r.from) && nodeIds.has(r.to)) { - edges.push({ from: r.from, to: r.to, label: r.relationType, arrows: 'to' }); + newEdges.push({ id: r.from + '-' + r.to + '-' + r.relationType, from: r.from, to: r.to, label: r.relationType, arrows: 'to' }); } }); - const container = document.getElementById('network-container'); - const graphData = { nodes: new vis.DataSet(nodes), edges: new vis.DataSet(edges) }; - const options = { - nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } }, - edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } }, - physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } } - }; + // Sync nodes + const currentNodes = nodesData.getIds(); + const toRemoveNodes = currentNodes.filter(id => !nodeIds.has(id)); + nodesData.remove(toRemoveNodes); + nodesData.update(newNodes); + + // Sync edges + const currentEdges = edgesData.getIds(); + const newEdgeIds = new Set(newEdges.map(e => e.id)); + const toRemoveEdges = currentEdges.filter(id => !newEdgeIds.has(id)); + edgesData.remove(toRemoveEdges); + edgesData.update(newEdges); - if (network) { - network.setData(graphData); - } else { - network = new vis.Network(container, graphData, options); + if (!network) { + const container = document.getElementById('network-container'); + const options = { + nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } }, + edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } }, + physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } } + }; + network = new vis.Network(container, { nodes: nodesData, edges: edgesData }, options); } - } catch (err) { - console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "
Error loading graph: " + err.message + "
"; - } - } + } catch (err) { console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "
Error loading graph: " + err.message + "
"; } } // Kanban Board Initialization async function loadTasks() { @@ -228,3 +234,6 @@ + + +