11import p2pIcon from './assets/p2p.svg' ;
2- import React , { useState , useEffect , useCallback } from 'react' ;
2+ import React , { useState , useEffect , useCallback , useMemo } from 'react' ;
33import editorIcon from './assets/editor.svg' ;
44import visualizationIcon from './assets/visualization.svg' ;
55import 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