From 6579151dcf91aee4fe6cd2da59980da4e409600d Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 20 Sep 2026 20:16:40 +0200 Subject: [PATCH] fix(dashboard): keep other EPG scopes when one is retired mid-tick forkJoin emits nothing when one input completes without a value, which is exactly what the EPG source-change guard does to an in-flight lookup. One retired or failing scope would therefore blank every other scope's answer for that tick; each group now contributes an empty map instead. Co-Authored-By: Claude Opus 5 --- .../workspace-dashboard-rails.component.ts | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.ts b/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.ts index 68fc94715..549d245d8 100644 --- a/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.ts +++ b/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.ts @@ -8,7 +8,16 @@ import { untracked, } from '@angular/core'; import { toObservable, toSignal } from '@angular/core/rxjs-interop'; -import { forkJoin, interval, map, of, startWith, switchMap } from 'rxjs'; +import { + catchError, + defaultIfEmpty, + forkJoin, + interval, + map, + of, + startWith, + switchMap, +} from 'rxjs'; import { EpgService } from '@iptvnator/epg/data-access'; import { type EpgProgram, @@ -340,7 +349,30 @@ export class WorkspaceDashboardRailsComponent { map((programs) => ({ scopeKey: group.scopeKey, programs, - })) + })), + // One scope retired by an EPG + // source change, or failing, + // must not blank every other + // scope's answer for the tick: + // `forkJoin` emits nothing at + // all when one input completes + // empty. + defaultIfEmpty({ + scopeKey: group.scopeKey, + programs: new Map< + string, + EpgProgram | null + >(), + }), + catchError(() => + of({ + scopeKey: group.scopeKey, + programs: new Map< + string, + EpgProgram | null + >(), + }) + ) ) ) ).pipe(