From 08e8329f9790511c99c0bca354fbfe5c92fa203f Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Sat, 14 Feb 2026 13:42:23 +0100 Subject: [PATCH] refactor(sync): consolidate LegacySyncProvider into SyncProviderId Remove duplicate LegacySyncProvider enum and use SyncProviderId everywhere. The two enums had identical values but were separate types for historical reasons, making the "Legacy" name misleading since providers are actively used. --- .../e2e-encryption-device-keys-DRAFT.md | 6 +- e2e/tests/sync/ENCRYPTION-E2E-STATUS.md | 12 ++-- src/app/core/startup/startup.service.ts | 4 +- .../config/form-cfgs/sync-form.const.ts | 52 +++++++------- .../features/config/global-config.model.ts | 5 +- .../store/global-config.reducer.spec.ts | 28 ++++---- .../dialog-sync-initial-cfg.component.ts | 14 ++-- .../sync/dropbox/store/dropbox.effects.ts | 3 +- .../imex/sync/legacy-sync-provider.model.ts | 7 -- src/app/imex/sync/legacy-sync.model.ts | 8 +-- src/app/imex/sync/sync-config.service.spec.ts | 67 +++++++++---------- .../imex/sync/sync-wrapper.service.spec.ts | 39 +++++------ src/app/imex/sync/sync-wrapper.service.ts | 3 +- src/app/imex/sync/sync.model.ts | 8 +-- .../sync-hydration.service.spec.ts | 32 ++++----- .../op-log/sync-providers/provider.const.ts | 4 +- .../config-page/config-page.component.spec.ts | 4 +- .../config-page/config-page.component.ts | 9 ++- 18 files changed, 142 insertions(+), 163 deletions(-) delete mode 100644 src/app/imex/sync/legacy-sync-provider.model.ts diff --git a/docs/long-term-plans/e2e-encryption-device-keys-DRAFT.md b/docs/long-term-plans/e2e-encryption-device-keys-DRAFT.md index 78594f61bd..33f99d8b24 100644 --- a/docs/long-term-plans/e2e-encryption-device-keys-DRAFT.md +++ b/docs/long-term-plans/e2e-encryption-device-keys-DRAFT.md @@ -534,7 +534,7 @@ export class DialogRecoveryPasswordComponent { type: 'tpl', className: 'tpl info-text', hideExpression: (m, v, field) => - field?.parent?.parent?.parent?.model.syncProvider !== LegacySyncProvider.SuperSync, + field?.parent?.parent?.parent?.model.syncProvider !== SyncProviderId.SuperSync, templateOptions: { tag: 'div', text: '🔒 End-to-end encryption enabled automatically' @@ -543,7 +543,7 @@ export class DialogRecoveryPasswordComponent { { type: 'btn', hideExpression: (m, v, field) => - field?.parent?.parent?.parent?.model.syncProvider !== LegacySyncProvider.SuperSync, + field?.parent?.parent?.parent?.model.syncProvider !== SyncProviderId.SuperSync, templateOptions: { text: 'Manage Recovery Password', onClick: async () => { @@ -570,7 +570,7 @@ export class DialogRecoveryPasswordComponent { ```typescript async updateSettingsFromForm(cfg: SyncConfig, isInitialSetup: boolean) { - if (cfg.syncProvider === LegacySyncProvider.SuperSync) { + if (cfg.syncProvider === SyncProviderId.SuperSync) { // Check if user has existing key const hasKey = await this._deviceKey.getMasterKey(); diff --git a/e2e/tests/sync/ENCRYPTION-E2E-STATUS.md b/e2e/tests/sync/ENCRYPTION-E2E-STATUS.md index c2f95236ff..2b00a6fce4 100644 --- a/e2e/tests/sync/ENCRYPTION-E2E-STATUS.md +++ b/e2e/tests/sync/ENCRYPTION-E2E-STATUS.md @@ -154,7 +154,7 @@ ngAfterViewInit(): void { this._subs.add( syncProviderControl.valueChanges .pipe(skip(1)) - .subscribe(async (newProvider: LegacySyncProvider | null) => { + .subscribe(async (newProvider: SyncProviderId | null) => { if (!newProvider) { return; } @@ -178,22 +178,22 @@ ngAfterViewInit(): void { // Create provider-specific config based on provider type let providerSpecificUpdate: Partial = {}; - if (newProvider === LegacySyncProvider.SuperSync && privateCfg) { + if (newProvider === SyncProviderId.SuperSync && privateCfg) { providerSpecificUpdate = { superSync: privateCfg as any, encryptKey: privateCfg.encryptKey || '', }; - } else if (newProvider === LegacySyncProvider.WebDAV && privateCfg) { + } else if (newProvider === SyncProviderId.WebDAV && privateCfg) { providerSpecificUpdate = { webDav: privateCfg as any, encryptKey: privateCfg.encryptKey || '', }; - } else if (newProvider === LegacySyncProvider.LocalFile && privateCfg) { + } else if (newProvider === SyncProviderId.LocalFile && privateCfg) { providerSpecificUpdate = { localFileSync: privateCfg as any, encryptKey: privateCfg.encryptKey || '', }; - } else if (newProvider === LegacySyncProvider.Dropbox && privateCfg) { + } else if (newProvider === SyncProviderId.Dropbox && privateCfg) { providerSpecificUpdate = { encryptKey: privateCfg.encryptKey || '', }; @@ -214,7 +214,7 @@ ngAfterViewInit(): void { }; // For non-SuperSync providers, update encryption from global config - if (newProvider !== LegacySyncProvider.SuperSync) { + if (newProvider !== SyncProviderId.SuperSync) { this._tmpUpdatedCfg = { ...this._tmpUpdatedCfg, isEncryptionEnabled: globalCfg?.isEncryptionEnabled || false, diff --git a/src/app/core/startup/startup.service.ts b/src/app/core/startup/startup.service.ts index 681d8d2dab..194283aede 100644 --- a/src/app/core/startup/startup.service.ts +++ b/src/app/core/startup/startup.service.ts @@ -26,7 +26,7 @@ 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 { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { GlobalConfigState } from '../../features/config/global-config.model'; import { IPC } from '../../../../electron/shared-with-frontend/ipc-events.const'; import { IpcRendererEvent } from 'electron'; @@ -272,7 +272,7 @@ export class StartupService { map(([syncConfig, enabledIssueProviders]) => { const hasCloudSync = syncConfig.syncProvider !== null && - syncConfig.syncProvider !== LegacySyncProvider.LocalFile; + syncConfig.syncProvider !== SyncProviderId.LocalFile; const hasIssueProviders = enabledIssueProviders.length > 0; return hasCloudSync || hasIssueProviders; }), diff --git a/src/app/features/config/form-cfgs/sync-form.const.ts b/src/app/features/config/form-cfgs/sync-form.const.ts index 332f49226d..01177ef9b2 100644 --- a/src/app/features/config/form-cfgs/sync-form.const.ts +++ b/src/app/features/config/form-cfgs/sync-form.const.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { T } from '../../../t.const'; import { ConfigFormSection, SyncConfig } from '../global-config.model'; -import { LegacySyncProvider } from '../../../imex/sync/legacy-sync-provider.model'; +import { SyncProviderId } from '../../../op-log/sync-providers/provider.const'; import { IS_ANDROID_WEB_VIEW } from '../../../util/is-android-web-view'; import { IS_ELECTRON } from '../../../app.constants'; import { fileSyncDroid, fileSyncElectron } from '../../../op-log/model/model-config'; @@ -64,7 +64,7 @@ const createWebdavFormFields = (options: { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.WebDAV, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.WebDAV, }, }, { @@ -76,7 +76,7 @@ const createWebdavFormFields = (options: { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.WebDAV, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.WebDAV, }, }, { @@ -89,7 +89,7 @@ const createWebdavFormFields = (options: { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.WebDAV, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.WebDAV, }, }, { @@ -101,7 +101,7 @@ const createWebdavFormFields = (options: { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.WebDAV, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.WebDAV, }, }, ]; @@ -127,14 +127,14 @@ export const SYNC_FORM: ConfigFormSection = { label: T.F.SYNC.FORM.L_SYNC_PROVIDER, required: true, options: [ - { label: 'SuperSync (Beta)', value: LegacySyncProvider.SuperSync }, - { label: LegacySyncProvider.Dropbox, value: LegacySyncProvider.Dropbox }, - { label: 'WebDAV (experimental)', value: LegacySyncProvider.WebDAV }, + { label: 'SuperSync (Beta)', value: SyncProviderId.SuperSync }, + { label: SyncProviderId.Dropbox, value: SyncProviderId.Dropbox }, + { label: 'WebDAV (experimental)', value: SyncProviderId.WebDAV }, ...(IS_ELECTRON || IS_ANDROID_WEB_VIEW ? [ { label: 'LocalFile (experimental)', - value: LegacySyncProvider.LocalFile, + value: SyncProviderId.LocalFile, }, ] : []), @@ -143,7 +143,7 @@ export const SYNC_FORM: ConfigFormSection = { }, { hideExpression: (m, v, field) => - field?.parent?.model.syncProvider !== LegacySyncProvider.LocalFile || + field?.parent?.model.syncProvider !== SyncProviderId.LocalFile || IS_ANDROID_WEB_VIEW, resetOnHide: false, key: 'localFileSync', @@ -166,14 +166,14 @@ export const SYNC_FORM: ConfigFormSection = { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.LocalFile, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.LocalFile, }, }, ], }, { hideExpression: (m, v, field) => - field?.parent?.model.syncProvider !== LegacySyncProvider.LocalFile || + field?.parent?.model.syncProvider !== SyncProviderId.LocalFile || !IS_ANDROID_WEB_VIEW, resetOnHide: false, key: 'localFileSync', @@ -197,7 +197,7 @@ export const SYNC_FORM: ConfigFormSection = { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.LocalFile, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.LocalFile, }, }, ], @@ -206,7 +206,7 @@ export const SYNC_FORM: ConfigFormSection = { // WebDAV provider form fields { hideExpression: (m, v, field) => - field?.parent?.model.syncProvider !== LegacySyncProvider.WebDAV, + field?.parent?.model.syncProvider !== SyncProviderId.WebDAV, resetOnHide: false, key: 'webDav', fieldGroup: createWebdavFormFields({ @@ -221,7 +221,7 @@ export const SYNC_FORM: ConfigFormSection = { // Note: No key needed - Dropbox credentials stored privately via SyncCredentialStore { hideExpression: (m, v, field) => - field?.parent?.model.syncProvider !== LegacySyncProvider.Dropbox, + field?.parent?.model.syncProvider !== SyncProviderId.Dropbox, resetOnHide: false, // Custom marker for identifying this field group in config-page.component.ts props: { dropboxAuth: true } as any, @@ -254,7 +254,7 @@ export const SYNC_FORM: ConfigFormSection = { // hideExpression: ((model: DropboxSyncConfig) => !model.accessToken), // Hide for SuperSync (uses fixed interval) and when manual sync only is enabled hideExpression: (m, v, field) => - field?.parent?.model.syncProvider === LegacySyncProvider.SuperSync || + field?.parent?.model.syncProvider === SyncProviderId.SuperSync || field?.parent?.model.isManualSyncOnly === true, resetOnHide: true, templateOptions: { @@ -269,7 +269,7 @@ export const SYNC_FORM: ConfigFormSection = { type: 'checkbox', // Only show for file-based providers (Dropbox, WebDAV, LocalFile) hideExpression: (m, v, field) => - field?.parent?.model.syncProvider === LegacySyncProvider.SuperSync || + field?.parent?.model.syncProvider === SyncProviderId.SuperSync || field?.parent?.model.syncProvider === null, templateOptions: { label: T.F.SYNC.FORM.L_MANUAL_SYNC_ONLY, @@ -300,8 +300,7 @@ export const SYNC_FORM: ConfigFormSection = { btnStyle: 'stroked', onClick: async (field: FormlyFieldConfig) => { const isSuperSync = - field?.parent?.parent?.model?.syncProvider === - LegacySyncProvider.SuperSync; + field?.parent?.parent?.model?.syncProvider === SyncProviderId.SuperSync; const result = isSuperSync ? await openEncryptionPasswordChangeDialog() : await openEncryptionPasswordChangeDialogForFileBased(); @@ -318,8 +317,7 @@ export const SYNC_FORM: ConfigFormSection = { btnStyle: 'stroked', onClick: async (field: FormlyFieldConfig) => { const isSuperSync = - field?.parent?.parent?.model?.syncProvider === - LegacySyncProvider.SuperSync; + field?.parent?.parent?.model?.syncProvider === SyncProviderId.SuperSync; const result = isSuperSync ? await openDisableEncryptionDialog() : await openDisableEncryptionDialogForFileBased(); @@ -348,7 +346,7 @@ export const SYNC_FORM: ConfigFormSection = { { type: 'collapsible', hideExpression: (m, v, field) => - field?.parent?.model.syncProvider === LegacySyncProvider.SuperSync, + field?.parent?.model.syncProvider === SyncProviderId.SuperSync, props: { label: T.G.ADVANCED_CFG }, fieldGroup: [ { @@ -361,7 +359,7 @@ export const SYNC_FORM: ConfigFormSection = { // Enable encryption button for file-based providers (shown when encryption is disabled) { hideExpression: (m: any, v: any, field?: FormlyFieldConfig) => - field?.parent?.parent?.model.syncProvider === LegacySyncProvider.SuperSync || + field?.parent?.parent?.model.syncProvider === SyncProviderId.SuperSync || m.isEncryptionEnabled, type: 'btn', className: 'e2e-file-based-enable-encryption-btn', @@ -388,7 +386,7 @@ export const SYNC_FORM: ConfigFormSection = { fieldGroup: [ { hideExpression: (m, v, field) => - field?.parent?.parent?.model.syncProvider !== LegacySyncProvider.SuperSync, + field?.parent?.parent?.model.syncProvider !== SyncProviderId.SuperSync, type: 'btn', templateOptions: { text: T.F.SYNC.FORM.SUPER_SYNC.BTN_GET_TOKEN, @@ -403,7 +401,7 @@ export const SYNC_FORM: ConfigFormSection = { }, { hideExpression: (m, v, field) => - field?.parent?.parent?.model.syncProvider !== LegacySyncProvider.SuperSync, + field?.parent?.parent?.model.syncProvider !== SyncProviderId.SuperSync, key: 'accessToken', type: 'textarea', className: 'e2e-accessToken', @@ -414,14 +412,14 @@ export const SYNC_FORM: ConfigFormSection = { }, expressions: { 'props.required': (field: FormlyFieldConfig) => - field?.parent?.parent?.model?.syncProvider === LegacySyncProvider.SuperSync, + field?.parent?.parent?.model?.syncProvider === SyncProviderId.SuperSync, }, }, // Advanced settings for SuperSync { type: 'collapsible', hideExpression: (m, v, field) => - field?.parent?.parent?.model.syncProvider !== LegacySyncProvider.SuperSync, + field?.parent?.parent?.model.syncProvider !== SyncProviderId.SuperSync, props: { label: T.G.ADVANCED_CFG }, fieldGroup: [ // Enable encryption button for SuperSync (shown when encryption is disabled) diff --git a/src/app/features/config/global-config.model.ts b/src/app/features/config/global-config.model.ts index 6659733b75..50cbf6b44b 100644 --- a/src/app/features/config/global-config.model.ts +++ b/src/app/features/config/global-config.model.ts @@ -1,7 +1,7 @@ import { FormlyFieldConfig } from '@ngx-formly/core'; import { LanguageCode, DateTimeLocale } from '../../core/locale.constants'; -import { LegacySyncProvider } from '../../imex/sync/legacy-sync-provider.model'; +import { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { ProjectCfgFormKey } from '../project/project.model'; import { KeyboardConfig } from './keyboard-config.model'; import { TaskReminderOptionId } from '../tasks/task.model'; @@ -162,8 +162,7 @@ export type SyncConfig = Readonly<{ isEnabled: boolean; isEncryptionEnabled?: boolean; isCompressionEnabled?: boolean; - // TODO migrate to SyncProviderId - syncProvider: LegacySyncProvider | null; + syncProvider: SyncProviderId | null; syncInterval: number; isManualSyncOnly?: boolean; diff --git a/src/app/features/config/store/global-config.reducer.spec.ts b/src/app/features/config/store/global-config.reducer.spec.ts index 950f1928f5..a8723d93c8 100644 --- a/src/app/features/config/store/global-config.reducer.spec.ts +++ b/src/app/features/config/store/global-config.reducer.spec.ts @@ -19,7 +19,7 @@ import { } from './global-config.reducer'; import { loadAllData } from '../../../root-store/meta/load-all-data.action'; import { GlobalConfigState } from '../global-config.model'; -import { LegacySyncProvider } from '../../../imex/sync/legacy-sync-provider.model'; +import { SyncProviderId } from '../../../op-log/sync-providers/provider.const'; import { AppDataComplete } from '../../../op-log/model/model-config'; import { DEFAULT_GLOBAL_CONFIG } from '../default-global-config.const'; @@ -98,7 +98,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.SuperSync, // Snapshot has user's provider + syncProvider: SyncProviderId.SuperSync, // Snapshot has user's provider }, }; @@ -110,7 +110,7 @@ describe('GlobalConfigReducer', () => { ); // Should use snapshot's syncProvider since oldState has null - expect(result.sync.syncProvider).toBe(LegacySyncProvider.SuperSync); + expect(result.sync.syncProvider).toBe(SyncProviderId.SuperSync); }); it('should preserve syncProvider from oldState when loading synced data', () => { @@ -118,7 +118,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, }, }; @@ -142,7 +142,7 @@ describe('GlobalConfigReducer', () => { ); // syncProvider should be preserved from oldState - expect(result.sync.syncProvider).toBe(LegacySyncProvider.SuperSync); + expect(result.sync.syncProvider).toBe(SyncProviderId.SuperSync); // Other config should be updated from synced data expect(result.misc.isDisableAnimations).toBe(true); }); @@ -152,7 +152,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, }, }; @@ -160,7 +160,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, }, }; @@ -172,7 +172,7 @@ describe('GlobalConfigReducer', () => { ); // syncProvider should be preserved from oldState, not overwritten - expect(result.sync.syncProvider).toBe(LegacySyncProvider.WebDAV); + expect(result.sync.syncProvider).toBe(SyncProviderId.WebDAV); }); it('should update other sync config properties while preserving syncProvider', () => { @@ -180,7 +180,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, }, }; @@ -203,7 +203,7 @@ describe('GlobalConfigReducer', () => { ); // syncProvider preserved - expect(result.sync.syncProvider).toBe(LegacySyncProvider.SuperSync); + expect(result.sync.syncProvider).toBe(SyncProviderId.SuperSync); // Other sync settings updated expect(result.sync.syncInterval).toBe(600000); expect(result.sync.isCompressionEnabled).toBe(true); @@ -218,7 +218,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.SuperSync, // Not null = not sync hydration + syncProvider: SyncProviderId.SuperSync, // Not null = not sync hydration isEnabled: true, // User had sync enabled }, }; @@ -240,7 +240,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, isEnabled: true, // User has sync enabled }, }; @@ -264,7 +264,7 @@ describe('GlobalConfigReducer', () => { // isEnabled should be preserved from oldState, not overwritten by remote's false expect(result.sync.isEnabled).toBe(true); // syncProvider should also be preserved - expect(result.sync.syncProvider).toBe(LegacySyncProvider.SuperSync); + expect(result.sync.syncProvider).toBe(SyncProviderId.SuperSync); }); it('should preserve isEnabled=false from oldState during sync hydration', () => { @@ -273,7 +273,7 @@ describe('GlobalConfigReducer', () => { ...initialGlobalConfigState, sync: { ...initialGlobalConfigState.sync, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, isEnabled: false, // User has sync disabled locally }, }; diff --git a/src/app/imex/sync/dialog-sync-initial-cfg/dialog-sync-initial-cfg.component.ts b/src/app/imex/sync/dialog-sync-initial-cfg/dialog-sync-initial-cfg.component.ts index e3eddf5070..5d61d75fb5 100644 --- a/src/app/imex/sync/dialog-sync-initial-cfg/dialog-sync-initial-cfg.component.ts +++ b/src/app/imex/sync/dialog-sync-initial-cfg/dialog-sync-initial-cfg.component.ts @@ -21,7 +21,7 @@ import { FormlyConfigModule } from '../../../ui/formly-config.module'; import { FormlyModule } from '@ngx-formly/core'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { SyncConfig } from '../../../features/config/global-config.model'; -import { LegacySyncProvider } from '../legacy-sync-provider.model'; +import { SyncProviderId } from '../../../op-log/sync-providers/provider.const'; import { SyncConfigService } from '../sync-config.service'; import { SyncWrapperService } from '../sync-wrapper.service'; import { Subscription } from 'rxjs'; @@ -107,7 +107,7 @@ export class DialogSyncInitialCfgComponent implements AfterViewInit { this._subs.add( syncProviderControl.valueChanges .pipe(skip(1)) - .subscribe(async (newProvider: LegacySyncProvider | null) => { + .subscribe(async (newProvider: SyncProviderId | null) => { if (!newProvider) { return; } @@ -133,24 +133,24 @@ export class DialogSyncInitialCfgComponent implements AfterViewInit { // Create provider-specific config based on provider type let providerSpecificUpdate: Partial = {}; - if (newProvider === LegacySyncProvider.SuperSync && privateCfg) { + if (newProvider === SyncProviderId.SuperSync && privateCfg) { providerSpecificUpdate = { superSync: privateCfg as any, encryptKey: privateCfg.encryptKey || '', // SuperSync stores isEncryptionEnabled in privateCfg, not globalCfg isEncryptionEnabled: (privateCfg as any).isEncryptionEnabled || false, }; - } else if (newProvider === LegacySyncProvider.WebDAV && privateCfg) { + } else if (newProvider === SyncProviderId.WebDAV && privateCfg) { providerSpecificUpdate = { webDav: privateCfg as any, encryptKey: privateCfg.encryptKey || '', }; - } else if (newProvider === LegacySyncProvider.LocalFile && privateCfg) { + } else if (newProvider === SyncProviderId.LocalFile && privateCfg) { providerSpecificUpdate = { localFileSync: privateCfg as any, encryptKey: privateCfg.encryptKey || '', }; - } else if (newProvider === LegacySyncProvider.Dropbox && privateCfg) { + } else if (newProvider === SyncProviderId.Dropbox && privateCfg) { providerSpecificUpdate = { encryptKey: privateCfg.encryptKey || '', }; @@ -172,7 +172,7 @@ export class DialogSyncInitialCfgComponent implements AfterViewInit { }; // For non-SuperSync providers, update encryption from global config - if (newProvider !== LegacySyncProvider.SuperSync) { + if (newProvider !== SyncProviderId.SuperSync) { this._tmpUpdatedCfg = { ...this._tmpUpdatedCfg, isEncryptionEnabled: globalCfg?.isEncryptionEnabled || false, diff --git a/src/app/imex/sync/dropbox/store/dropbox.effects.ts b/src/app/imex/sync/dropbox/store/dropbox.effects.ts index 57f58bb886..5bb1c2c769 100644 --- a/src/app/imex/sync/dropbox/store/dropbox.effects.ts +++ b/src/app/imex/sync/dropbox/store/dropbox.effects.ts @@ -8,7 +8,6 @@ import { updateGlobalConfigSection } from '../../../../features/config/store/glo import { environment } from '../../../../../environments/environment'; import { SyncProviderManager } from '../../../../op-log/sync-providers/provider-manager.service'; import { DropboxPrivateCfg, SyncProviderId } from '../../../../op-log/sync-exports'; -import { LegacySyncProvider } from '../../legacy-sync-provider.model'; import { confirmDialog } from '../../../../util/native-dialogs'; @Injectable() @@ -26,7 +25,7 @@ export class DropboxEffects { ), tap(async ({ sectionCfg }) => { const syncCfg = sectionCfg as SyncConfig; - if (syncCfg.syncProvider !== LegacySyncProvider.Dropbox) { + if (syncCfg.syncProvider !== SyncProviderId.Dropbox) { return; } const provider = this._providerManager.getProviderById(SyncProviderId.Dropbox); diff --git a/src/app/imex/sync/legacy-sync-provider.model.ts b/src/app/imex/sync/legacy-sync-provider.model.ts deleted file mode 100644 index 07f0ed3a02..0000000000 --- a/src/app/imex/sync/legacy-sync-provider.model.ts +++ /dev/null @@ -1,7 +0,0 @@ -// NOTE: do not change!! -export enum LegacySyncProvider { - 'Dropbox' = 'Dropbox', - 'WebDAV' = 'WebDAV', - 'LocalFile' = 'LocalFile', - 'SuperSync' = 'SuperSync', -} diff --git a/src/app/imex/sync/legacy-sync.model.ts b/src/app/imex/sync/legacy-sync.model.ts index 713e571291..485b99c365 100644 --- a/src/app/imex/sync/legacy-sync.model.ts +++ b/src/app/imex/sync/legacy-sync.model.ts @@ -6,7 +6,7 @@ import { TaskRepeatCfgState } from '../../features/task-repeat-cfg/task-repeat-c import { TagState } from '../../features/tag/tag.model'; import { SimpleCounterState } from '../../features/simple-counter/simple-counter.model'; import { ProjectArchive } from '../../features/project/project-archive.model'; -import { LegacySyncProvider } from './legacy-sync-provider.model'; +import { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { ProjectState } from '../../features/project/project.model'; import { NoteState } from '../../features/note/note.model'; import { LocalSyncMetaForProvider } from './sync.model'; @@ -30,9 +30,9 @@ export interface LegacyAppBaseData { } export interface LocalSyncMetaModel { - [LegacySyncProvider.WebDAV]: LocalSyncMetaForProvider; - [LegacySyncProvider.Dropbox]: LocalSyncMetaForProvider; - [LegacySyncProvider.LocalFile]: LocalSyncMetaForProvider; + [SyncProviderId.WebDAV]: LocalSyncMetaForProvider; + [SyncProviderId.Dropbox]: LocalSyncMetaForProvider; + [SyncProviderId.LocalFile]: LocalSyncMetaForProvider; } // NOTE: [key:string] always refers to projectId diff --git a/src/app/imex/sync/sync-config.service.spec.ts b/src/app/imex/sync/sync-config.service.spec.ts index b0f2c29873..1e1d6a910b 100644 --- a/src/app/imex/sync/sync-config.service.spec.ts +++ b/src/app/imex/sync/sync-config.service.spec.ts @@ -4,8 +4,7 @@ import { SyncProviderManager } from '../../op-log/sync-providers/provider-manage import { GlobalConfigService } from '../../features/config/global-config.service'; import { BehaviorSubject } from 'rxjs'; import { SyncConfig } from '../../features/config/global-config.model'; -import { LegacySyncProvider } from './legacy-sync-provider.model'; -import { SyncProviderId } from '../../op-log/sync-exports'; +import { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { DEFAULT_GLOBAL_CONFIG } from '../../features/config/default-global-config.const'; import { first } from 'rxjs/operators'; import { WrappedProviderService } from '../../op-log/sync-providers/wrapped-provider.service'; @@ -29,7 +28,7 @@ describe('SyncConfigService', () => { mockSyncConfig$ = new BehaviorSubject({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, isEncryptionEnabled: true, }); @@ -78,7 +77,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'secret-key', @@ -95,7 +94,7 @@ describe('SyncConfigService', () => { // Should only pass non-private data to global config expect(globalConfigService.updateSection).toHaveBeenCalledWith('sync', { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, }); @@ -122,7 +121,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'test-key', @@ -152,7 +151,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'test-key', @@ -191,7 +190,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.Dropbox, + syncProvider: SyncProviderId.Dropbox, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'dropbox-key', @@ -232,7 +231,7 @@ describe('SyncConfigService', () => { // Update settings without changing the provider const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.Dropbox, + syncProvider: SyncProviderId.Dropbox, syncInterval: 600000, // Changed interval isEncryptionEnabled: true, encryptKey: 'existing-key', // Same key @@ -277,7 +276,7 @@ describe('SyncConfigService', () => { // Form only provides baseUrl, accessToken is empty string (reset by Formly) const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 600000, // Changed interval (unrelated setting) superSync: { baseUrl: existingBaseUrl, @@ -318,7 +317,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, superSync: { baseUrl: 'https://example.com', @@ -360,7 +359,7 @@ describe('SyncConfigService', () => { // Form provides empty password (e.g., from resetOnHide or form state issue) const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 600000, webDav: { baseUrl: 'https://webdav.example.com', @@ -400,7 +399,7 @@ describe('SyncConfigService', () => { // User explicitly disables encryption (false should be respected) const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, superSync: { baseUrl: 'https://example.com', @@ -440,7 +439,7 @@ describe('SyncConfigService', () => { // Form provides only baseUrl, all other fields empty const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, webDav: { baseUrl: 'https://webdav.example.com', @@ -484,7 +483,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, webDav: { baseUrl: 'https://new.example.com', // Updated @@ -527,7 +526,7 @@ describe('SyncConfigService', () => { // Form provides empty path const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, syncInterval: 600000, localFileSync: { syncFolderPath: '', // Empty - should not overwrite @@ -556,7 +555,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: false, webDav: { @@ -599,7 +598,7 @@ describe('SyncConfigService', () => { const settings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'new-key', @@ -634,7 +633,7 @@ describe('SyncConfigService', () => { const initialSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'my-secret-password', @@ -665,7 +664,7 @@ describe('SyncConfigService', () => { mockSyncConfig$.next({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, isEncryptionEnabled: true, syncInterval: 300000, }); @@ -688,7 +687,7 @@ describe('SyncConfigService', () => { // Step 1: Simulate initial setup - user enables encryption const initialSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'test-password-123', @@ -708,7 +707,7 @@ describe('SyncConfigService', () => { mockSyncConfig$.next({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, isEncryptionEnabled: true, // This is saved correctly syncInterval: 300000, }); @@ -733,7 +732,7 @@ describe('SyncConfigService', () => { mockSyncConfig$.next({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, isEncryptionEnabled: false, // Encryption is disabled syncInterval: 300000, }); @@ -751,7 +750,7 @@ describe('SyncConfigService', () => { // Ensure our fix doesn't break other providers const webDavSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'webdav-password', @@ -793,7 +792,7 @@ describe('SyncConfigService', () => { // Step 1: User enables LocalFile sync with encryption const newSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'test-password-123', @@ -849,7 +848,7 @@ describe('SyncConfigService', () => { mockSyncConfig$.next({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, isEncryptionEnabled: true, syncInterval: 300000, }); @@ -877,7 +876,7 @@ describe('SyncConfigService', () => { mockSyncConfig$.next({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, isEncryptionEnabled: true, syncInterval: 300000, }); @@ -933,7 +932,7 @@ describe('SyncConfigService', () => { mockSyncConfig$.next({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, superSync: { baseUrl: customUrl, }, @@ -1314,7 +1313,7 @@ describe('SyncConfigService', () => { // Simulate form update with NO encryptKey (stale form model) const formSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: '', // Empty - simulating stale form model @@ -1362,7 +1361,7 @@ describe('SyncConfigService', () => { // Simulate form update with OLD password (stale form model from before dialog) const formSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: oldPassword, // Old - simulating stale form model @@ -1409,7 +1408,7 @@ describe('SyncConfigService', () => { const newFormPassword = 'new-webdav-password'; const formSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: newFormPassword, // New password from form @@ -1449,7 +1448,7 @@ describe('SyncConfigService', () => { // Simulate form update with password in settings.encryptKey (legacy path) const formSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: 'settings-level-password', // Password at settings level @@ -1496,7 +1495,7 @@ describe('SyncConfigService', () => { const formSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, isEncryptionEnabled: false, encryptKey: '', @@ -1550,7 +1549,7 @@ describe('SyncConfigService', () => { // from BEFORE the dialog updated the password const staleFormSettings: SyncConfig = { isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, syncInterval: 300000, isEncryptionEnabled: true, encryptKey: '', // STALE: Form model didn't have the new password diff --git a/src/app/imex/sync/sync-wrapper.service.spec.ts b/src/app/imex/sync/sync-wrapper.service.spec.ts index c1dbeaa96d..c150839a54 100644 --- a/src/app/imex/sync/sync-wrapper.service.spec.ts +++ b/src/app/imex/sync/sync-wrapper.service.spec.ts @@ -28,7 +28,6 @@ import { MissingRefreshTokenAPIError, } from '../../op-log/core/errors/sync-errors'; import { MAX_LWW_REUPLOAD_RETRIES } from '../../op-log/core/operation-log.const'; -import { LegacySyncProvider } from './legacy-sync-provider.model'; describe('SyncWrapperService', () => { let service: SyncWrapperService; @@ -49,7 +48,7 @@ describe('SyncWrapperService', () => { let configSubject: BehaviorSubject; let mockSyncCapableProvider: any; - const createMockSyncConfig = (provider: LegacySyncProvider | null): { sync: any } => ({ + const createMockSyncConfig = (provider: SyncProviderId | null): { sync: any } => ({ sync: { syncProvider: provider, syncInterval: 60000, @@ -57,9 +56,7 @@ describe('SyncWrapperService', () => { }); beforeEach(() => { - configSubject = new BehaviorSubject( - createMockSyncConfig(LegacySyncProvider.SuperSync), - ); + configSubject = new BehaviorSubject(createMockSyncConfig(SyncProviderId.SuperSync)); mockSyncCapableProvider = { uploadOperations: jasmine.createSpy('uploadOperations'), @@ -228,7 +225,7 @@ describe('SyncWrapperService', () => { describe('_sync() - Provider handling', () => { it('should call _syncVectorClockToPfapi for WebDAV provider', async () => { - configSubject.next(createMockSyncConfig(LegacySyncProvider.WebDAV)); + configSubject.next(createMockSyncConfig(SyncProviderId.WebDAV)); mockOpLogStore.getVectorClockEntry.and.returnValue( Promise.resolve({ clock: { clientA: 5 }, @@ -244,7 +241,7 @@ describe('SyncWrapperService', () => { }); it('should call _syncVectorClockToPfapi for Dropbox provider', async () => { - configSubject.next(createMockSyncConfig(LegacySyncProvider.Dropbox)); + configSubject.next(createMockSyncConfig(SyncProviderId.Dropbox)); mockOpLogStore.getVectorClockEntry.and.returnValue( Promise.resolve({ clock: { clientA: 5 }, @@ -259,7 +256,7 @@ describe('SyncWrapperService', () => { }); it('should NOT call _syncVectorClockToPfapi for SuperSync provider', async () => { - configSubject.next(createMockSyncConfig(LegacySyncProvider.SuperSync)); + configSubject.next(createMockSyncConfig(SyncProviderId.SuperSync)); await service.sync(); @@ -1067,8 +1064,8 @@ describe('SyncWrapperService', () => { }); describe('syncProviderId$', () => { - it('should convert LegacySyncProvider to SyncProviderId', (done) => { - configSubject.next(createMockSyncConfig(LegacySyncProvider.SuperSync)); + it('should emit SyncProviderId from sync config', (done) => { + configSubject.next(createMockSyncConfig(SyncProviderId.SuperSync)); service.syncProviderId$.subscribe((providerId) => { expect(providerId).toBe(SyncProviderId.SuperSync); @@ -1091,9 +1088,7 @@ describe('SyncWrapperService', () => { let isConfirmedSignal: ReturnType>; let signalConfigSubject: BehaviorSubject; - const createSignalMockConfig = ( - provider: LegacySyncProvider | null, - ): { sync: any } => ({ + const createSignalMockConfig = (provider: SyncProviderId | null): { sync: any } => ({ sync: { syncProvider: provider, syncInterval: 60000, @@ -1103,7 +1098,7 @@ describe('SyncWrapperService', () => { const createServiceWithSignal = (initialValue: boolean): SyncWrapperService => { isConfirmedSignal = signal(initialValue); signalConfigSubject = new BehaviorSubject( - createSignalMockConfig(LegacySyncProvider.SuperSync), + createSignalMockConfig(SyncProviderId.SuperSync), ); const signalMockSuperSyncStatusService = { @@ -1143,7 +1138,7 @@ describe('SyncWrapperService', () => { describe('with SuperSync provider', () => { it('should return true when SuperSyncStatusService.isConfirmedInSync is true', (done) => { signalService = createServiceWithSignal(true); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.SuperSync)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.SuperSync)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(true); @@ -1153,7 +1148,7 @@ describe('SyncWrapperService', () => { it('should return false when SuperSyncStatusService.isConfirmedInSync is false', (done) => { signalService = createServiceWithSignal(false); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.SuperSync)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.SuperSync)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(false); @@ -1165,7 +1160,7 @@ describe('SyncWrapperService', () => { describe('with file-based providers', () => { it('should return false for WebDAV when status service returns false', (done) => { signalService = createServiceWithSignal(false); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.WebDAV)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.WebDAV)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(false); @@ -1175,7 +1170,7 @@ describe('SyncWrapperService', () => { it('should return true for WebDAV when status service returns true', (done) => { signalService = createServiceWithSignal(true); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.WebDAV)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.WebDAV)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(true); @@ -1185,7 +1180,7 @@ describe('SyncWrapperService', () => { it('should return false for Dropbox when status service returns false', (done) => { signalService = createServiceWithSignal(false); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.Dropbox)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.Dropbox)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(false); @@ -1195,7 +1190,7 @@ describe('SyncWrapperService', () => { it('should return true for Dropbox when status service returns true', (done) => { signalService = createServiceWithSignal(true); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.Dropbox)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.Dropbox)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(true); @@ -1205,7 +1200,7 @@ describe('SyncWrapperService', () => { it('should return false for LocalFile when status service returns false', (done) => { signalService = createServiceWithSignal(false); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.LocalFile)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.LocalFile)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(false); @@ -1215,7 +1210,7 @@ describe('SyncWrapperService', () => { it('should return true for LocalFile when status service returns true', (done) => { signalService = createServiceWithSignal(true); - signalConfigSubject.next(createSignalMockConfig(LegacySyncProvider.LocalFile)); + signalConfigSubject.next(createSignalMockConfig(SyncProviderId.LocalFile)); signalService.superSyncIsConfirmedInSync$.subscribe((isConfirmed) => { expect(isConfirmed).toBe(true); diff --git a/src/app/imex/sync/sync-wrapper.service.ts b/src/app/imex/sync/sync-wrapper.service.ts index 5d45208e0f..b18d88eeb1 100644 --- a/src/app/imex/sync/sync-wrapper.service.ts +++ b/src/app/imex/sync/sync-wrapper.service.ts @@ -59,7 +59,6 @@ import { promiseTimeout } from '../../util/promise-timeout'; import { devError } from '../../util/dev-error'; import { alertDialog, confirmDialog } from '../../util/native-dialogs'; import { UserInputWaitStateService } from './user-input-wait-state.service'; -import { LegacySyncProvider } from './legacy-sync-provider.model'; import { SYNC_WAIT_TIMEOUT_MS, SYNC_REINIT_DELAY_MS } from './sync.const'; import { SuperSyncStatusService } from '../../op-log/sync/super-sync-status.service'; import { IS_ELECTRON } from '../../app.constants'; @@ -99,7 +98,7 @@ export class SyncWrapperService { syncInterval$: Observable = this.syncCfg$.pipe( map((cfg) => { if (cfg.isManualSyncOnly) return 0; - return cfg.syncProvider === LegacySyncProvider.SuperSync ? 60000 : cfg.syncInterval; + return cfg.syncProvider === SyncProviderId.SuperSync ? 60000 : cfg.syncInterval; }), ); diff --git a/src/app/imex/sync/sync.model.ts b/src/app/imex/sync/sync.model.ts index f2be6fd570..f872c20a63 100644 --- a/src/app/imex/sync/sync.model.ts +++ b/src/app/imex/sync/sync.model.ts @@ -6,7 +6,7 @@ import { TaskRepeatCfgState } from '../../features/task-repeat-cfg/task-repeat-c import { TagState } from '../../features/tag/tag.model'; import { SimpleCounterState } from '../../features/simple-counter/simple-counter.model'; import { ProjectArchive } from '../../features/project/project-archive.model'; -import { LegacySyncProvider } from './legacy-sync-provider.model'; +import { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { ProjectState } from '../../features/project/project.model'; import { NoteState } from '../../features/note/note.model'; import { PlannerState } from '../../features/planner/store/planner.reducer'; @@ -60,9 +60,9 @@ export interface LocalSyncMetaForProvider { } export interface LocalSyncMetaModel { - [LegacySyncProvider.WebDAV]: LocalSyncMetaForProvider; - [LegacySyncProvider.Dropbox]: LocalSyncMetaForProvider; - [LegacySyncProvider.LocalFile]: LocalSyncMetaForProvider; + [SyncProviderId.WebDAV]: LocalSyncMetaForProvider; + [SyncProviderId.Dropbox]: LocalSyncMetaForProvider; + [SyncProviderId.LocalFile]: LocalSyncMetaForProvider; } export type AppBaseDataEntityLikeStates = diff --git a/src/app/op-log/persistence/sync-hydration.service.spec.ts b/src/app/op-log/persistence/sync-hydration.service.spec.ts index 27ef28890e..1e73c4a3f0 100644 --- a/src/app/op-log/persistence/sync-hydration.service.spec.ts +++ b/src/app/op-log/persistence/sync-hydration.service.spec.ts @@ -9,7 +9,7 @@ import { VectorClockService } from '../sync/vector-clock.service'; import { ValidateStateService } from '../validation/validate-state.service'; import { loadAllData } from '../../root-store/meta/load-all-data.action'; import { ActionType, OpType } from '../core/operation.types'; -import { LegacySyncProvider } from '../../imex/sync/legacy-sync-provider.model'; +import { SyncProviderId } from '../sync-providers/provider.const'; import { DEFAULT_GLOBAL_CONFIG } from '../../features/config/default-global-config.const'; import { SnackService } from '../../core/snack/snack.service'; @@ -27,7 +27,7 @@ describe('SyncHydrationService', () => { const defaultLocalSyncConfig = { ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, }; beforeEach(() => { @@ -537,7 +537,7 @@ describe('SyncHydrationService', () => { const localSyncConfig = { ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, }; mockStore.select.and.returnValue(of(localSyncConfig)); @@ -548,7 +548,7 @@ describe('SyncHydrationService', () => { sync: { ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: false, // Another client had sync disabled! - syncProvider: LegacySyncProvider.Dropbox, // Different provider too + syncProvider: SyncProviderId.Dropbox, // Different provider too }, }, task: { ids: [], entities: {} }, @@ -568,7 +568,7 @@ describe('SyncHydrationService', () => { // Step 4: Verify the snapshot has PRESERVED local settings (not remote's false) expect(snapshotSync['isEnabled']).toBe(true); // Local value preserved! - expect(snapshotSync['syncProvider']).toBe(LegacySyncProvider.WebDAV); // Local provider preserved! + expect(snapshotSync['syncProvider']).toBe(SyncProviderId.WebDAV); // Local provider preserved! // Step 5: Simulate what happens on reload // The hydrator will call store.dispatch(loadAllData({ appDataComplete: snapshotState })) @@ -581,7 +581,7 @@ describe('SyncHydrationService', () => { // Final verification: The data dispatched to NgRx has correct local settings expect(dispatchedSync['isEnabled']).toBe(true); - expect(dispatchedSync['syncProvider']).toBe(LegacySyncProvider.WebDAV); + expect(dispatchedSync['syncProvider']).toBe(SyncProviderId.WebDAV); }); it('should preserve local isEnabled when remote has it disabled', async () => { @@ -590,7 +590,7 @@ describe('SyncHydrationService', () => { of({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, }), ); @@ -612,7 +612,7 @@ describe('SyncHydrationService', () => { const globalConfig = savedState['globalConfig'] as Record; const sync = globalConfig['sync'] as Record; expect(sync['isEnabled']).toBe(true); - expect(sync['syncProvider']).toBe(LegacySyncProvider.WebDAV); + expect(sync['syncProvider']).toBe(SyncProviderId.WebDAV); }); it('should preserve local isEnabled when remote has it enabled', async () => { @@ -621,7 +621,7 @@ describe('SyncHydrationService', () => { of({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: false, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, }), ); @@ -651,7 +651,7 @@ describe('SyncHydrationService', () => { of({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, }), ); @@ -660,7 +660,7 @@ describe('SyncHydrationService', () => { globalConfig: { sync: { isEnabled: false, - syncProvider: LegacySyncProvider.Dropbox, + syncProvider: SyncProviderId.Dropbox, }, }, }; @@ -677,7 +677,7 @@ describe('SyncHydrationService', () => { unknown >; const sync = globalConfig['sync'] as Record; - expect(sync['syncProvider']).toBe(LegacySyncProvider.WebDAV); + expect(sync['syncProvider']).toBe(SyncProviderId.WebDAV); expect(sync['isEnabled']).toBe(true); }); @@ -686,7 +686,7 @@ describe('SyncHydrationService', () => { of({ ...DEFAULT_GLOBAL_CONFIG.sync, isEnabled: true, - syncProvider: LegacySyncProvider.SuperSync, + syncProvider: SyncProviderId.SuperSync, }), ); @@ -694,7 +694,7 @@ describe('SyncHydrationService', () => { globalConfig: { sync: { isEnabled: false, - syncProvider: LegacySyncProvider.LocalFile, + syncProvider: SyncProviderId.LocalFile, }, }, }; @@ -707,7 +707,7 @@ describe('SyncHydrationService', () => { const savedGlobalConfig = savedState['globalConfig'] as Record; const savedSync = savedGlobalConfig['sync'] as Record; expect(savedSync['isEnabled']).toBe(true); - expect(savedSync['syncProvider']).toBe(LegacySyncProvider.SuperSync); + expect(savedSync['syncProvider']).toBe(SyncProviderId.SuperSync); // Check dispatch const dispatchCall = mockStore.dispatch.calls.mostRecent(); @@ -718,7 +718,7 @@ describe('SyncHydrationService', () => { .globalConfig as Record; const dispatchedSync = dispatchedGlobalConfig['sync'] as Record; expect(dispatchedSync['isEnabled']).toBe(true); - expect(dispatchedSync['syncProvider']).toBe(LegacySyncProvider.SuperSync); + expect(dispatchedSync['syncProvider']).toBe(SyncProviderId.SuperSync); }); }); }); diff --git a/src/app/op-log/sync-providers/provider.const.ts b/src/app/op-log/sync-providers/provider.const.ts index e624c83f04..30681c23c5 100644 --- a/src/app/op-log/sync-providers/provider.const.ts +++ b/src/app/op-log/sync-providers/provider.const.ts @@ -8,9 +8,7 @@ export enum SyncProviderId { /** * Type-safe conversion from string-based sync provider value to SyncProviderId. - * LegacySyncProvider and SyncProviderId have identical string values but are - * separate types for historical reasons. This provides safe conversion with - * runtime validation. + * Validates that a persisted string value is a valid SyncProviderId at runtime. */ export const toSyncProviderId = ( value: string | null | undefined, diff --git a/src/app/pages/config-page/config-page.component.spec.ts b/src/app/pages/config-page/config-page.component.spec.ts index 650d50e95d..a5432d6022 100644 --- a/src/app/pages/config-page/config-page.component.spec.ts +++ b/src/app/pages/config-page/config-page.component.spec.ts @@ -13,7 +13,7 @@ import { SyncWrapperService } from '../../imex/sync/sync-wrapper.service'; import { ShareService } from '../../core/share/share.service'; import { UserProfileService } from '../../features/user-profile/user-profile.service'; import { MatDialog } from '@angular/material/dialog'; -import { LegacySyncProvider } from '../../imex/sync/legacy-sync-provider.model'; +import { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { TranslateService } from '@ngx-translate/core'; describe('ConfigPageComponent', () => { @@ -93,7 +93,7 @@ describe('ConfigPageComponent', () => { const fullSyncModel = { isEnabled: true, - syncProvider: LegacySyncProvider.WebDAV, + syncProvider: SyncProviderId.WebDAV, syncInterval: 600000, webDav: webDavCfg, }; diff --git a/src/app/pages/config-page/config-page.component.ts b/src/app/pages/config-page/config-page.component.ts index 90e28a517e..1b0443603b 100644 --- a/src/app/pages/config-page/config-page.component.ts +++ b/src/app/pages/config-page/config-page.component.ts @@ -56,8 +56,7 @@ import { UserProfileService } from '../../features/user-profile/user-profile.ser import { MatDialog } from '@angular/material/dialog'; import { DialogDisableProfilesConfirmationComponent } from '../../features/user-profile/dialog-disable-profiles-confirmation/dialog-disable-profiles-confirmation.component'; import { DialogRestorePointComponent } from '../../imex/sync/dialog-restore-point/dialog-restore-point.component'; -import { LegacySyncProvider } from '../../imex/sync/legacy-sync-provider.model'; -import { toSyncProviderId } from '../../op-log/sync-exports'; +import { SyncProviderId } from '../../op-log/sync-providers/provider.const'; import { DialogConfirmComponent } from '../../ui/dialog-confirm/dialog-confirm.component'; import { LS } from '../../core/persistence/storage-keys.const'; import { MatTab, MatTabGroup, MatTabLabel } from '@angular/material/tabs'; @@ -378,7 +377,7 @@ export class ConfigPageComponent implements OnInit, OnDestroy { if ((item as any).props?.dropboxAuth && item.fieldGroup) { // Check if Dropbox is already authenticated const dropboxProvider = this._providerManager.getProviderById( - toSyncProviderId(LegacySyncProvider.Dropbox)!, + SyncProviderId.Dropbox, ); // We need to check auth status asynchronously, so we'll set initial state @@ -419,7 +418,7 @@ export class ConfigPageComponent implements OnInit, OnDestroy { const result = await this._syncWrapperService.configuredAuthForSyncProviderIfNecessary( - toSyncProviderId(LegacySyncProvider.Dropbox)!, + SyncProviderId.Dropbox, true, // force re-authentication even if already configured ); @@ -525,7 +524,7 @@ export class ConfigPageComponent implements OnInit, OnDestroy { }, { hideExpression: (m: Record) => - !m.isEnabled || m.syncProvider !== LegacySyncProvider.SuperSync, + !m.isEnabled || m.syncProvider !== SyncProviderId.SuperSync, type: 'btn', className: 'mt2 block', templateOptions: {