From 5953e60d9a8b84dbeffc36289d0d2f69aa7f45e4 Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 6 Sep 2026 23:54:52 +0200 Subject: [PATCH] fix(xtream): never report another panel's status for the selected playlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review follow-up (Greptile): callers gate content initialization on the value `checkPortalStatus()` returns for whatever is selected NOW. When the answer no longer describes the selected playlist (source switch or in-place edit during the request), the store's own verdict about the current selection is returned instead of the old panel's status — on success and on failure alike. Co-Authored-By: Claude Fable 5.1 --- .../stores/features/with-portal.feature.spec.ts | 9 ++++++--- .../lib/stores/features/with-portal.feature.ts | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.spec.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.spec.ts index 8aeab6eae..da2d39242 100644 --- a/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.spec.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.spec.ts @@ -242,7 +242,9 @@ describe('withPortal', () => { server_info: { timezone: 'Europe/London' }, }); - await expect(pending).resolves.toBe('active'); + // The answer describes A; callers gating content init on the + // result get the store's verdict about B instead. + await expect(pending).resolves.toBe('unavailable'); expect(store.currentPlaylist()).toEqual(other); expect(store.portalStatus()).toBe('unavailable'); expect(transformPlaylistMeta).toHaveBeenCalledWith( @@ -277,7 +279,7 @@ describe('withPortal', () => { server_info: { timezone: 'Europe/London' }, }); - await expect(pending).resolves.toBe('active'); + await expect(pending).resolves.toBe('unavailable'); expect(store.currentPlaylist()).toEqual(moved); expect(store.portalStatus()).toBe('unavailable'); expect(storedPlaylist.serverTimezone).toBeUndefined(); @@ -326,7 +328,8 @@ describe('withPortal', () => { fail(new Error('panel down')); - await expect(pending).resolves.toBe('unavailable'); + // A's failure says nothing about B, so the caller gets B's verdict. + await expect(pending).resolves.toBe('active'); expect(store.portalStatus()).toBe('active'); }); diff --git a/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts index f9a078f44..fcb3f16bd 100644 --- a/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts @@ -199,10 +199,10 @@ export function withPortal() { // request may hand the old panel's status or clock // to the new one. const current = store.currentPlaylist(); - if ( + const describesCurrent = current?.id === playlist.id && - answersFor(current, credentials) - ) { + answersFor(current, credentials); + if (describesCurrent) { patchState(store, { portalStatus, currentPlaylist: { @@ -226,7 +226,12 @@ export function withPortal() { serverTimezone ); } - return portalStatus; + // Callers gate content initialization on this value + // for whatever is selected NOW; an answer about + // another panel must not unblock it. + return describesCurrent + ? portalStatus + : store.portalStatus(); } catch (error) { logger.error('Error checking portal status', error); const current = store.currentPlaylist(); @@ -236,7 +241,9 @@ export function withPortal() { ) { patchState(store, { portalStatus: 'unavailable' }); } - return 'unavailable'; + // The old panel's failure says nothing about a + // playlist selected or edited meanwhile. + return store.portalStatus(); } },