From 2ee2d033de9a100028a0c21014fd5dbe9e9a51ff Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Thu, 15 Jan 2026 19:01:11 +0100 Subject: [PATCH] fix(offline-banner): only show when cloud features are configured The offline banner now only appears when the user has cloud sync (Dropbox, WebDAV, or SuperSync) or enabled issue providers configured. Users with LocalFile sync and no issue providers will no longer see the misleading "Syncing will not work" banner when going offline. --- src/app/core/startup/startup.service.spec.ts | 9 +++++++ src/app/core/startup/startup.service.ts | 25 +++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/app/core/startup/startup.service.spec.ts b/src/app/core/startup/startup.service.spec.ts index 0bcee05ce..6666a1d06 100644 --- a/src/app/core/startup/startup.service.spec.ts +++ b/src/app/core/startup/startup.service.spec.ts @@ -16,6 +16,9 @@ import { TrackingReminderService } from '../../features/tracking-reminder/tracki import { of } from 'rxjs'; import { signal } from '@angular/core'; import { LS } from '../persistence/storage-keys.const'; +import { provideMockStore } from '@ngrx/store/testing'; +import { selectSyncConfig } from '../../features/config/store/global-config.reducer'; +import { selectEnabledIssueProviders } from '../../features/issue/store/issue-provider.selectors'; describe('StartupService', () => { let service: StartupService; @@ -108,6 +111,12 @@ describe('StartupService', () => { }, { provide: ProjectService, useValue: projectServiceSpy }, { provide: TrackingReminderService, useValue: trackingReminderServiceSpy }, + provideMockStore({ + selectors: [ + { selector: selectSyncConfig, value: { syncProvider: null } }, + { selector: selectEnabledIssueProviders, value: [] }, + ], + }), ], }); diff --git a/src/app/core/startup/startup.service.ts b/src/app/core/startup/startup.service.ts index a3278d6c7..b348c732d 100644 --- a/src/app/core/startup/startup.service.ts +++ b/src/app/core/startup/startup.service.ts @@ -21,7 +21,12 @@ import { isOnline$ } from '../../util/is-online'; import { LS } from '../persistence/storage-keys.const'; import { getDbDateStr } from '../../util/get-db-date-str'; import { DialogPleaseRateComponent } from '../../features/dialog-please-rate/dialog-please-rate.component'; -import { take } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; +import { combineLatest } from 'rxjs'; +import { Store } from '@ngrx/store'; +import { selectSyncConfig } from '../../features/config/store/global-config.reducer'; +import { selectEnabledIssueProviders } from '../../features/issue/store/issue-provider.selectors'; +import { LegacySyncProvider } from '../../imex/sync/legacy-sync-provider.model'; import { GlobalConfigState } from '../../features/config/global-config.model'; import { IPC } from '../../../../electron/shared-with-frontend/ipc-events.const'; import { IpcRendererEvent } from 'electron'; @@ -51,6 +56,7 @@ export class StartupService { private _projectService = inject(ProjectService); private _trackingReminderService = inject(TrackingReminderService); private _opLogStore = inject(OperationLogStoreService); + private _store = inject(Store); constructor() { // Initialize electron error handler in an effect @@ -235,8 +241,21 @@ export class StartupService { } private _initOfflineBanner(): void { - isOnline$.subscribe((isOnlineIn) => { - if (!isOnlineIn) { + const needsInternet$ = combineLatest([ + this._store.select(selectSyncConfig), + this._store.select(selectEnabledIssueProviders), + ]).pipe( + map(([syncConfig, enabledIssueProviders]) => { + const hasCloudSync = + syncConfig.syncProvider !== null && + syncConfig.syncProvider !== LegacySyncProvider.LocalFile; + const hasIssueProviders = enabledIssueProviders.length > 0; + return hasCloudSync || hasIssueProviders; + }), + ); + + combineLatest([isOnline$, needsInternet$]).subscribe(([isOnline, needsInternet]) => { + if (!isOnline && needsInternet) { this._bannerService.open({ id: BannerId.Offline, ico: 'cloud_off',