docs(plans): template picker — live rig gate PASS (New Instance…, ?templateId prefill, picker reveal/search/cancel, Disable verb) + task status
Claude-Session: https://claude.ai/code/session_01G2GHPnbbKGvyyfbr2XBRVH
This commit is contained in:
@@ -732,4 +732,67 @@ Content: one paragraph under the Create-Instance bullet — template chosen thro
|
||||
|
||||
## Status
|
||||
|
||||
_(filled in by the executing session)_
|
||||
**DONE — all 8 tasks complete, 2026-08-21.** Branch `feat/template-picker` (worktree
|
||||
`~/Desktop/ScadaBridge-template-picker`), 8 commits.
|
||||
|
||||
| # | Task | Result |
|
||||
|---|------|--------|
|
||||
| 1 | `TemplatePathFormatter` | done — 4 tests |
|
||||
| 2 | `TemplateFolderTree.RevealKeys` | done — 3 tests; `TreeViewTests` / `TemplatesPageTests` / `TransportExportPageTests` unaffected |
|
||||
| 3 | `TemplatePickerDialog` | done — 7 tests |
|
||||
| 4 | Create page picker field + `?templateId=` | done — 5 tests (first bUnit render of `InstanceCreate`) |
|
||||
| 5 | Templates tree "New Instance…" | done — 2 tests (Deployer shows, Designer-only hides) |
|
||||
| 6 | Topology Disable confirm pin | done — 3 tests, **PASS on first run** (no production change; `0db253b5` intact) |
|
||||
| 7 | Docs | done — `Component-CentralUI.md` (Create-Instance + Templates-page + dialog-label bullets), this design doc → implemented, bindings design §3.2 superseded note |
|
||||
| 8 | Build + sweep + live rig | **PASS** — see below |
|
||||
|
||||
### Deviations from the plan, and why
|
||||
|
||||
1. **Selection is tracked inside `TemplatePickerDialog`, not through `SelectedKeys`/`SelectedKeysChanged`.**
|
||||
In `TreeViewSelectionMode.Single` the inner `TreeView` uses the *singular* `SelectedKey` /
|
||||
`SelectedKeyChanged` pair; `TemplateFolderTree` forwards only the plural (Checkbox-mode) pair,
|
||||
which `TreeView` reads for tri-state checkbox aggregation. The plan's wiring would therefore
|
||||
never have highlighted a row and `OnSelectedKeysChanged` would never have fired. The dialog's own
|
||||
`NodeContent` click/dblclick handlers own selection and the `text-primary` highlight — no change
|
||||
to the shared tree's public surface.
|
||||
2. **`[SupplyParameterFromQuery]` cannot be set as an ordinary bUnit parameter** ("only accepts
|
||||
cascading values"). The Task-4 tests seed `BunitNavigationManager.NavigateTo(".../create?templateId=7")`
|
||||
instead, matching `Pages/QueryStringDrillInTests.cs`.
|
||||
3. **`…` in a Razor *attribute* is emitted literally** — the placeholder uses the real `…`.
|
||||
4. **The Task-3 `Open()` helper needs a block-bodied `InvokeAsync` lambda.** An expression body
|
||||
returning the pending `Task` binds to `InvokeAsync(Func<Task>)` and awaits the dialog itself;
|
||||
every test hung until it was changed (comment left in the file).
|
||||
|
||||
### Task 8 — build, sweep, live rig gate
|
||||
|
||||
- `dotnet build ZB.MOM.WW.ScadaBridge.slnx -v q` → **0 warnings, 0 errors**.
|
||||
- `dotnet test tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests` → **1154 / 1154 PASS**.
|
||||
- Rig: `docker/build.sh` run from the worktree (tags `scadabridge:latest`), then
|
||||
`docker compose -f docker/docker-compose.yml up -d --force-recreate` from the **primary
|
||||
checkout** — deploying `deploy.sh` wholesale from a worktree would have rehomed every node's
|
||||
bind-mounted appsettings to the worktree copy. `/health/ready` Healthy on all 8 nodes.
|
||||
- Live check at `http://localhost:9000` as `multi-role`, **all PASS**:
|
||||
1. `/design/templates` → right-click **Motor Controller** (inside folder `Test`) → the menu shows
|
||||
**New Instance…** between its own dividers → lands on
|
||||
`/deployment/instances/create?templateId=4` with the field reading **"Test / Motor Controller"**.
|
||||
2. Site = *Test Plant A* → Connection Bindings card appears (30 attributes, 4 groups) — the
|
||||
`?templateId` preselect does feed `OnTemplateOrSiteChangedAsync`.
|
||||
3. **Choose…** → picker opens **expanded to and highlighting** Motor Controller, footer
|
||||
"Selected: Test / Motor Controller", Select enabled. Search "Tank" narrows to one row.
|
||||
**Cancel** left the field, the site and the card untouched.
|
||||
4. Re-open → **double-click "Tank Monitor"** → dialog closes, field reads "Tank Monitor"
|
||||
(root template ⇒ no folder prefix), card re-previews to 7 attributes / 2 groups.
|
||||
5. `/deployment/instances/create` with no query → field blank with the placeholder, picker opens
|
||||
**collapsed**, footer "Select a template", **Select disabled**; clicking a *folder* label leaves
|
||||
it disabled.
|
||||
6. `/deployment/topology` → right-click `rig-probe-1` (Enabled) → **Disable** → confirm button reads
|
||||
**Disable** in red, body "Disable instance 'rig-probe-1'? …". Cancelled; instance still Enabled.
|
||||
|
||||
### Known limitation (pre-existing, not introduced here)
|
||||
|
||||
`TreeView.InitiallyExpanded` is applied **once** (`_initialExpansionApplied`). So in the picker, if a
|
||||
preselected template reveals on first render and the operator *then* types a search, the filter's own
|
||||
ancestor-expand does not re-apply — matches under a still-collapsed folder stay hidden until the
|
||||
folder is opened by hand. Opening the picker with no preselect (the common case) is unaffected,
|
||||
because nothing consumed the one-shot. Fixing it means resetting `_initialExpansionApplied` when
|
||||
`InitiallyExpanded` changes identity, which touches every `TreeView` caller — out of scope here.
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
{
|
||||
"id": 7,
|
||||
"subject": "Task 7: Docs",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"blockedBy": [
|
||||
4,
|
||||
5,
|
||||
@@ -51,7 +51,7 @@
|
||||
{
|
||||
"id": 8,
|
||||
"subject": "Task 8: Solution build + CentralUI test sweep + live rig check",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"blockedBy": [
|
||||
7
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user