fix(centralui): surface inherited compositions in the templates tree (followup #9)
The templates tree rendered a derived/composed member (e.g. LeftReactorSide, derived from ReactorSide) as a flat leaf, omitting compositions it inherits from its base (e.g. LeakTest composed onto ReactorSide). BuildCompositionLeavesFor recursed only over a template's OWN composition rows; an inherited composition row lives on the ancestor, and TemplateComposition has no IsInherited placeholder (unlike attributes/alarms/scripts/native-sources), so the child's own Compositions was empty. Same 'derived templates don't surface inherited members' family as followups #1/#2, but for compositions. Deploy/flatten was always correct (TemplateResolver.ResolveAllMembers walks the chain) — display-only. Fix: - BuildCompositionLeavesFor now renders the EFFECTIVE composition set (own + inherited) via EffectiveCompositionsFor, which walks the inheritance chain (leaf->root, child wins on InstanceName), mirroring the resolver. - Inherited slots are flagged (TemplateTreeNode.IsInherited), badged 'inherited' in the label, and their context menu offers only 'Open composed template' (Rename/Delete edit the ancestor's slot, so suppressed on inherited nodes). - The same inherited row can appear under several derived members (LeakTest under both LeftReactorSide and RightReactorSide), so composition nodes use a path-qualified KeyOverride to keep TreeView selection/expansion keys unique; recursion is cycle-guarded. Tests: +1 bUnit (TemplatesPageTests.Renders_InheritedComposition_UnderDerivedComposedMember); CentralUI suite 867 green; full solution builds 0/0. Docs: Component-CentralUI.md (effective composition set in tree); known-issues tracker #9 recorded + resolved. Note: CentralUI change — shows on wonder-app-vd03 only after that host is redeployed.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
**Status:** RESOLVED · **Found:** 2026-06-24 · **Context:** live ops session on `wonder-app-vd03` (CvdReactor / Z28061 / Z28061Sim) — renaming the template, adding the LeakTest module, and adding MoveInType to the MESReceiver children.
|
||||
**Components:** Central UI (#9), Template Engine (#1), CLI (#19), Configuration Database (#17), Deployment Manager (#2)
|
||||
|
||||
**Resolved:** #3 (collision detector) and #7 (sandbox compile surface) on branch `fix/followups-3-7`; #1 + #2 (inherited-member propagation & resync) on branch `fix/followups-1-2`; #4 + #5 + #6 + #8 (CLI ergonomics + structured deploy validation error) on branch `fix/followups-4-5-6-8` (all 2026-06-24). All items resolved.
|
||||
**Resolved:** #3 (collision detector) and #7 (sandbox compile surface) on branch `fix/followups-3-7`; #1 + #2 (inherited-member propagation & resync) on branch `fix/followups-1-2`; #4 + #5 + #6 + #8 (CLI ergonomics + structured deploy validation error) and #9 (inherited compositions in the templates tree) on branch `fix/followups-4-5-6-8` (all 2026-06-24). All items resolved.
|
||||
|
||||
Issues are listed worst-first. Severities are author estimates. None caused data loss; the runtime/flattened config and deployed instances are correct.
|
||||
|
||||
@@ -150,3 +150,16 @@ message fallback, mixed categories).
|
||||
**Root cause:** `ValidateConnectionBindingCompleteness` emits one clause per unbound attribute and joins them into a flat string; there is no grouping or count.
|
||||
|
||||
**Suggested fix:** return a structured/summarized error — leading count (`52 attributes are unbound`) + grouped-by-module breakdown (or a capped list with "…and N more") — instead of the flat semicolon-joined dump. Keep the full list available in a detail/expandable view or the deploy log.
|
||||
|
||||
---
|
||||
|
||||
## 9. Templates tree omits inherited compositions under derived composed-members (user-reported)
|
||||
**Severity:** Low-Medium · **Components:** Central UI (#9) · **✅ RESOLVED 2026-06-24 (branch `fix/followups-4-5-6-8`)**
|
||||
|
||||
**Fix:** `Templates.razor` → `BuildCompositionLeavesFor` now renders the **effective** composition set (own + inherited) via a new `EffectiveCompositionsFor` that walks the inheritance chain (leaf→root, child wins on `InstanceName`), mirroring `TemplateResolver.ResolveAllMembers`. Inherited slots are flagged (`TemplateTreeNode.IsInherited`), badged **"inherited"** in the label, and their context menu offers only **Open composed template** (Rename/Delete edit the ancestor's slot, so they're suppressed on inherited nodes). Because the same inherited row can now appear under several derived members (LeakTest under both LeftReactorSide and RightReactorSide), composition nodes use a path-qualified `KeyOverride` (`t:{owner}/c:{id}/…`) so TreeView selection/expansion keys stay unique; the recursion is cycle-guarded. Covered by `TemplatesPageTests.Renders_InheritedComposition_UnderDerivedComposedMember`.
|
||||
|
||||
**Symptom:** On `/design/templates`, the base `ReactorSide` node expands to show its composed `↳ LeakTest`. But under `CvdReactor`, the composed members `LeftReactorSide` / `RightReactorSide` (derived from `ReactorSide`) render as **flat leaves with no LeakTest** — even though they inherit it. Observed live on `wonder-app-vd03`.
|
||||
|
||||
**Root cause:** `BuildCompositionLeavesFor(owner)` recursed only over `owner.Compositions` (the template's **own** rows). A derived template's inherited composition row lives on its ancestor, and `TemplateComposition` has no `IsInherited` placeholder (unlike attributes/alarms/scripts/native-sources, which `BuildDerivedTemplate`/the #1/#2 reconcile materialize) — so the derived child's own `Compositions` is empty and the recursion found nothing. Same "derived templates don't surface inherited members" family as #1/#2, but for compositions, which the #1/#2 fix did not cover. Deploy/flatten was always correct (`TemplateResolver.ResolveAllMembers` walks the chain), so this was display-only.
|
||||
|
||||
**Note:** this is a Central UI change — it shows on `wonder-app-vd03` only after that host is redeployed with the new build.
|
||||
|
||||
Reference in New Issue
Block a user