Phase C of the program viewer. Replaces the "panel coming soon" stub with a real Lit-based side panel that consumes the Phase-B websocket commands. Layout (top to bottom): * Header — title + total/filtered count * Filter bar — search box (substring match), trigger-type chips (TIMED / EVENT / YEARLY / WHEN / AT / EVERY / REMARK), a clearable "filtering on <ref>" pill when an entity filter is active * Two-column body: program list on the left, slide-in detail panel on the right. Collapses to single-column on `narrow` view. The program list renders one row per program (or per chain head, for clausal multi-record programs). Each row carries the slot number, the rendered one-line summary token stream, and meta pills for trigger type / condition count / multi-action count. The detail panel renders the full structured-English token stream inside a styled <pre>. A "Fire now" button calls ``omni_pca/programs/fire`` over the wire — the panel actually runs the program. For chain detail the spanned slot range is shown underneath. REF tokens are rendered as `<button>` elements that click to filter the list to "programs that mention this entity" — the most useful navigational affordance for the "why is this happening?" use case. Live-state badges (SECURE / NOT READY / ON 60% / Away / 72°F / …) are appended to REF tokens via the Phase-B coordinator-backed StateResolver. The panel polls ``programs/list`` every 5 seconds to refresh badges; switching to push-event subscriptions is a follow-up when polling overhead becomes visible. Theming uses HA's standard CSS variables (--primary-color, --card-background-color, --divider-color, etc.) so the panel inherits the user's HA theme automatically. Build pipeline: * TypeScript source under ``custom_components/omni_pca/frontend/src/`` * esbuild bundles entry → ESM in one self-contained file * Output at ``custom_components/omni_pca/www/panel.js`` (~34 KB minified) is committed so end-users don't need Node installed * ``npm run watch`` for HA-dev-time iteration * tsconfig has strict mode + noUnusedLocals; bundle currently type-checks clean Manifest declares deps on ``http`` and ``websocket_api``; ``frontend`` and ``panel_custom`` are loaded opportunistically (they require ``hass_frontend`` which the test harness doesn't ship — keeping them out of the manifest deps keeps tests green). Full suite: 634 passed, 1 skipped (no test changes; the integration side hasn't moved since Phase B).
42 lines
1.7 KiB
Markdown
42 lines
1.7 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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.
|