@@ -20,9 +20,10 @@ interface NodeCardProps {
2020 nodeRegistry : any ;
2121 isPublic ?: boolean ; // Optional prop for public view mode
2222 graphId ?: string ; // Explicit graph id for actions
23+ onMorphChange ?: ( nodeId : string , morphId : string ) => void ; // Callback for morph changes
2324}
2425
25- export function NodeCard ( { node, allNodes, allRelations, attributes, isActive, onSelectNode, onImportContext, nodeRegistry, isPublic = false , graphId } : NodeCardProps ) {
26+ export function NodeCard ( { node, allNodes, allRelations, attributes, isActive, onSelectNode, onImportContext, nodeRegistry, isPublic = false , graphId, onMorphChange } : NodeCardProps ) {
2627 const cardRef = React . useRef < HTMLDivElement > ( null ) ;
2728 const subgraphSvgRef = React . useRef < string | null > ( null ) ;
2829 const registryEntry = nodeRegistry [ node . id ] ;
@@ -158,23 +159,15 @@ export function NodeCard({ node, allNodes, allRelations, attributes, isActive, o
158159 } ;
159160
160161 const handleMorphChange = async ( morphId : string ) => {
161- if ( ! graphId || isChangingMorph ) return ;
162+ if ( ! graphId || isChangingMorph || ! onMorphChange ) return ;
162163
163164 setIsChangingMorph ( true ) ;
164165 try {
165- const response = await authenticatedFetch ( `${ API_BASE_URL } /api/graphs/${ graphId } /nodes/${ node . id } /morph` , {
166- method : 'POST' ,
167- body : JSON . stringify ( { morphId } )
168- } ) ;
169-
170- if ( response . ok ) {
171- const result = await response . json ( ) ;
172- console . log ( `Changed to morph: ${ result . morphName } ` ) ;
173- // Refresh the page to show the updated morph
174- window . location . reload ( ) ;
175- } else {
176- throw new Error ( 'Failed to change morph' ) ;
177- }
166+ // Update the node's nbh property locally for immediate UI update
167+ node . nbh = morphId ;
168+
169+ // Notify parent component to handle the API call and refresh graph data
170+ await onMorphChange ( node . id , morphId ) ;
178171 } catch ( error ) {
179172 console . error ( 'Error changing morph:' , error ) ;
180173 alert ( 'Failed to change morph. See console for details.' ) ;
@@ -226,10 +219,16 @@ export function NodeCard({ node, allNodes, allRelations, attributes, isActive, o
226219 ) ;
227220 } ;
228221
229- // Calculate subgraph data
222+ // Backend should already filter attributes and relations by active morph
223+ // Use all attributes and relations since backend filtering is now handled by morph registry
224+ const filteredAttributes = attributes . filter ( attr => attr . source_id === node . id ) ;
225+ const filteredRelations = allRelations . filter ( rel => rel . source_id === node . id || rel . target_id === node . id ) ;
226+
227+ // Calculate subgraph data using Cytoscape's neighborhood concept
230228 const subgraphNodes = [ node ] ;
231- const subgraphRelations = allRelations . filter ( r => r . source_id === node . id || r . target_id === node . id ) ;
232- for ( const rel of subgraphRelations ) {
229+
230+ // Add related nodes (targets of outgoing relations and sources of incoming relations)
231+ for ( const rel of filteredRelations ) {
233232 const otherNodeId = rel . source_id === node . id ? rel . target_id : rel . source_id ;
234233 if ( ! subgraphNodes . find ( n => n . id === otherNodeId ) ) {
235234 const otherNode = allNodes . find ( n => n . id === otherNodeId ) ;
@@ -240,7 +239,18 @@ export function NodeCard({ node, allNodes, allRelations, attributes, isActive, o
240239 return (
241240 < div ref = { cardRef } className = { `node-card ${ isActive ? 'active' : '' } ` } >
242241 < div className = "node-card-header" >
243- < h3 > { node . name } </ h3 >
242+ < h3 >
243+ { ( ( ) => {
244+ // Show morph name if active morph is not basic
245+ if ( node . morphs && node . nbh ) {
246+ const activeMorph = node . morphs . find ( m => m . morph_id === node . nbh ) ;
247+ if ( activeMorph && activeMorph . name !== 'basic' ) {
248+ return `${ node . name } (${ activeMorph . name } )` ;
249+ }
250+ }
251+ return node . name ;
252+ } ) ( ) }
253+ </ h3 >
244254 < div className = "node-card-header-actions" >
245255 < button
246256 className = { `publication-toggle ${ node . publication_mode ?. toLowerCase ( ) } ` }
@@ -255,9 +265,10 @@ export function NodeCard({ node, allNodes, allRelations, attributes, isActive, o
255265
256266 < div className = "node-card-image" >
257267 < Subgraph
268+ key = { `subgraph-${ node . id } -${ node . nbh || 'default' } ` }
258269 nodes = { subgraphNodes }
259- relations = { subgraphRelations }
260- attributes = { attributes . filter ( a => a . source_id === node . id ) }
270+ relations = { filteredRelations }
271+ attributes = { filteredAttributes }
261272 onReady = { ( { exportSvg } ) => { subgraphSvgRef . current = exportSvg ( ) ; } }
262273 />
263274 </ div >
0 commit comments