Skip to content

Commit de2bb2e

Browse files
committed
fix simulation of transitions in nodecard
1 parent f877c1a commit de2bb2e

1 file changed

Lines changed: 190 additions & 29 deletions

File tree

nodebook-base/frontend/src/App.tsx

Lines changed: 190 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import p2pIcon from './assets/p2p.svg';
2-
import React, { useState, useEffect, useCallback } from 'react';
2+
import React, { useState, useEffect, useCallback, useMemo } from 'react';
33
import editorIcon from './assets/editor.svg';
44
import visualizationIcon from './assets/visualization.svg';
55
import jsonDataIcon from './assets/jsonData.svg';
@@ -246,6 +246,62 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
246246

247247
return { relations: morphRelations, attributes: morphAttributes };
248248
};
249+
250+
// Memoized function to build complete graph data based on current morph states
251+
const graphDataFromMorphStates = useMemo(() => {
252+
console.log(`[App] Building graph data from morph states (memoized)`);
253+
254+
// Use raw data if available, otherwise fall back to main graph data
255+
const allNodes = rawGraphData ? rawGraphData.nodes : nodes;
256+
const allRelations = rawGraphData ? rawGraphData.relations : relations;
257+
const allAttributes = rawGraphData ? rawGraphData.attributes : attributes;
258+
259+
const filteredRelations: Edge[] = [];
260+
const filteredAttributes: Attribute[] = [];
261+
262+
// Get all relations and attributes that belong to active morphs
263+
allNodes.forEach(node => {
264+
if (node.nbh && node.morphs) {
265+
const activeMorph = node.morphs.find(m => m.morph_id === node.nbh);
266+
if (activeMorph) {
267+
// Add relations for this morph
268+
if (activeMorph.relationNode_ids) {
269+
const morphRelations = activeMorph.relationNode_ids
270+
.map(relId => allRelations.find(rel => rel.id === relId))
271+
.filter(Boolean) as Edge[];
272+
filteredRelations.push(...morphRelations);
273+
}
274+
275+
// Add attributes for this morph
276+
if (activeMorph.attributeNode_ids) {
277+
const morphAttributes = activeMorph.attributeNode_ids
278+
.map(attrId => allAttributes.find(attr => attr.id === attrId))
279+
.filter(Boolean) as Attribute[];
280+
filteredAttributes.push(...morphAttributes);
281+
}
282+
}
283+
}
284+
});
285+
286+
// Remove duplicates
287+
const uniqueRelations = filteredRelations.filter((rel, index, self) =>
288+
index === self.findIndex(r => r.id === rel.id)
289+
);
290+
const uniqueAttributes = filteredAttributes.filter((attr, index, self) =>
291+
index === self.findIndex(a => a.id === attr.id)
292+
);
293+
294+
console.log(`[App] Built graph data from morph states:`, {
295+
relationsCount: uniqueRelations.length,
296+
attributesCount: uniqueAttributes.length
297+
});
298+
299+
return {
300+
nodes: allNodes,
301+
relations: uniqueRelations,
302+
attributes: uniqueAttributes
303+
};
304+
}, [rawGraphData, nodes, relations, attributes]);
249305

250306
// Debug effect to log data being passed to components
251307
useEffect(() => {
@@ -285,7 +341,7 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
285341

286342
setNodes(updatedNodes);
287343

288-
// Update the in-memory graph nodes (but keep relations/attributes unchanged)
344+
// Update the in-memory graph with filtered relations and attributes based on new morph states
289345
setInMemoryGraph(prevGraph => {
290346
if (!prevGraph) {
291347
console.log('[App] No in-memory graph to update, creating new one');
@@ -296,23 +352,64 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
296352
};
297353
}
298354

299-
console.log('[App] Updating in-memory graph with morph change');
355+
console.log('[App] Updating in-memory graph with morph change and filtering relations/attributes');
300356

301-
// Only update the specific node's morph, keep everything else unchanged
357+
// Update the specific node's morph
302358
const updatedInMemoryNodes = prevGraph.nodes.map(node =>
303359
node.id === nodeId
304360
? { ...node, nbh: morphId }
305361
: node
306362
);
307363

364+
// Filter relations and attributes based on all nodes' current morph states
365+
const filteredRelations: Edge[] = [];
366+
const filteredAttributes: Attribute[] = [];
367+
368+
// Get all relations and attributes that belong to active morphs
369+
updatedInMemoryNodes.forEach(node => {
370+
if (node.nbh && node.morphs) {
371+
const activeMorph = node.morphs.find(m => m.morph_id === node.nbh);
372+
if (activeMorph) {
373+
// Add relations for this morph
374+
if (activeMorph.relationNode_ids) {
375+
const morphRelations = activeMorph.relationNode_ids
376+
.map(relId => relations.find(rel => rel.id === relId))
377+
.filter(Boolean) as Edge[];
378+
filteredRelations.push(...morphRelations);
379+
}
380+
381+
// Add attributes for this morph
382+
if (activeMorph.attributeNode_ids) {
383+
const morphAttributes = activeMorph.attributeNode_ids
384+
.map(attrId => attributes.find(attr => attr.id === attrId))
385+
.filter(Boolean) as Attribute[];
386+
filteredAttributes.push(...morphAttributes);
387+
}
388+
}
389+
}
390+
});
391+
392+
// Remove duplicates
393+
const uniqueRelations = filteredRelations.filter((rel, index, self) =>
394+
index === self.findIndex(r => r.id === rel.id)
395+
);
396+
const uniqueAttributes = filteredAttributes.filter((attr, index, self) =>
397+
index === self.findIndex(a => a.id === attr.id)
398+
);
399+
400+
console.log(`[App] Filtered relations/attributes for morph change:`, {
401+
relationsCount: uniqueRelations.length,
402+
attributesCount: uniqueAttributes.length
403+
});
404+
308405
return {
309406
nodes: updatedInMemoryNodes,
310-
relations: prevGraph.relations, // Keep relations unchanged
311-
attributes: prevGraph.attributes // Keep attributes unchanged
407+
relations: uniqueRelations,
408+
attributes: uniqueAttributes
312409
};
313410
});
314411

315-
console.log(`[App] Morph change completed successfully (node-specific update)`);
412+
console.log(`[App] Morph change completed successfully (with relation/attribute filtering)`);
316413
};
317414

318415
/**
@@ -437,19 +534,18 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
437534

438535
setNodes(updatedNodes);
439536

440-
// Update in-memory graph with morph changes and proper filtering
537+
// Update in-memory graph with morph changes using direct retrieval (no filtering)
441538
setInMemoryGraph(prevGraph => {
442539
if (!prevGraph) {
443-
// Create new in-memory graph from current state with filtering
444-
const filtered = filterByActiveMorphs(updatedNodes);
540+
console.log('[App] Creating new in-memory graph for transition simulation');
445541
return {
446542
nodes: updatedNodes,
447-
relations: filtered.relations,
448-
attributes: filtered.attributes
543+
relations: relations, // Keep original relations
544+
attributes: attributes // Keep original attributes
449545
};
450546
}
451547

452-
// Update nodes with new morph states and apply filtering
548+
// Update nodes with new morph states
453549
const updatedInMemoryNodes = prevGraph.nodes.map(node => {
454550
const mapping = stateMapping.find(m => m.priorNode === node.id);
455551
if (mapping && mapping.targetMorph) {
@@ -458,12 +554,51 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
458554
return node;
459555
});
460556

461-
const filtered = filterByActiveMorphs(updatedInMemoryNodes);
557+
// Filter relations and attributes based on all nodes' current morph states
558+
const filteredRelations: Edge[] = [];
559+
const filteredAttributes: Attribute[] = [];
560+
561+
// Get all relations and attributes that belong to active morphs
562+
updatedInMemoryNodes.forEach(node => {
563+
if (node.nbh && node.morphs) {
564+
const activeMorph = node.morphs.find(m => m.morph_id === node.nbh);
565+
if (activeMorph) {
566+
// Add relations for this morph
567+
if (activeMorph.relationNode_ids) {
568+
const morphRelations = activeMorph.relationNode_ids
569+
.map(relId => relations.find(rel => rel.id === relId))
570+
.filter(Boolean) as Edge[];
571+
filteredRelations.push(...morphRelations);
572+
}
573+
574+
// Add attributes for this morph
575+
if (activeMorph.attributeNode_ids) {
576+
const morphAttributes = activeMorph.attributeNode_ids
577+
.map(attrId => attributes.find(attr => attr.id === attrId))
578+
.filter(Boolean) as Attribute[];
579+
filteredAttributes.push(...morphAttributes);
580+
}
581+
}
582+
}
583+
});
584+
585+
// Remove duplicates
586+
const uniqueRelations = filteredRelations.filter((rel, index, self) =>
587+
index === self.findIndex(r => r.id === rel.id)
588+
);
589+
const uniqueAttributes = filteredAttributes.filter((attr, index, self) =>
590+
index === self.findIndex(a => a.id === attr.id)
591+
);
592+
593+
console.log(`[App] Transition simulation filtered relations/attributes:`, {
594+
relationsCount: uniqueRelations.length,
595+
attributesCount: uniqueAttributes.length
596+
});
462597

463598
return {
464599
nodes: updatedInMemoryNodes,
465-
relations: filtered.relations,
466-
attributes: filtered.attributes
600+
relations: uniqueRelations,
601+
attributes: uniqueAttributes
467602
};
468603
});
469604

@@ -723,7 +858,26 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
723858
// Recalculate score when graph data changes
724859
useEffect(() => {
725860
if (nodes.length > 0 || relations.length > 0 || attributes.length > 0) {
726-
const score = calculateGraphScore(nodes, relations, attributes);
861+
// Convert Attribute instances to graphScoring AttributeType format
862+
const attributeTypes = attributes.map(attr => ({
863+
id: attr.id,
864+
name: attr.name,
865+
value: String(attr.value),
866+
unit: undefined, // Attribute interface doesn't have unit property
867+
source_id: attr.source_id
868+
}));
869+
870+
// Convert Node instances to graphScoring Node format
871+
const scoringNodes = nodes.map(node => ({
872+
id: node.id,
873+
name: node.name,
874+
role: node.role,
875+
description: node.description || undefined, // Convert null to undefined
876+
adjective: node.adjective,
877+
quantifier: node.quantifier
878+
}));
879+
880+
const score = calculateGraphScore(scoringNodes, relations, attributeTypes);
727881
setGraphScore(score);
728882
}
729883
}, [nodes, relations, attributes]);
@@ -1046,7 +1200,7 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
10461200
})()}
10471201
graphId={activeGraphId}
10481202
graphMode={graphMode}
1049-
onGraphModeChange={setGraphMode}
1203+
onGraphModeChange={(mode: string) => setGraphMode(mode as 'markdown' | 'mindmap' | 'richgraph' | 'strictgraph')}
10501204
onVersionControlOpen={() => setIsVersionControlOpen(true)}
10511205
enableCollaboration={enableCollaboration}
10521206
onCollaborationToggle={setEnableCollaboration}
@@ -1102,7 +1256,11 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
11021256
isVersionControlOpen={isVersionControlOpen}
11031257
onVersionControlOpen={() => setIsVersionControlOpen(true)}
11041258
onVersionControlClose={() => setIsVersionControlOpen(false)}
1105-
onInsertText={handleInsertTextFunction}
1259+
onInsertText={(text: string) => {
1260+
if (insertTextFunction) {
1261+
insertTextFunction(text);
1262+
}
1263+
}}
11061264
/>
11071265

11081266
{/* Score widget at bottom of Editor */}
@@ -1138,10 +1296,10 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
11381296
) : (
11391297
<>
11401298
<Visualization
1141-
key={`viz-${activeGraphId}-${(inMemoryGraph?.nodes || nodes).map(n => `${n.id}-${n.nbh || 'default'}`).join('-')}`}
1142-
nodes={inMemoryGraph?.nodes || nodes}
1143-
relations={inMemoryGraph?.relations || relations}
1144-
attributes={inMemoryGraph?.attributes || attributes}
1299+
key={`viz-${activeGraphId}-${nodes.map(n => `${n.id}-${n.nbh || 'default'}`).join('-')}`}
1300+
nodes={graphDataFromMorphStates.nodes}
1301+
relations={graphDataFromMorphStates.relations}
1302+
attributes={graphDataFromMorphStates.attributes}
11451303
onNodeSelect={handleNodeSelect}
11461304
onMorphChange={handleMorphChange}
11471305
graphMode={graphMode === 'strictgraph' ? 'richgraph' : graphMode}
@@ -1228,7 +1386,11 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
12281386
isVersionControlOpen={isVersionControlOpen}
12291387
onVersionControlOpen={() => setIsVersionControlOpen(true)}
12301388
onVersionControlClose={() => setIsVersionControlOpen(false)}
1231-
onInsertText={handleInsertTextFunction}
1389+
onInsertText={(text: string) => {
1390+
if (insertTextFunction) {
1391+
insertTextFunction(text);
1392+
}
1393+
}}
12321394
/>
12331395
</div>
12341396
)}
@@ -1237,10 +1399,10 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
12371399
{viewMode === 'visualization' && (
12381400
<div className={styles.visualizationWrapper}>
12391401
<Visualization
1240-
key={`viz-full-${activeGraphId}-${(inMemoryGraph?.nodes || nodes).map(n => `${n.id}-${n.nbh || 'default'}`).join('-')}`}
1241-
nodes={inMemoryGraph?.nodes || nodes}
1242-
relations={inMemoryGraph?.relations || relations}
1243-
attributes={inMemoryGraph?.attributes || attributes}
1402+
key={`viz-full-${activeGraphId}-${nodes.map(n => `${n.id}-${n.nbh || 'default'}`).join('-')}`}
1403+
nodes={graphDataFromMorphStates.nodes}
1404+
relations={graphDataFromMorphStates.relations}
1405+
attributes={graphDataFromMorphStates.attributes}
12441406
onNodeSelect={handleNodeSelect}
12451407
onMorphChange={handleMorphChange}
12461408
graphMode={graphMode === 'strictgraph' ? 'richgraph' : (graphMode === 'markdown' ? 'richgraph' : graphMode)}
@@ -1343,7 +1505,6 @@ function App({ onLogout, onGoToDashboard, user }: AppProps) {
13431505
onClose={() => setIsNLPPanelOpen(false)}
13441506
analysisResults={nlpAnalysisResults}
13451507
isLoading={isNLPLoading}
1346-
error={nlpError}
13471508
/>
13481509
)}
13491510

0 commit comments

Comments
 (0)