11import { useMemo , useState } from 'react' ;
22import type {
3- SclModel , IedModel , LDeviceModel , DataSetModel ,
3+ SclModel , IedModel , LDeviceModel , LnModel , DataSetModel ,
44 GooseControlModel , SvControlModel , ReportControlModel , FcdaModel ,
5+ DataTypeTemplatesModel ,
56} from '../model/types' ;
67
78interface IedExplorerProps {
@@ -123,6 +124,7 @@ function IedTree({ ied, model }: { ied: IedModel; model: SclModel }): JSX.Elemen
123124 goose = { goose . filter ( ( g ) => g . ldInst === ld . inst ) }
124125 sv = { sv . filter ( ( s ) => s . ldInst === ld . inst ) }
125126 reports = { reports . filter ( ( r ) => r . ldInst === ld . inst ) }
127+ dtt = { model . dataTypeTemplates ?? { lNodeTypes : new Map ( ) , doTypes : new Map ( ) , daTypes : new Map ( ) , enumTypes : new Map ( ) , duplicateTypeIds : [ ] } }
126128 isOpen = { isOpen }
127129 onToggle = { toggle }
128130 depth = { 1 }
@@ -136,14 +138,15 @@ function IedTree({ ied, model }: { ied: IedModel; model: SclModel }): JSX.Elemen
136138/* ── LDevice node ──────────────────────────────────────────────────── */
137139
138140function LDeviceNode ( {
139- ied, ld, datasets, goose, sv, reports, isOpen, onToggle, depth,
141+ ied, ld, datasets, goose, sv, reports, dtt , isOpen, onToggle, depth,
140142} : {
141143 ied : IedModel ;
142144 ld : LDeviceModel ;
143145 datasets : DataSetModel [ ] ;
144146 goose : GooseControlModel [ ] ;
145147 sv : SvControlModel [ ] ;
146148 reports : ReportControlModel [ ] ;
149+ dtt : DataTypeTemplatesModel ;
147150 isOpen : ( key : string ) => boolean ;
148151 onToggle : ( key : string ) => void ;
149152 depth : number ;
@@ -272,12 +275,123 @@ function LDeviceNode({
272275
273276 { /* Other LNs */ }
274277 { ld . lns . map ( ( ln ) => (
275- < LeafNode
278+ < LnNode
276279 key = { `${ ln . lnClass } ${ ln . inst } ` }
277- icon = "◈"
278- iconClass = { `ied-tree-icon-ln ied-tree-ln-${ getLnGroup ( ln . lnClass ) } ` }
279- label = { `${ ln . prefix ?? '' } ${ ln . lnClass } ${ ln . inst } ` }
280- sublabel = { ln . lnType }
280+ nodeKey = { `ln:${ ied . name } :${ ld . inst } :${ ln . prefix ?? '' } ${ ln . lnClass } ${ ln . inst } ` }
281+ ln = { ln }
282+ dtt = { dtt }
283+ isOpen = { isOpen }
284+ onToggle = { onToggle }
285+ depth = { depth + 1 }
286+ />
287+ ) ) }
288+ </ TreeNode >
289+ ) ;
290+ }
291+
292+ /* ── LN node (with DO/DA from DataTypeTemplates) ─────────────────── */
293+
294+ function LnNode ( {
295+ nodeKey, ln, dtt, isOpen, onToggle, depth,
296+ } : {
297+ nodeKey : string ;
298+ ln : LnModel ;
299+ dtt : DataTypeTemplatesModel ;
300+ isOpen : ( key : string ) => boolean ;
301+ onToggle : ( key : string ) => void ;
302+ depth : number ;
303+ } ) : JSX . Element {
304+ const label = `${ ln . prefix ?? '' } ${ ln . lnClass } ${ ln . inst } ` ;
305+ const lnTypeDef = ln . lnType ? dtt . lNodeTypes . get ( ln . lnType ) : undefined ;
306+ const dos = lnTypeDef ?. dos ?? [ ] ;
307+
308+ if ( dos . length === 0 ) {
309+ return (
310+ < LeafNode
311+ icon = "◈"
312+ iconClass = { `ied-tree-icon-ln ied-tree-ln-${ getLnGroup ( ln . lnClass ) } ` }
313+ label = { label }
314+ sublabel = { ln . lnType }
315+ depth = { depth }
316+ />
317+ ) ;
318+ }
319+
320+ return (
321+ < TreeNode
322+ nodeKey = { nodeKey }
323+ icon = "◈"
324+ iconClass = { `ied-tree-icon-ln ied-tree-ln-${ getLnGroup ( ln . lnClass ) } ` }
325+ label = { label }
326+ sublabel = { ln . lnType }
327+ isOpen = { isOpen ( nodeKey ) }
328+ onToggle = { onToggle }
329+ depth = { depth }
330+ >
331+ { dos . map ( ( doEntry ) => (
332+ < DoNode
333+ key = { doEntry . name }
334+ nodeKey = { `${ nodeKey } :do:${ doEntry . name } ` }
335+ doName = { doEntry . name }
336+ doType = { doEntry . type }
337+ dtt = { dtt }
338+ isOpen = { isOpen }
339+ onToggle = { onToggle }
340+ depth = { depth + 1 }
341+ />
342+ ) ) }
343+ </ TreeNode >
344+ ) ;
345+ }
346+
347+ /* ── DO node ──────────────────────────────────────────────────────── */
348+
349+ function DoNode ( {
350+ nodeKey, doName, doType, dtt, isOpen, onToggle, depth,
351+ } : {
352+ nodeKey : string ;
353+ doName : string ;
354+ doType : string ;
355+ dtt : DataTypeTemplatesModel ;
356+ isOpen : ( key : string ) => boolean ;
357+ onToggle : ( key : string ) => void ;
358+ depth : number ;
359+ } ) : JSX . Element {
360+ const doTypeDef = dtt . doTypes . get ( doType ) ;
361+ const das = doTypeDef ?. das ?? [ ] ;
362+ const cdc = doTypeDef ?. cdc ;
363+
364+ if ( das . length === 0 ) {
365+ return (
366+ < LeafNode
367+ icon = "◇"
368+ iconClass = "ied-tree-icon-do"
369+ label = { doName }
370+ sublabel = { cdc }
371+ depth = { depth }
372+ />
373+ ) ;
374+ }
375+
376+ return (
377+ < TreeNode
378+ nodeKey = { nodeKey }
379+ icon = "◇"
380+ iconClass = "ied-tree-icon-do"
381+ label = { doName }
382+ sublabel = { cdc }
383+ isOpen = { isOpen ( nodeKey ) }
384+ onToggle = { onToggle }
385+ depth = { depth }
386+ >
387+ { das . map ( ( da ) => (
388+ < LeafNode
389+ key = { da . name }
390+ icon = "·"
391+ iconClass = "ied-tree-icon-da"
392+ label = { da . name }
393+ sublabel = { da . bType ?? da . type }
394+ tag = { da . fc }
281395 depth = { depth + 1 }
282396 />
283397 ) ) }
0 commit comments