From 388fa9e29d3459c02820d0cc29cfc7236f8975c9 Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Wed, 30 Sep 2026 07:24:30 +0200 Subject: [PATCH] chore(release): pick the 0.25 highlights and add a settings search screenshot (#1727) * chore(release): add 0.25 highlights and a settings search screenshot Mark the deferred Electron startup wiring as the "Faster startup" highlight next to settings search, and give the settings search note a screenshot: a new `open-settings-search=` capture action types the term into the header search and waits for the ranked results. Guard the manifest tooling with tests that validate the committed screenshots.manifest.json and keep KNOWN_ACTIONS in step with the capture navigation action tables. Co-Authored-By: Claude Opus 5.5 * build(release): hash the capture action tables for release-tools:test The KNOWN_ACTIONS parity test reads capture-navigation-*-actions.ts, so those files must invalidate the cached test result. Co-Authored-By: Claude Opus 5.5 * chore(release): trim 0.25 to three highlights Keep redesigned player controls, parental lock and the cinematic dashboard hero as the headline changes. Settings search, faster startup, the player settings panel and the up next card stay as regular notes; settings search keeps its screenshot. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: 4gray Co-authored-by: Claude Opus 5.5 --- .changes/playback-player-settings-panel.md | 1 - .changes/playback-up-next-card.md | 1 - .changes/settings-search.md | 2 +- .../capture-navigation-setup-actions.ts | 31 +++++++++++++++++++ tools/release/project.json | 1 + tools/release/screenshot-guards.mjs | 1 + tools/release/screenshot-guards.test.mjs | 30 ++++++++++++++++++ tools/release/screenshots.manifest.json | 7 +++++ 8 files changed, 71 insertions(+), 3 deletions(-) diff --git a/.changes/playback-player-settings-panel.md b/.changes/playback-player-settings-panel.md index 0ab266108..983fd6e6f 100644 --- a/.changes/playback-player-settings-panel.md +++ b/.changes/playback-player-settings-panel.md @@ -1,7 +1,6 @@ --- type: feature area: playback -highlight: Player settings panel --- Audio, subtitles, quality, speed and aspect ratio now live in one settings diff --git a/.changes/playback-up-next-card.md b/.changes/playback-up-next-card.md index 670036029..96f9cc6fa 100644 --- a/.changes/playback-up-next-card.md +++ b/.changes/playback-up-next-card.md @@ -1,7 +1,6 @@ --- type: feature area: playback -highlight: Up next in the player --- In the last minutes of a series episode the player shows an "Up next" card diff --git a/.changes/settings-search.md b/.changes/settings-search.md index 137d7eff1..0b27dc810 100644 --- a/.changes/settings-search.md +++ b/.changes/settings-search.md @@ -1,7 +1,7 @@ --- type: feature area: settings -highlight: Search your settings +screenshot: settings-search --- Settings are now searchable: type in the search box on the Settings page to diff --git a/tools/release/capture-navigation-setup-actions.ts b/tools/release/capture-navigation-setup-actions.ts index cbeb140aa..6bb49bf1b 100644 --- a/tools/release/capture-navigation-setup-actions.ts +++ b/tools/release/capture-navigation-setup-actions.ts @@ -164,6 +164,36 @@ async function openSettingsEpg(page: Page): Promise { await page.waitForTimeout(500); } +/** + * Settings with a term typed into the header search, so the page shows the + * ranked results list and the per-section match counts instead of a section. + * The term lives only in the `q` query param: the next action's navigation + * clears it, and nothing is staged in the settings form. + */ +async function openSettingsSearch( + page: Page, + term: string | null +): Promise { + if (!term) { + throw new Error('open-settings-search needs a term: open-settings-search='); + } + + await openSettings(page); + await page + .locator('app-workspace-shell-header input[type="search"]') + .fill(term, { timeout: 10_000 }); + await page.waitForURL(/\/workspace\/settings\/general\?q=/, { + timeout: 15_000, + }); + const results = page.locator('[data-test-id="settings-search-results"]'); + await results.waitFor({ state: 'visible', timeout: 15_000 }); + await results + .locator('[data-test-id^="settings-search-result-"]') + .first() + .waitFor({ state: 'visible', timeout: 10_000 }); + await settleUi(page); +} + /* ------------------------------------------------------------------ */ /* Remote control (guide shots) */ /* ------------------------------------------------------------------ */ @@ -301,6 +331,7 @@ export const SETUP_ACTIONS: Readonly> = { 'open-add-playlist-stalker': openAddPlaylistStalker, 'open-add-playlist-m3u-url': openAddPlaylistM3uUrl, 'open-settings-epg': openSettingsEpg, + 'open-settings-search': openSettingsSearch, 'open-settings-tmdb': openSettingsTmdb, 'open-settings-remote-control': openSettingsRemoteControl, 'enable-remote-control': enableRemoteControl, diff --git a/tools/release/project.json b/tools/release/project.json index 6b56d349c..c71c7dedd 100644 --- a/tools/release/project.json +++ b/tools/release/project.json @@ -21,6 +21,7 @@ "{workspaceRoot}/tools/release/nightly-version.mjs", "{workspaceRoot}/tools/release/screenshot-guards.mjs", "{workspaceRoot}/tools/release/screenshots.manifest.json", + "{workspaceRoot}/tools/release/capture-navigation-*-actions.ts", "{workspaceRoot}/.github/workflows/build-and-make.yaml", "{workspaceRoot}/tools/release/release-notes.test.mjs", "{workspaceRoot}/tools/release/release-note-gate.test.mjs", diff --git a/tools/release/screenshot-guards.mjs b/tools/release/screenshot-guards.mjs index 9d7641010..a805f8402 100644 --- a/tools/release/screenshot-guards.mjs +++ b/tools/release/screenshot-guards.mjs @@ -70,6 +70,7 @@ export const KNOWN_ACTIONS = [ 'open-m3u-channel-menu', 'open-epg-mapping-dialog', 'open-settings-tmdb', + 'open-settings-search', ]; /** diff --git a/tools/release/screenshot-guards.test.mjs b/tools/release/screenshot-guards.test.mjs index fa61b90b3..f29706bfb 100644 --- a/tools/release/screenshot-guards.test.mjs +++ b/tools/release/screenshot-guards.test.mjs @@ -26,6 +26,7 @@ import { snapshotDatabaseState, stubbedResponseFor, DEFAULT_SHOT_GROUP, + KNOWN_ACTIONS, FICTIONAL_STALKER_MAC, outputDirectoryFor, shotGroup, @@ -81,6 +82,35 @@ describe('manifest validation', () => { assert.deepEqual(validateManifest(validManifest()), []); }); + it('accepts the committed screenshots.manifest.json', () => { + const manifest = JSON.parse( + readFileSync(new URL('./screenshots.manifest.json', import.meta.url), 'utf8') + ); + + assert.deepEqual(validateManifest(manifest), []); + }); + + it('knows exactly the setup actions the capture navigation dispatches', () => { + // The dispatcher is TypeScript and cannot be imported here, so read + // the action tables' keys from source: an action added on one side + // only would fail the manifest check or the capture run. + const dir = new URL('./', import.meta.url); + const dispatched = readdirSync(dir) + .filter((name) => /^capture-navigation-.+-actions\.ts$/.test(name)) + .flatMap((name) => { + const source = readFileSync(new URL(name, dir), 'utf8'); + const table = source.match( + /_ACTIONS: Readonly> = \{([^}]*)\}/ + ); + assert.ok(table, `${name} exports no action table`); + return [...table[1].matchAll(/'([a-z0-9-]+)':/g)].map( + ([, action]) => action + ); + }); + + assert.deepEqual([...dispatched].sort(), [...KNOWN_ACTIONS].sort()); + }); + it('rejects unknown setup actions, bad slugs and duplicates', () => { const manifest = validManifest(); manifest.shots.push( diff --git a/tools/release/screenshots.manifest.json b/tools/release/screenshots.manifest.json index d9dc53582..ec58e8b06 100644 --- a/tools/release/screenshots.manifest.json +++ b/tools/release/screenshots.manifest.json @@ -23,6 +23,13 @@ "open-settings" ] }, + { + "slug": "settings-search", + "title": "Settings search results", + "setup": [ + "open-settings-search=player" + ] + }, { "slug": "xtream-vod-details", "title": "Movie details",