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.
This commit is contained in:
Johannes Millan 2026-02-14 13:42:23 +01:00
parent 1e516113f6
commit 08e8329f97
18 changed files with 142 additions and 163 deletions

View file

@ -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();

View file

@ -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<SyncConfig> = {};
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,

View file

@ -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;
}),

View file

@ -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<SyncConfig> = {
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<SyncConfig> = {
},
{
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<SyncConfig> = {
},
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<SyncConfig> = {
},
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<SyncConfig> = {
// 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<SyncConfig> = {
// 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<SyncConfig> = {
// 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<SyncConfig> = {
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<SyncConfig> = {
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<SyncConfig> = {
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<SyncConfig> = {
{
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<SyncConfig> = {
// 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<SyncConfig> = {
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<SyncConfig> = {
},
{
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<SyncConfig> = {
},
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)

View file

@ -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;

View file

@ -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
},
};

View file

@ -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<SyncConfig> = {};
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,

View file

@ -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);

View file

@ -1,7 +0,0 @@
// NOTE: do not change!!
export enum LegacySyncProvider {
'Dropbox' = 'Dropbox',
'WebDAV' = 'WebDAV',
'LocalFile' = 'LocalFile',
'SuperSync' = 'SuperSync',
}

View file

@ -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

View file

@ -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<SyncConfig>({
...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

View file

@ -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<any>;
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<typeof signal<boolean>>;
let signalConfigSubject: BehaviorSubject<any>;
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);

View file

@ -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<number> = 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;
}),
);

View file

@ -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 =

View file

@ -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<string, unknown>;
const sync = globalConfig['sync'] as Record<string, unknown>;
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<string, unknown>;
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<string, unknown>;
const savedSync = savedGlobalConfig['sync'] as Record<string, unknown>;
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<string, unknown>;
const dispatchedSync = dispatchedGlobalConfig['sync'] as Record<string, unknown>;
expect(dispatchedSync['isEnabled']).toBe(true);
expect(dispatchedSync['syncProvider']).toBe(LegacySyncProvider.SuperSync);
expect(dispatchedSync['syncProvider']).toBe(SyncProviderId.SuperSync);
});
});
});

View file

@ -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,

View file

@ -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,
};

View file

@ -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<string, unknown>) =>
!m.isEnabled || m.syncProvider !== LegacySyncProvider.SuperSync,
!m.isEnabled || m.syncProvider !== SyncProviderId.SuperSync,
type: 'btn',
className: 'mt2 block',
templateOptions: {