fix(dashboard): use vis.DataSet diffing to maintain zoom and physics simulation, and fix broken right-column flex HTML markup
This commit is contained in:
1 parent
981a49327c
commit
5d37af1d74
1 file changed
+27
-18
+27
-18
@@ -62,10 +62,7 @@
|
|||||||
<button onclick="resetGraph()" title="Reset View">⌂</button>
|
<button onclick="resetGraph()" title="Reset View">⌂</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="network-container"></div>
|
<div id="network-container"></div>
|
||||||
</div>
|
</div><div class="right-column">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="right-column">
|
|
||||||
<div class="panel search-panel">
|
<div class="panel search-panel">
|
||||||
<h2>Omni-Search</h2>
|
<h2>Omni-Search</h2>
|
||||||
<input type="text" id="search-box" placeholder="Search memory (e.g., 'database')..." onkeyup="handleSearch(event)">
|
<input type="text" id="search-box" placeholder="Search memory (e.g., 'database')..." onkeyup="handleSearch(event)">
|
||||||
@@ -107,43 +104,52 @@
|
|||||||
|
|
||||||
// Graph Initialization
|
// Graph Initialization
|
||||||
let network = null;
|
let network = null;
|
||||||
|
let nodesData = new vis.DataSet();
|
||||||
|
let edgesData = new vis.DataSet();
|
||||||
|
|
||||||
async function loadGraph() {
|
async function loadGraph() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/graph');
|
const res = await fetch('/api/graph');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
const nodes = [];
|
const newNodes = [];
|
||||||
const edges = [];
|
const newEdges = [];
|
||||||
const nodeIds = new Set();
|
const nodeIds = new Set();
|
||||||
|
|
||||||
for (const [name, entity] of Object.entries(data.entities)) {
|
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);
|
nodeIds.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.relations.forEach(r => {
|
data.relations.forEach(r => {
|
||||||
if (nodeIds.has(r.from) && nodeIds.has(r.to)) {
|
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' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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) {
|
||||||
const container = document.getElementById('network-container');
|
const container = document.getElementById('network-container');
|
||||||
const graphData = { nodes: new vis.DataSet(nodes), edges: new vis.DataSet(edges) };
|
|
||||||
const options = {
|
const options = {
|
||||||
nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } },
|
nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } },
|
||||||
edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } },
|
edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } },
|
||||||
physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } }
|
physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } }
|
||||||
};
|
};
|
||||||
|
network = new vis.Network(container, { nodes: nodesData, edges: edgesData }, options);
|
||||||
if (network) {
|
|
||||||
network.setData(graphData);
|
|
||||||
} else {
|
|
||||||
network = new vis.Network(container, graphData, options);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "<div style=\"color:red;padding:20px;\">Error loading graph: " + err.message + "</div>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} catch (err) { console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "<div style=`"color:red;padding:20px;`">Error loading graph: " + err.message + "</div>"; } }
|
||||||
|
|
||||||
// Kanban Board Initialization
|
// Kanban Board Initialization
|
||||||
async function loadTasks() {
|
async function loadTasks() {
|
||||||
@@ -228,3 +234,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user