diff --git a/src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor b/src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
index 0c6a4e1..6b794af 100644
--- a/src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
+++ b/src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
@@ -81,7 +81,7 @@
@@ -178,22 +178,13 @@
// 3. Template nodes with composition leaves. Derived templates are
// 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))
{
- var compChildren = t.Compositions
- .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()))
- .ToList();
+ var compChildren = BuildCompositionLeaves(t, templatesById);
var tNode = new TmplNode(
Key: $"t:{t.Id}",
@@ -220,6 +211,33 @@
_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 BuildCompositionLeaves(Template owner, IReadOnlyDictionary templatesById)
+ {
+ var result = new List();
+ 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();
+
+ 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 children)
{
children.Sort((a, b) =>