docs(scripting): document {{equip}} equipment-relative tag paths
This commit is contained in:
@@ -170,4 +170,4 @@ runtime publish gate uses, so what the editor accepts/rejects matches publish
|
|||||||
exactly. The backend lives in
|
exactly. The backend lives in
|
||||||
`src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/` (six minimal-API
|
`src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/` (six minimal-API
|
||||||
endpoints under `/api/script-analysis/*`, gated by the `FleetAdmin` policy).
|
endpoints under `/api/script-analysis/*`, gated by the `FleetAdmin` policy).
|
||||||
See `docs/ScriptEditor.md` for the full guide.
|
See `docs/ScriptEditor.md` for the full guide. Scripts may use the `{{equip}}` token for equipment-relative tag paths that resolve per-equipment at deploy time — see the "Equipment-relative tag paths" section in `docs/ScriptEditor.md`.
|
||||||
|
|||||||
@@ -293,6 +293,83 @@ Register the replacement in `EndpointRouteBuilderExtensions.AddAdminUI`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Equipment-relative tag paths (`{{equip}}`)
|
||||||
|
|
||||||
|
### Why
|
||||||
|
|
||||||
|
Today each VirtualTag bound to a script typically needs its own near-duplicate
|
||||||
|
script because tag paths are hard-coded absolutes (e.g. `TestMachine_001.Speed`).
|
||||||
|
The `{{equip}}` token breaks this coupling: point many VirtualTags' `ScriptId` at
|
||||||
|
a single template script, and each resolves the token to its own equipment's tag
|
||||||
|
base prefix at deploy time. No schema change is required — sharing a `Script`
|
||||||
|
record across VirtualTags already works; `{{equip}}` is what makes the shared
|
||||||
|
script resolve per-equipment.
|
||||||
|
|
||||||
|
### Before / after
|
||||||
|
|
||||||
|
**Before — one script per machine:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Script "Calc_TestMachine_001" — hard-coded, cannot reuse
|
||||||
|
return ctx.GetTag("TestMachine_001.Speed").Value;
|
||||||
|
```
|
||||||
|
|
||||||
|
**After — one shared template:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Script "Calc_Speed" — works for any machine
|
||||||
|
return ctx.GetTag("{{equip}}.Speed").Value;
|
||||||
|
```
|
||||||
|
|
||||||
|
`TestMachine_001` and `TestMachine_002` both bind `ScriptId = "Calc_Speed"`.
|
||||||
|
At deploy, each VirtualTag receives its own expanded copy:
|
||||||
|
`TestMachine_001.Speed` and `TestMachine_002.Speed` respectively.
|
||||||
|
|
||||||
|
### Token rules
|
||||||
|
|
||||||
|
- The token is `{{equip}}` (double braces, lowercase).
|
||||||
|
- It is substituted **only inside `ctx.GetTag(…)` / `ctx.SetVirtualTag(…)` first-argument
|
||||||
|
string literals** — comments, logger strings, and other code are untouched.
|
||||||
|
- The operator writes the separator and tail: `ctx.GetTag("{{equip}}.Speed")`,
|
||||||
|
`ctx.GetTag("{{equip}}.Sub.Field")`, etc.
|
||||||
|
- The token expands to the equipment's **tag base prefix** — the common
|
||||||
|
substring-before-the-first-dot of that equipment's configured driver-tag
|
||||||
|
`FullName` values. Example: tags `TestMachine_001.Speed` and
|
||||||
|
`TestMachine_001.Temp` → base `TestMachine_001`.
|
||||||
|
|
||||||
|
### Validation requirement
|
||||||
|
|
||||||
|
Saving a VirtualTag that is bound to a `{{equip}}`-using script is rejected in
|
||||||
|
the AdminUI if the equipment does not have at least one configured driver tag, or
|
||||||
|
if its tags span multiple object prefixes (i.e. the common prefix is ambiguous or
|
||||||
|
absent). The rejection message is surfaced as a clear validation error on the save
|
||||||
|
form. This check is enforced eagerly so that an unresolved `{{equip}}` token —
|
||||||
|
which would leave a path that resolves to nothing at runtime (Bad quality) — can
|
||||||
|
never reach the deployed artifact.
|
||||||
|
|
||||||
|
### Editor support
|
||||||
|
|
||||||
|
In the Monaco script editor (ScriptEdit page and the `/uns` virtual-tag modal's
|
||||||
|
inline script panel):
|
||||||
|
|
||||||
|
- **Hover** — hovering a `{{equip}}` path literal shows an
|
||||||
|
*"Equipment-relative path — resolved at deploy"* note.
|
||||||
|
- **Completions** — typing `{{equip}}.` inside a `GetTag`/`SetVirtualTag` literal
|
||||||
|
offers completion of attribute leaf names (the part after the first dot of known
|
||||||
|
tag references in the catalog).
|
||||||
|
|
||||||
|
### Maintainer note
|
||||||
|
|
||||||
|
Substitution runs at the two compose seams —
|
||||||
|
`Phase7Composer.Compose` and `DeploymentArtifact.BuildEquipmentVirtualTagPlans`
|
||||||
|
— via the shared `ZB.MOM.WW.OtOpcUa.Commons.Types.EquipmentScriptPaths` helper,
|
||||||
|
**before** dependency extraction. The runtime, the static change-trigger
|
||||||
|
dependency graph, and the literal-only path rule are therefore all unchanged:
|
||||||
|
by the time they see the script, `{{equip}}` has been replaced with a concrete
|
||||||
|
tag-base prefix and the path is a normal string literal.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Known Limitations / Follow-ups
|
## Known Limitations / Follow-ups
|
||||||
|
|
||||||
- **Tag-path completion shows resolvable keys only.** Surfacing the UNS browse
|
- **Tag-path completion shows resolvable keys only.** Surfacing the UNS browse
|
||||||
|
|||||||
Reference in New Issue
Block a user