fix(ui/templates): expand composition leaves to show cascaded slots
Composition leaves were rendered flat — the cascaded inner derived templates existed in the DB but the tree only showed the outer slot name (e.g. "Tank Monitor > DrivePump") with no way to see DrivePump's own TempSensor + AlarmSensor slots. BuildCompositionLeaves now recurses: for each composition under a template, look up the composed template (which after derive-on-compose is a derived row carrying its own Compositions) and build its slot leaves as children. HasChildrenSelector loses the "not a composition" guard so nested leaves render with the expand chevron.
This commit is contained in:
@@ -81,7 +81,7 @@
|
|||||||
<div style="max-height: calc(100vh - 160px); overflow-y: auto; padding: 4px;">
|
<div style="max-height: calc(100vh - 160px); overflow-y: auto; padding: 4px;">
|
||||||
<TreeView @ref="_tree" TItem="TmplNode" Items="_treeRoots"
|
<TreeView @ref="_tree" TItem="TmplNode" Items="_treeRoots"
|
||||||
ChildrenSelector="n => n.Children"
|
ChildrenSelector="n => n.Children"
|
||||||
HasChildrenSelector="n => n.Kind != TmplNodeKind.Composition && n.Children.Count > 0"
|
HasChildrenSelector="n => n.Children.Count > 0"
|
||||||
KeySelector="n => (object)n.Key"
|
KeySelector="n => (object)n.Key"
|
||||||
StorageKey="templates-tree">
|
StorageKey="templates-tree">
|
||||||
<NodeContent Context="node">
|
<NodeContent Context="node">
|
||||||
@@ -178,22 +178,13 @@
|
|||||||
|
|
||||||
// 3. Template nodes with composition leaves. Derived templates are
|
// 3. Template nodes with composition leaves. Derived templates are
|
||||||
// slot-owned and reached via their parent's composition leaf — never
|
// slot-owned and reached via their parent's composition leaf — never
|
||||||
// shown as standalone tree nodes.
|
// shown as standalone tree nodes. Composition leaves recurse so a
|
||||||
|
// composite slot (e.g. Pump composed with TempSensor) reveals its own
|
||||||
|
// child slots when expanded.
|
||||||
|
var templatesById = _templates.ToDictionary(t => t.Id);
|
||||||
foreach (var t in _templates.Where(t => !t.IsDerived).OrderBy(t => t.Name, StringComparer.OrdinalIgnoreCase))
|
foreach (var t in _templates.Where(t => !t.IsDerived).OrderBy(t => t.Name, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var compChildren = t.Compositions
|
var compChildren = BuildCompositionLeaves(t, templatesById);
|
||||||
.OrderBy(c => c.InstanceName, StringComparer.OrdinalIgnoreCase)
|
|
||||||
.Select(c => new TmplNode(
|
|
||||||
Key: $"c:{c.Id}",
|
|
||||||
Kind: TmplNodeKind.Composition,
|
|
||||||
EntityId: c.Id,
|
|
||||||
Label: c.InstanceName,
|
|
||||||
ParentFolderId: null,
|
|
||||||
OwnerTemplateId: t.Id,
|
|
||||||
Template: null,
|
|
||||||
Composition: c,
|
|
||||||
Children: new List<TmplNode>()))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var tNode = new TmplNode(
|
var tNode = new TmplNode(
|
||||||
Key: $"t:{t.Id}",
|
Key: $"t:{t.Id}",
|
||||||
@@ -220,6 +211,33 @@
|
|||||||
_treeRoots = roots;
|
_treeRoots = roots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recursive: each composition leaf's children are the composed-template's
|
||||||
|
// own composition leaves. Cascaded derived templates carry their slot
|
||||||
|
// compositions, so walking ComposedTemplateId surfaces the full nested
|
||||||
|
// structure.
|
||||||
|
private static List<TmplNode> BuildCompositionLeaves(Template owner, IReadOnlyDictionary<int, Template> templatesById)
|
||||||
|
{
|
||||||
|
var result = new List<TmplNode>();
|
||||||
|
foreach (var c in owner.Compositions.OrderBy(c => c.InstanceName, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var nestedChildren = templatesById.TryGetValue(c.ComposedTemplateId, out var composed)
|
||||||
|
? BuildCompositionLeaves(composed, templatesById)
|
||||||
|
: new List<TmplNode>();
|
||||||
|
|
||||||
|
result.Add(new TmplNode(
|
||||||
|
Key: $"c:{c.Id}",
|
||||||
|
Kind: TmplNodeKind.Composition,
|
||||||
|
EntityId: c.Id,
|
||||||
|
Label: c.InstanceName,
|
||||||
|
ParentFolderId: null,
|
||||||
|
OwnerTemplateId: owner.Id,
|
||||||
|
Template: null,
|
||||||
|
Composition: c,
|
||||||
|
Children: nestedChildren));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static void SortChildren(List<TmplNode> children)
|
private static void SortChildren(List<TmplNode> children)
|
||||||
{
|
{
|
||||||
children.Sort((a, b) =>
|
children.Sort((a, b) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user