Ryan Malloy 8a0fb1e4fe panel: Arg2-as-object editor for structured-AND records
Lets structured-AND IF rows compare a typed field against another
typed field, not just a constant. Authoring "Thermostat 1.Temp >
Thermostat 2.Temp" now works in-place; previously Arg2 was locked
to Constant in the editor.

- types.ts: relax isEditableStructuredAnd to permit Zone/Unit/
  Thermostat/Area/TimeDate as Arg2 types (the same editable set
  already accepted for Arg1).
- omni-panel-programs.ts: replace the lone constant input with
  Arg2 type/object/field controls that mirror the Arg1 layout;
  switching Arg2 between Constant and a reference type swaps the
  sub-controls and resets defaults sensibly.
- _renderStructuredArg1Picker generalised to _renderStructuredObjectPicker
  driving both sides; _defaultIxForKind extracted as a shared helper.
- Bundle rebuilt.
- dev/screenshot_arg2_object.py: targeted playwright helper that
  opens the chain at slot 200 and screenshots the editor for
  visual verification.
2026-05-17 13:06:07 -06:00
..

Omni Programs side panel — frontend

Lit/TypeScript source for the HA side panel registered by websocket.py:async_register_side_panel. The build output (../www/panel.js) is committed so end-users don't need Node installed.

Edit / rebuild

cd custom_components/omni_pca/frontend
npm install         # one-time
npm run build       # one-shot — drops a fresh ../www/panel.js
npm run watch       # rebuild on change (use during HA dev)

The build script (build.mjs) bundles the entry point + Lit + all imports into a single ESM file at ../www/panel.js. Source maps are inlined in --watch mode and stripped in production builds. Output is ~34 KB minified.

Layout

File Purpose
src/omni-panel-programs.ts The custom-element entry point. Defines <omni-panel-programs> (matching the panel_custom registration).
src/token-renderer.ts Token stream → Lit TemplateResult. Each TokenKind gets distinctive styling; REF tokens become buttons that dispatch a click.
src/types.ts TS interfaces mirroring the Phase-B websocket wire shapes. Short keys (k/t/ek/ei/s) match websocket.py:_tokens_to_json.

Wire contract

The panel calls three websocket commands (all defined in ../websocket.py):

  • omni_pca/programs/list — paginated, filterable summaries.
  • omni_pca/programs/get — full structured-English detail for one slot.
  • omni_pca/programs/fire — sends Command.EXECUTE_PROGRAM over the wire.

The frontend doesn't subscribe to push events; live-state badges refresh on a low-frequency poll (REFRESH_MS = 5000). That's a deliberate scope choice — switching to per-entity event subscription is a follow-up if the polling overhead becomes visible on huge installs.