From 1ed42dc42548d4ee8e4a7449f81403ba12c20317 Mon Sep 17 00:00:00 2001 From: Max Gramser Date: Fri, 18 Sep 2026 08:32:08 +0200 Subject: [PATCH] =?UTF-8?q?Release=200.2.73:=20the=20Vue=20editor=20with?= =?UTF-8?q?=20live=20values,=20Identify,=20a=20test=20alert,=20layout=20co?= =?UTF-8?q?pying=20and=20=E2=8C=98K?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- AGENTS.md | 2 +- docs/TEST_RESULTS_0273.md | 37 +++++++++++++++++++++++++++++++++ screen_manager/Dockerfile | 2 +- screen_manager/app/changelog.py | 2 +- screen_manager/app/server.py | 6 +++--- screen_manager/app/updates.py | 2 +- tests/editor_sources.py | 2 +- tests/test_editor_live.py | 2 +- tests/test_editor_startup.py | 2 +- tests/test_page_assets.py | 2 +- tests/test_settings_view.py | 2 +- web/src/store.ts | 8 +++---- 12 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 docs/TEST_RESULTS_0273.md diff --git a/AGENTS.md b/AGENTS.md index ad64ccf..b43899b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,7 +54,7 @@ and screens for lookups and tests. If that file is missing you are not on his ma - Keep base hardware and UI in `home-like-2432s028.yaml`; personal data belongs in the gitignored local profiles. -- The editor is `web/` (Vue 3 + Vite, TypeScript; app 0.2.74+). `screen_manager/app/static` is its build +- The editor is `web/` (Vue 3 + Vite, TypeScript; app 0.2.73+). `screen_manager/app/static` is its build output: change `web/src`, run `cd web && npm test && npm run build`, and commit both. Keep every URL the page asks for relative (`api/...`), so it works behind Home Assistant's ingress path. Tests read the source through `tests/editor_sources.py`; docs/RELEASING.md "Local development" has the dev-server recipe. diff --git a/docs/TEST_RESULTS_0273.md b/docs/TEST_RESULTS_0273.md new file mode 100644 index 0000000..93f0483 --- /dev/null +++ b/docs/TEST_RESULTS_0273.md @@ -0,0 +1,37 @@ +# Test results 0.2.73 (firmware 0.2.61, unchanged) + +Date: 2026-09-18. Branch `editor-vue`, rebased on 9f5694b (0.2.72). The firmware and the packages did not change; +this release is the editor (web/, Vue 3 + Vite) and four additive add-on endpoints. + +## Automated + +- Python: `.venv-portal/bin/python -m unittest discover -s tests` → 398 tests OK. New: `tests/test_editor_live.py` + (`/api/states`, `/api/screens/{inbox}/identify`, `/api/alerts/test`, the changelog in the update summary, and the + page side of every new feature read from the Vue sources). The nine tests that used to read `static/app.js` now + read the sources through `tests/editor_sources.py`; `tests/test_page_assets.py` checks the committed Vite build. +- Editor: `cd web && npm test` → Vitest, 37 tests OK (grid rules, top bar rules, store, TileCard, Library, + CommandPalette in jsdom). `npm run check` (vue-tsc) clean. `npm run build` → `screen_manager/app/static`. +- `tools/generate_icons.py --check` → 150 pickable icons, 309 glyphs verified (the editor font now lives in + `web/src/assets`). + +## By hand, on the demo home (real add-on code, fake Home Assistant, port 8199) + +- Choose a screen, tile drawer with every field, top bar drawer with the live sample, add to the top bar, Screen + settings tab, add an entity from the library and Save & send (PUT arrives, chip says Saved), drag a tile onto + another (swap), remove with Undo, Esc closes the drawer, ··· menu, Override YAML with the example, New screen, + Firmware & USB, Alerts, Settings; dark mode; 375 px layout. +- New in this release: live values on every tile (temperature with unit, On/Off with a lit icon, setpoint, volume and + position fills, the playing title), Identify (show_alert with flash reaches the demo HA), Try it to one screen and + to all (two calls logged), Copy layout from the other screen, Export (download + clipboard), room filter, Hide + placed, lit and grey avatars, ⌘K search that adds an entity, What's new under the Update badge. + +## On Max's own Home Assistant + +- The first build of this editor ran as a local add-on (same code, before the six features) against his real screens + and Home Assistant: "ik vind de rest van de editor ook echt geweldig, heb hem getest". + +## Not exercised + +- The progress bar of a running firmware update (the demo home cannot build firmware); only the mapping from phase + and ESPHome stage to a percentage is unit-tested. +- Drag & drop on a phone (touch), and the six new features inside the Home Assistant ingress iframe. diff --git a/screen_manager/Dockerfile b/screen_manager/Dockerfile index a6e8dd5..dc0619c 100644 --- a/screen_manager/Dockerfile +++ b/screen_manager/Dockerfile @@ -5,7 +5,7 @@ ARG BUILD_ARCH LABEL io.hass.version="${BUILD_VERSION}" io.hass.type="app" io.hass.arch="${BUILD_ARCH}" RUN pip install --no-cache-dir 'aiohttp>=3.12,<4' PyYAML COPY app /app -# The Update badge shows what's new from the changelog (app 0.2.74). +# The Update badge shows what's new from the changelog (app 0.2.73). COPY CHANGELOG.md /app/CHANGELOG.md WORKDIR /app ENTRYPOINT [] diff --git a/screen_manager/app/changelog.py b/screen_manager/app/changelog.py index 795744f..c8ef049 100644 --- a/screen_manager/app/changelog.py +++ b/screen_manager/app/changelog.py @@ -1,4 +1,4 @@ -"""What's new for the Update badge (app 0.2.74): the CHANGELOG sections since a screen's firmware. +"""What's new for the Update badge (app 0.2.73): the CHANGELOG sections since a screen's firmware. The Dockerfile copies CHANGELOG.md next to this file; a development checkout has it one folder up. Each `## (firmware )` section gives its bullet lines as plain text, newest first. diff --git a/screen_manager/app/server.py b/screen_manager/app/server.py index e965bff..61ecf47 100644 --- a/screen_manager/app/server.py +++ b/screen_manager/app/server.py @@ -1624,7 +1624,7 @@ def create_app(manager, development=False): 'attributes':state_message(i,t,manager.ha.states)['a'], 'options':t.get('options',{})} for i,t in enumerate(layout['tiles'])]}) async def states(request): - """Live values for the editor's mockup (app 0.2.74): the state, Home Assistant's word and the attributes a + """Live values for the editor's mockup (app 0.2.73): the state, Home Assistant's word and the attributes a card shows, for the tiles on the page, saved or not. At most sixty entities per request.""" index = manager.registry_index() result = {} @@ -1647,14 +1647,14 @@ def create_app(manager, development=False): raise ValueError(f"{screen['name']} can't show an alert: {skipped[0][1] if skipped else 'not ready'}.") return ready[0] async def identify(request): - """Identify (app 0.2.74): the screen shows a short card and blinks its backlight, so you know which one it is.""" + """Identify (app 0.2.73): the screen shows a short card and blinks its backlight, so you know which one it is.""" screen = one_alert_target(request.match_info['inbox']) data, _ = alert_data({'title': f"This is {screen['name']}", 'subtitle': 'Identify, from ESP Screens', 'icon': 'bell-ring', 'color': 'blue', 'button_text': 'OK', 'timeout': 8, 'flash': True}) await manager.ha.call(alert_service(screen['node']), data) return web.json_response({'ok': True}) async def test_alert(request): - """Alerts → Try it (app 0.2.74): one alert to one screen or to every screen, with the fields an automation sends.""" + """Alerts → Try it (app 0.2.73): one alert to one screen or to every screen, with the fields an automation sends.""" body = await request.json() if not isinstance(body, dict): raise ValueError('Invalid alert.') diff --git a/screen_manager/app/updates.py b/screen_manager/app/updates.py index 194cf91..4d13615 100644 --- a/screen_manager/app/updates.py +++ b/screen_manager/app/updates.py @@ -32,7 +32,7 @@ class Updater: self.manager, self.path = manager, Path(path) self.auto, self.hosts, self.results, self.last_round = False, {}, {}, None self.task, self.current, self.queue, self.phase = None, None, [], None - # What's new since a screen's firmware, for the Update badge (app 0.2.74). + # What's new since a screen's firmware, for the Update badge (app 0.2.73). self.changelog = changelog.load() if self.path.exists(): raw = json.loads(self.path.read_text()) diff --git a/tests/editor_sources.py b/tests/editor_sources.py index 00aae25..751a9a7 100644 --- a/tests/editor_sources.py +++ b/tests/editor_sources.py @@ -1,6 +1,6 @@ """The editor's source, for the tests that read it. -The page is a Vue app in web/ (app 0.2.74); `npm run build` writes it to screen_manager/app/static. Tests look at +The page is a Vue app in web/ (app 0.2.73); `npm run build` writes it to screen_manager/app/static. Tests look at the source, not the build: every .ts and .vue file under web/src as one text (SCRIPT, which is also the markup: a .vue file carries its template), and the stylesheets as another (CSS). """ diff --git a/tests/test_editor_live.py b/tests/test_editor_live.py index 361b264..ac039b3 100644 --- a/tests/test_editor_live.py +++ b/tests/test_editor_live.py @@ -1,4 +1,4 @@ -"""Live values on the mockup, Identify, the test alert and the changelog for the Update badge (app 0.2.74). +"""Live values on the mockup, Identify, the test alert and the changelog for the Update badge (app 0.2.73). The editor asks /api/states for the tiles it shows and draws Home Assistant's values on the mockup; Identify and Try it call a screen's own show_alert action, with the same field rules as an alert event; the update summary diff --git a/tests/test_editor_startup.py b/tests/test_editor_startup.py index 961394f..0c3ee41 100644 --- a/tests/test_editor_startup.py +++ b/tests/test_editor_startup.py @@ -8,7 +8,7 @@ fills in what was missing. App 0.2.65: the page no longer opens the first screen by itself; the owner picks one. Until then a card asks for that, or offers the install when there are no screens yet. -App 0.2.74: the page is the Vue app in web/; these tests read its source (tests/editor_sources.py). +App 0.2.73: the page is the Vue app in web/; these tests read its source (tests/editor_sources.py). """ import re import sys diff --git a/tests/test_page_assets.py b/tests/test_page_assets.py index 8a6452c..480a35f 100644 --- a/tests/test_page_assets.py +++ b/tests/test_page_assets.py @@ -1,4 +1,4 @@ -"""The page loads its own script and styles by content hash (app 0.2.58, Vite build since 0.2.74). +"""The page loads its own script and styles by content hash (app 0.2.58, Vite build since 0.2.73). After updating to 0.2.57, Safari showed an empty Screen settings panel: it kept a cached script from before the update. Vite names every built file after a hash of its content and index.html asks for those names, so a diff --git a/tests/test_settings_view.py b/tests/test_settings_view.py index 75d1168..71da674 100644 --- a/tests/test_settings_view.py +++ b/tests/test_settings_view.py @@ -1,5 +1,5 @@ """Settings (app 0.2.45): New screen, Firmware & USB, firmware updates, Alerts and Claude moved off the main -page into a view of their own. App 0.2.74: the sidebar carries the way in (New screen, Firmware & USB, Alerts, +page into a view of their own. App 0.2.73: the sidebar carries the way in (New screen, Firmware & USB, Alerts, Settings), each once; the Settings page keeps the updates and Claude.""" import re import sys diff --git a/web/src/store.ts b/web/src/store.ts index 6c18753..5e0354f 100644 --- a/web/src/store.ts +++ b/web/src/store.ts @@ -165,7 +165,7 @@ export async function loadEntityActions(entity: string) { } } -// ---- Live values on the mockup (app 0.2.74): what the screen shows right now ---- +// ---- Live values on the mockup (app 0.2.73): what the screen shows right now ---- let statesFlight = false; export async function loadStates() { const entities = [...new Set((state.layout?.tiles || []).map((t) => t.entity).filter((id) => !id.startsWith("screen.")))]; @@ -347,7 +347,7 @@ export async function save() { } } -// ---- Identify and the test alert (app 0.2.74): a screen's own show_alert action ---- +// ---- Identify and the test alert (app 0.2.73): a screen's own show_alert action ---- export const canAlert = (screen: Screen | undefined) => Boolean(screen && screen.alert_action && versionAtLeast(screen.firmware, state.inventory.alerts?.min_firmware || "0.2.31")); export async function identify(screen: Screen) { @@ -362,7 +362,7 @@ export async function sendTestAlert(target: string, data: Record, what: string) { const layout = state.layout; @@ -418,7 +418,7 @@ export function importLayout(text: string) { adopt(data, "Layout imported"); } -// ---- Updates with content (app 0.2.74): what a screen gets, and how far its update is ---- +// ---- Updates with content (app 0.2.73): what a screen gets, and how far its update is ---- export function whatsNew(screen: Screen): string[] { const target = state.inventory.updates?.target; const sections = (state.inventory.updates as any)?.changelog as { app: string; firmware: string; lines: string[] }[] | undefined;