@@ -106,6 +106,10 @@ function computeContainerBounds(containers, visibleItems, positions) {
106106
107107function buildAutoPositions ( items , edges , containers , hiddenIds , basePositions ) {
108108 const visibleItems = items . filter ( ( item ) => ! hiddenIds . has ( item . id ) ) ;
109+ const subnetContainer = containers . find ( ( c ) => c . type === 'subnet' ) ;
110+ const subnetNodeIds = new Set ( subnetContainer ? subnetContainer . members : [ ] ) ;
111+ const graphItems = visibleItems . filter ( ( item ) => ! subnetNodeIds . has ( item . id ) ) ;
112+ const subnetItems = visibleItems . filter ( ( item ) => subnetNodeIds . has ( item . id ) ) ;
109113 const g = new dagre . graphlib . Graph ( { compound : true } ) ;
110114 g . setGraph ( {
111115 rankdir : 'TB' ,
@@ -116,12 +120,14 @@ function buildAutoPositions(items, edges, containers, hiddenIds, basePositions)
116120 } ) ;
117121 g . setDefaultEdgeLabel ( ( ) => ( { } ) ) ;
118122
119- visibleItems . forEach ( ( item ) => {
123+ graphItems . forEach ( ( item ) => {
120124 g . setNode ( item . id , { width : CARD_W , height : CARD_H } ) ;
121125 } ) ;
122126
123127 containers . forEach ( ( c ) => {
124- const members = c . members . filter ( ( id ) => visibleItems . some ( ( n ) => n . id === id ) ) ;
128+ if ( c . type === 'subnet' )
129+ return ;
130+ const members = c . members . filter ( ( id ) => graphItems . some ( ( n ) => n . id === id ) ) ;
125131 if ( members . length === 0 ) {
126132 const cid = `empty_cluster_${ c . id } ` ;
127133 g . setNode ( cid , { width : 220 , height : 80 } ) ;
@@ -131,7 +137,7 @@ function buildAutoPositions(items, edges, containers, hiddenIds, basePositions)
131137 members . forEach ( ( id ) => g . setParent ( id , c . id ) ) ;
132138 } ) ;
133139
134- const visibleNodeIds = new Set ( visibleItems . map ( ( n ) => n . id ) ) ;
140+ const visibleNodeIds = new Set ( graphItems . map ( ( n ) => n . id ) ) ;
135141 edges . forEach ( ( e ) => {
136142 if ( ! visibleNodeIds . has ( e . from ) || ! visibleNodeIds . has ( e . to ) )
137143 return ;
@@ -141,12 +147,20 @@ function buildAutoPositions(items, edges, containers, hiddenIds, basePositions)
141147 dagre . layout ( g ) ;
142148
143149 const positions = { } ;
144- visibleItems . forEach ( ( item ) => {
150+ graphItems . forEach ( ( item ) => {
145151 const n = g . node ( item . id ) ;
146152 if ( n ) {
147153 positions [ item . id ] = { x : n . x - CARD_W / 2 , y : n . y - CARD_H / 2 } ;
148154 }
149155 } ) ;
156+ if ( subnetItems . length > 0 ) {
157+ const graphBottom = Object . values ( positions )
158+ . reduce ( ( acc , p ) => Math . max ( acc , p . y + CARD_H ) , 0 ) ;
159+ const rowY = graphBottom + 120 ;
160+ subnetItems . forEach ( ( item , idx ) => {
161+ positions [ item . id ] = { x : 20 + idx * ( CARD_W + 24 ) , y : rowY } ;
162+ } ) ;
163+ }
150164 return { ...positions , ...( basePositions || { } ) } ;
151165}
152166
@@ -287,8 +301,15 @@ export default function NodeCanvas(props) {
287301 < div className = "node-canvas" ref = { canvasRef } onClick = { ( ) => onSelect ( null ) } >
288302 { renderedContainers . map ( ( c ) => {
289303 const b = c . bounds ;
290- let cls = c . type === 'netns' ? 'node-container node-container-netns' :
291- 'node-container node-container-vrf' ;
304+ let cls ;
305+ if ( c . type === 'netns' )
306+ cls = 'node-container node-container-netns' ;
307+ else if ( c . type === 'vrf' )
308+ cls = 'node-container node-container-vrf' ;
309+ else if ( c . type === 'subnet' )
310+ cls = 'node-container node-container-subnet' ;
311+ else
312+ cls = 'node-container node-container-vrf' ;
292313 if ( selectedItemId === c . id )
293314 cls += ' node-container-selected' ;
294315
0 commit comments