fix(settings): clear an Xtream detail from a hidden category synchronously on relock

The synchronous relock step now clears a selected Xtream item whose
category the visible category list cannot place (a manually hidden
category opened through search), instead of leaving it usable until the
awaited reloads and lookup finish.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-09-27 13:20:05 +02:00
1 parent 92382052d8
commit e9afb56017
3 files changed
+36 -4

No files matched your search

@@ -349,6 +349,33 @@ describe('ParentalLockEnforcementService', () => {
expect(xtreamStore.refreshSearchResults).toHaveBeenCalled();
});
it('clears on relock, synchronously, a detail whose category is not in the visible list', () => {
// Opened through search from a manually hidden category: the
// on-screen list cannot place it, and the unfiltered lookup is
// an awaited read that may hang.
router.url = '/workspace/xtreams/xtream-1/vod/55/900';
xtreamStore.selectedItem.set({ category_id: 55 });
service.failClosedNow();
expect(xtreamStore.setSelectedItem).toHaveBeenCalledWith(null);
expect(router.navigate).toHaveBeenCalledWith([
'/workspace',
'xtreams',
'xtream-1',
'vod',
]);
});
it('keeps a detail on relock whose visible category is not locked', () => {
router.url = '/workspace/xtreams/xtream-1/vod/7/900';
xtreamStore.selectedItem.set({ category_id: 7 });
service.failClosedNow();
expect(xtreamStore.setSelectedItem).not.toHaveBeenCalled();
});
it('fails closed synchronously on relock: detail, catalog and search', () => {
router.url = '/workspace/xtreams/xtream-1/vod/42';
lockProvider(70);
@@ -223,8 +223,10 @@ export class ParentalLockEnforcementService {
* Clears a selected Xtream item whose category the lock store already
* says is locked. Electron rows carry the SQLite category row id; the
* category list still on screen maps it to the provider id the store is
* keyed by, the PWA carries the provider id directly. An item that
* cannot be placed is left to the post-reload check.
* keyed by, the PWA carries the provider id directly. An item whose
* category is not in that list (a manually hidden category, opened
* through search) cannot be judged without an awaited read that may
* hang, so it is cleared too: fail closed.
*/
private stepOffLockedXtreamSelection(
playlistId: string,
@@ -249,7 +251,8 @@ export class ParentalLockEnforcementService {
) as { xtream_id?: number; category_id?: string } | undefined;
const providerId = Number(category?.xtream_id ?? category?.category_id);
if (
!Number.isFinite(providerId) ||
category &&
Number.isFinite(providerId) &&
!this.parentalLock.isXtreamCategoryLocked(
playlistId,
categoryType,
+3 -1
View File
@@ -188,7 +188,9 @@ on either side.
database answers — ahead of the serialized apply queue, so an earlier
apply still waiting on a slow or hung read cannot delay it: the selected detail is stepped off synchronously when
the lock store already names its category (the pre-reload category list
maps Electron's row id to the provider id), then `withholdCatalog()`
maps Electron's row id to the provider id) or when that list cannot place
it at all (a manually hidden category opened through search), then
`withholdCatalog()`
empties every catalog list and `clearSearchResults()` the stored search
(retiring a search still in flight, which was issued under the previous
lock state) before the filtered reads refill them; both reloads take a publish guard