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=<term>` 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 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-09-29 19:39:59 +02:00
1 parent f38c6f86d1
commit f0b5cd6b4e
6 files changed
+71

No files matched your search

@@ -1,6 +1,7 @@
---
type: perf
area: electron
highlight: Faster startup
---
The desktop app now opens its window before it prepares the portal, program
+1
View File
@@ -1,6 +1,7 @@
---
type: feature
area: settings
screenshot: settings-search
highlight: Search your settings
---
@@ -164,6 +164,36 @@ async function openSettingsEpg(page: Page): Promise<void> {
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<void> {
if (!term) {
throw new Error('open-settings-search needs a term: open-settings-search=<term>');
}
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<Record<string, CaptureAction>> = {
'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,
+1
View File
@@ -70,6 +70,7 @@ export const KNOWN_ACTIONS = [
'open-m3u-channel-menu',
'open-epg-mapping-dialog',
'open-settings-tmdb',
'open-settings-search',
];
/**
+30
View File
@@ -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<Record<string, CaptureAction>> = \{([^}]*)\}/
);
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(
+7
View File
@@ -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",