diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index b373ae6c438..9a55bbde2f9 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -49,7 +49,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; -import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAuthTokenServiceChannel, UserDataAutoSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; @@ -65,6 +65,7 @@ import { NativeStorageService } from 'vs/platform/storage/node/storageService'; import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; +import { UserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService'; export interface ISharedProcessConfiguration { readonly machineId: string; @@ -192,6 +193,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', client => client.ctx !== 'main'))); services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService)); services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService)); + services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService)); services.set(ISettingsSyncService, new SyncDescriptor(SettingsSynchroniser)); services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService)); registerConfiguration(); diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index a5c1b02971b..cdd275e4105 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, IFileContent, FileChangesEvent, FileSystemProviderError, FileSystemProviderErrorCode, FileOperationResult, FileOperationError } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { URI } from 'vs/base/common/uri'; -import { SyncSource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; +import { SyncSource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { joinPath, dirname } from 'vs/base/common/resources'; import { toLocalISOString } from 'vs/base/common/date'; @@ -41,6 +41,7 @@ export abstract class AbstractSynchroniser extends Disposable { @IFileService protected readonly fileService: IFileService, @IEnvironmentService environmentService: IEnvironmentService, @IUserDataSyncStoreService protected readonly userDataSyncStoreService: IUserDataSyncStoreService, + @IUserDataSyncEnablementService protected readonly userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IUserDataSyncLogService protected readonly logService: IUserDataSyncLogService, ) { @@ -66,6 +67,8 @@ export abstract class AbstractSynchroniser extends Disposable { } } + protected get enabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resourceKey); } + async sync(ref?: string): Promise { if (!this.enabled) { this.logService.info(`${this.source}: Skipping synchronizing ${this.source.toLowerCase()} as it is disabled.`); @@ -138,7 +141,6 @@ export abstract class AbstractSynchroniser extends Disposable { } abstract readonly resourceKey: ResourceKey; - protected abstract readonly enabled: boolean; protected abstract doSync(remoteUserData: IUserData, lastSyncUserData: IUserData | null): Promise; } @@ -162,10 +164,11 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser { @IFileService fileService: IFileService, @IEnvironmentService environmentService: IEnvironmentService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService telemetryService: ITelemetryService, @IUserDataSyncLogService logService: IUserDataSyncLogService, ) { - super(source, fileService, environmentService, userDataSyncStoreService, telemetryService, logService); + super(source, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService); this._register(this.fileService.watch(dirname(file))); this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); } @@ -257,11 +260,12 @@ export abstract class AbstractJsonFileSynchroniser extends AbstractFileSynchroni @IFileService fileService: IFileService, @IEnvironmentService environmentService: IEnvironmentService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService telemetryService: ITelemetryService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IUserDataSyncUtilService protected readonly userDataSyncUtilService: IUserDataSyncUtilService, ) { - super(file, source, fileService, environmentService, userDataSyncStoreService, telemetryService, logService); + super(file, source, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService); } protected hasErrors(content: string): boolean { diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index d61bb0be1bd..7b5b88cfbe5 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncSource, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncSource, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { Event } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -34,7 +34,6 @@ interface ILastSyncUserData extends IUserData { export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser { readonly resourceKey: ResourceKey = 'extensions'; - protected get enabled(): boolean { return this.configurationService.getValue('sync.enableExtensions') === true && this.extensionGalleryService.isEnabled(); } constructor( @IEnvironmentService environmentService: IEnvironmentService, @@ -45,9 +44,10 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse @IUserDataSyncLogService logService: IUserDataSyncLogService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService telemetryService: ITelemetryService, ) { - super(SyncSource.Extensions, fileService, environmentService, userDataSyncStoreService, telemetryService, logService); + super(SyncSource.Extensions, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService); this._register( Event.debounce( Event.any( diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 94e9019414f..d24f443fd62 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncSource, IUserDataSynchroniser, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncSource, IUserDataSynchroniser, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { Event } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -12,7 +12,6 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IStringDictionary } from 'vs/base/common/collections'; import { edit } from 'vs/platform/userDataSync/common/content'; import { merge } from 'vs/platform/userDataSync/common/globalStateMerge'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parse } from 'vs/base/common/json'; import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -29,17 +28,16 @@ interface ISyncPreviewResult { export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser { readonly resourceKey: ResourceKey = 'globalState'; - protected get enabled(): boolean { return this.configurationService.getValue('sync.enableUIState') === true; } constructor( @IFileService fileService: IFileService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService telemetryService: ITelemetryService, ) { - super(SyncSource.GlobalState, fileService, environmentService, userDataSyncStoreService, telemetryService, logService); + super(SyncSource.GlobalState, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService); this._register(this.fileService.watch(dirname(this.environmentService.argvResource))); this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.argvResource))(() => this._onDidChangeLocal.fire())); } diff --git a/src/vs/platform/userDataSync/common/keybindingsSync.ts b/src/vs/platform/userDataSync/common/keybindingsSync.ts index d5a009eceeb..552b5880494 100644 --- a/src/vs/platform/userDataSync/common/keybindingsSync.ts +++ b/src/vs/platform/userDataSync/common/keybindingsSync.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; -import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncSource, IUserDataSynchroniser, IUserData, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncSource, IUserDataSynchroniser, IUserData, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse } from 'vs/base/common/json'; @@ -31,18 +31,18 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem readonly resourceKey: ResourceKey = 'keybindings'; protected get conflictsPreviewResource(): URI { return this.environmentService.keybindingsSyncPreviewResource; } - protected get enabled(): boolean { return this.configurationService.getValue('sync.enableKeybindings') === true; } constructor( @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @IFileService fileService: IFileService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService, @ITelemetryService telemetryService: ITelemetryService, ) { - super(environmentService.keybindingsResource, SyncSource.Keybindings, fileService, environmentService, userDataSyncStoreService, telemetryService, logService, userDataSyncUtilService); + super(environmentService.keybindingsResource, SyncSource.Keybindings, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService); } async pull(): Promise { diff --git a/src/vs/platform/userDataSync/common/settingsMerge.ts b/src/vs/platform/userDataSync/common/settingsMerge.ts index dfc1f7af2b8..9b9b146fd39 100644 --- a/src/vs/platform/userDataSync/common/settingsMerge.ts +++ b/src/vs/platform/userDataSync/common/settingsMerge.ts @@ -10,7 +10,7 @@ import { values } from 'vs/base/common/map'; import { IStringDictionary } from 'vs/base/common/collections'; import { FormattingOptions, Edit, getEOL } from 'vs/base/common/jsonFormatter'; import * as contentUtil from 'vs/platform/userDataSync/common/content'; -import { IConflictSetting, DEFAULT_IGNORED_SETTINGS } from 'vs/platform/userDataSync/common/userDataSync'; +import { IConflictSetting, CONFIGURATION_SYNC_STORE_KEY } from 'vs/platform/userDataSync/common/userDataSync'; import { firstIndex } from 'vs/base/common/arrays'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { startsWith } from 'vs/base/common/strings'; @@ -42,7 +42,7 @@ export function getIgnoredSettings(configurationService: IConfigurationService, } } } - return [...DEFAULT_IGNORED_SETTINGS, ...added].filter(setting => removed.indexOf(setting) === -1); + return [CONFIGURATION_SYNC_STORE_KEY, ...added].filter(setting => removed.indexOf(setting) === -1); } diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index edcac4e83e0..5795fe23451 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; -import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, IConflictSetting, ISettingsSyncService, CONFIGURATION_SYNC_STORE_KEY, SyncSource, IUserData, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, IConflictSetting, ISettingsSyncService, CONFIGURATION_SYNC_STORE_KEY, SyncSource, IUserData, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse } from 'vs/base/common/json'; import { localize } from 'vs/nls'; @@ -28,7 +28,6 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement readonly resourceKey: ResourceKey = 'settings'; protected get conflictsPreviewResource(): URI { return this.environmentService.settingsSyncPreviewResource; } - protected get enabled(): boolean { return this.configurationService.getValue('sync.enableSettings') === true; } private _conflicts: IConflictSetting[] = []; get conflicts(): IConflictSetting[] { return this._conflicts; } @@ -42,9 +41,10 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement @IUserDataSyncLogService logService: IUserDataSyncLogService, @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService, @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService telemetryService: ITelemetryService, ) { - super(environmentService.settingsResource, SyncSource.Settings, fileService, environmentService, userDataSyncStoreService, telemetryService, logService, userDataSyncUtilService); + super(environmentService.settingsResource, SyncSource.Settings, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService); } protected setStatus(status: SyncStatus): void { diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 77b79981b63..4ee4d9f8026 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -6,8 +6,7 @@ import { timeout, Delayer } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAuthTokenService, IUserDataAutoSyncService, IUserDataSyncUtilService, UserDataSyncError, UserDataSyncErrorCode, SyncSource } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAuthTokenService, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, SyncSource, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; export class UserDataAutoSyncService extends Disposable implements IUserDataAutoSyncService { @@ -21,18 +20,18 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto readonly onError: Event<{ code: UserDataSyncErrorCode, source?: SyncSource }> = this._onError.event; constructor( - @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService, @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IUserDataAuthTokenService private readonly userDataAuthTokenService: IUserDataAuthTokenService, - @IUserDataSyncUtilService private readonly userDataSyncUtilService: IUserDataSyncUtilService, ) { super(); this.updateEnablement(false, true); this.syncDelayer = this._register(new Delayer(0)); this._register(Event.any(userDataAuthTokenService.onDidChangeToken)(() => this.updateEnablement(true, true))); this._register(Event.any(userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true, true))); - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('sync.enable'))(() => this.updateEnablement(true, false))); + this._register(this.userDataSyncEnablementService.onDidChangeEnablement(() => this.updateEnablement(true, false))); + this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync())); } private async updateEnablement(stopIfDisabled: boolean, auto: boolean): Promise { @@ -72,7 +71,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto await this.userDataSyncService.resetLocal(); this.logService.info('Auto Sync: Completed resetting the local sync state.'); if (auto) { - return this.userDataSyncUtilService.updateConfigurationValue('sync.enable', false); + return this.userDataSyncEnablementService.setEnablement(false); } else { return this.sync(loop, auto); } @@ -91,7 +90,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto } private async isAutoSyncEnabled(): Promise { - return this.configurationService.getValue('sync.enable') + return this.userDataSyncEnablementService.isEnabled() && this.userDataSyncService.status !== SyncStatus.Uninitialized && !!(await this.userDataAuthTokenService.getToken()); } diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 9b816299847..0e87a9357a4 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -23,13 +23,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' export const CONFIGURATION_SYNC_STORE_KEY = 'configurationSync.store'; -export const DEFAULT_IGNORED_SETTINGS = [ - CONFIGURATION_SYNC_STORE_KEY, - 'sync.enable', - 'sync.enableSettings', - 'sync.enableExtensions', -]; - export interface ISyncConfiguration { sync: { enable: boolean, @@ -54,33 +47,33 @@ export function registerConfiguration(): IDisposable { properties: { 'sync.enable': { type: 'boolean', - description: localize('sync.enable', "Enable synchronization."), default: false, - scope: ConfigurationScope.APPLICATION + scope: ConfigurationScope.APPLICATION, + deprecationMessage: 'deprecated' }, 'sync.enableSettings': { type: 'boolean', - description: localize('sync.enableSettings', "Enable synchronizing settings."), default: true, scope: ConfigurationScope.APPLICATION, + deprecationMessage: 'deprecated' }, 'sync.enableKeybindings': { type: 'boolean', - description: localize('sync.enableKeybindings', "Enable synchronizing keybindings."), default: true, scope: ConfigurationScope.APPLICATION, + deprecationMessage: 'Deprecated' }, 'sync.enableUIState': { type: 'boolean', - description: localize('sync.enableUIState', "Enable synchronizing UI state (Only Display Language)."), default: true, scope: ConfigurationScope.APPLICATION, + deprecationMessage: 'deprecated' }, 'sync.enableExtensions': { type: 'boolean', - description: localize('sync.enableExtensions', "Enable synchronizing extensions."), default: true, scope: ConfigurationScope.APPLICATION, + deprecationMessage: 'deprecated' }, 'sync.keybindingsPerPlatform': { type: 'boolean', @@ -97,7 +90,7 @@ export function registerConfiguration(): IDisposable { }, 'sync.ignoredSettings': { 'type': 'array', - description: localize('sync.ignoredSettings', "Configure settings to be ignored while synchronizing. \nDefault Ignored Settings:\n\n{0}", DEFAULT_IGNORED_SETTINGS.sort().map(setting => `- ${setting}`).join('\n')), + description: localize('sync.ignoredSettings', "Configure settings to be ignored while synchronizing."), 'default': [], 'scope': ConfigurationScope.APPLICATION, $ref: ignoredSettingsSchemaId, @@ -111,7 +104,7 @@ export function registerConfiguration(): IDisposable { const ignoredSettingsSchema: IJSONSchema = { items: { type: 'string', - enum: [...Object.keys(allSettings.properties).filter(setting => DEFAULT_IGNORED_SETTINGS.indexOf(setting) === -1), ...DEFAULT_IGNORED_SETTINGS.map(setting => `-${setting}`)] + enum: Object.keys(allSettings.properties) } }; jsonRegistry.registerSchema(ignoredSettingsSchemaId, ignoredSettingsSchema); @@ -136,6 +129,7 @@ export function getUserDataSyncStore(configurationService: IConfigurationService return value && value.url && value.authenticationProviderId ? value : undefined; } +export const ALL_RESOURCE_KEYS: ResourceKey[] = ['settings', 'keybindings', 'extensions', 'globalState']; export type ResourceKey = 'settings' | 'keybindings' | 'extensions' | 'globalState'; export interface IUserDataManifest { @@ -247,6 +241,20 @@ export interface IUserDataSynchroniser { // #region User Data Sync Services +export const IUserDataSyncEnablementService = createDecorator('IUserDataSyncEnablementService'); +export interface IUserDataSyncEnablementService { + _serviceBrand: any; + + readonly onDidChangeEnablement: Event; + readonly onDidChangeResourceEnablement: Event<[ResourceKey, boolean]>; + + isEnabled(): boolean; + setEnablement(enabled: boolean): void; + + isResourceEnabled(key: ResourceKey): boolean; + setResourceEnablement(key: ResourceKey, enabled: boolean): void; +} + export const IUserDataSyncService = createDecorator('IUserDataSyncService'); export interface IUserDataSyncService { _serviceBrand: any; @@ -280,7 +288,6 @@ export interface IUserDataAutoSyncService { export const IUserDataSyncUtilService = createDecorator('IUserDataSyncUtilService'); export interface IUserDataSyncUtilService { _serviceBrand: undefined; - updateConfigurationValue(key: string, value: any): Promise; resolveUserBindings(userbindings: string[]): Promise>; resolveFormattingOptions(resource: URI): Promise; } diff --git a/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts b/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts new file mode 100644 index 00000000000..ea7cbca4cd6 --- /dev/null +++ b/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IUserDataSyncEnablementService, ResourceKey, ALL_RESOURCE_KEYS } from 'vs/platform/userDataSync/common/userDataSync'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IStorageService, IWorkspaceStorageChangeEvent, StorageScope } from 'vs/platform/storage/common/storage'; + +const enablementKey = 'sync.enable'; +function getEnablementKey(resourceKey: ResourceKey) { return `${enablementKey}.${resourceKey}`; } + +export class UserDataSyncEnablementService extends Disposable implements IUserDataSyncEnablementService { + + _serviceBrand: any; + + private _onDidChangeEnablement = new Emitter(); + readonly onDidChangeEnablement: Event = this._onDidChangeEnablement.event; + + private _onDidChangeResourceEnablement = new Emitter<[ResourceKey, boolean]>(); + readonly onDidChangeResourceEnablement: Event<[ResourceKey, boolean]> = this._onDidChangeResourceEnablement.event; + + constructor( + @IStorageService private readonly storageService: IStorageService + ) { + super(); + this._register(storageService.onDidChangeStorage(e => this.onDidStorageChange(e))); + } + + isEnabled(): boolean { + return this.storageService.getBoolean(enablementKey, StorageScope.GLOBAL, false); + } + + setEnablement(enabled: boolean): void { + if (this.isEnabled() !== enabled) { + this.storageService.store(enablementKey, enabled, StorageScope.GLOBAL); + } + } + + isResourceEnabled(resourceKey: ResourceKey): boolean { + return this.storageService.getBoolean(getEnablementKey(resourceKey), StorageScope.GLOBAL, true); + } + + setResourceEnablement(resourceKey: ResourceKey, enabled: boolean): void { + if (this.isResourceEnabled(resourceKey) !== enabled) { + this.storageService.store(getEnablementKey(resourceKey), enabled, StorageScope.GLOBAL); + } + } + + private onDidStorageChange(workspaceStorageChangeEvent: IWorkspaceStorageChangeEvent): void { + if (workspaceStorageChangeEvent.scope === StorageScope.GLOBAL) { + if (enablementKey === workspaceStorageChangeEvent.key) { + this._onDidChangeEnablement.fire(this.isEnabled()); + return; + } + const resourceKey = ALL_RESOURCE_KEYS.filter(resourceKey => getEnablementKey(resourceKey) === workspaceStorageChangeEvent.key)[0]; + if (resourceKey) { + this._onDidChangeResourceEnablement.fire([resourceKey, this.isEnabled()]); + return; + } + } + } + +} diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 4fd3bea80a9..ec38e651598 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -121,7 +121,6 @@ export class UserDataSycnUtilServiceChannel implements IServerChannel { switch (command) { case 'resolveUserKeybindings': return this.service.resolveUserBindings(args[0]); case 'resolveFormattingOptions': return this.service.resolveFormattingOptions(URI.revive(args[0])); - case 'updateConfigurationValue': return this.service.updateConfigurationValue(args[0], args[1]); } throw new Error('Invalid call'); } @@ -142,9 +141,5 @@ export class UserDataSyncUtilServiceClient implements IUserDataSyncUtilService { return this.channel.call('resolveFormattingOptions', [file]); } - async updateConfigurationValue(key: string, value: any): Promise { - return this.channel.call('updateConfigurationValue', [key, value]); - } - } diff --git a/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts index 2b5fdcaba9e..097c1b23eee 100644 --- a/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts @@ -3,23 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, IUserDataSyncLogService, IUserDataAuthTokenService, IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, IUserDataSyncLogService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { Event } from 'vs/base/common/event'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { constructor( + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @IUserDataSyncService userDataSyncService: IUserDataSyncService, @IElectronService electronService: IElectronService, - @IConfigurationService configurationService: IConfigurationService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IUserDataAuthTokenService authTokenService: IUserDataAuthTokenService, - @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService, ) { - super(configurationService, userDataSyncService, logService, authTokenService, userDataSyncUtilService); + super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService); // Sync immediately if there is a local change. this._register(Event.debounce(Event.any( diff --git a/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts b/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts index 8a971055e6d..3780af3ab57 100644 --- a/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts +++ b/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts @@ -638,7 +638,5 @@ class MockUserDataSyncUtilService implements IUserDataSyncUtilService { return { eol: '\n', insertSpaces: false, tabSize: 4 }; } - async updateConfigurationValue(key: string, value: any): Promise { } - async ignoreExtensionsToSync(extensions: IExtensionIdentifier[]): Promise { } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index c66d36362c0..ca5fb320cbb 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -49,6 +49,7 @@ import { ExcludeSettingWidget, IListChangeEvent, IListDataItem, ListSettingWidge import { SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ISetting, ISettingsGroup, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; +import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; const $ = DOM.$; @@ -1191,7 +1192,7 @@ export class SettingTreeRenderers { @IInstantiationService private readonly _instantiationService: IInstantiationService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @IContextViewService private readonly _contextViewService: IContextViewService, - @IConfigurationService private readonly _configService: IConfigurationService, + @IUserDataSyncEnablementService private readonly _userDataSyncEnablementService: IUserDataSyncEnablementService, ) { this.settingActions = [ new Action('settings.resetSetting', localize('resetSettingLabel', "Reset Setting"), undefined, undefined, (context: SettingsTreeSettingElement) => { @@ -1235,7 +1236,7 @@ export class SettingTreeRenderers { } private getActionsForSetting(setting: ISetting): IAction[] { - const enableSync = this._configService.getValue('sync.enable'); + const enableSync = this._userDataSyncEnablementService.isEnabled(); return enableSync ? [this._instantiationService.createInstance(StopSyncingSettingAction, setting)] : []; diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts index 5e5b10448cd..5148c307b3c 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, IUserDataSyncLogService, IUserDataAuthTokenService, IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, IUserDataSyncLogService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Event } from 'vs/base/common/event'; import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService'; @@ -14,15 +14,15 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { constructor( + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @IUserDataSyncService userDataSyncService: IUserDataSyncService, @IConfigurationService configurationService: IConfigurationService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IUserDataAuthTokenService authTokenService: IUserDataAuthTokenService, @IInstantiationService instantiationService: IInstantiationService, @IHostService hostService: IHostService, - @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService, ) { - super(configurationService, userDataSyncService, logService, authTokenService, userDataSyncUtilService); + super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService); // Sync immediately if there is a local change. this._register(Event.debounce(Event.any( diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index 367dd0b6fb3..f728e0e9a68 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -3,10 +3,46 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { UserDataSyncWorkbenchContribution } from 'vs/workbench/contrib/userDataSync/browser/userDataSync'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; + +class UserDataSyncSettingsMigrationContribution implements IWorkbenchContribution { + + constructor( + @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, + ) { + if (!configurationService.getValue('sync.enableSettings')) { + userDataSyncEnablementService.setResourceEnablement('settings', false); + } + if (!configurationService.getValue('sync.enableKeybindings')) { + userDataSyncEnablementService.setResourceEnablement('keybindings', false); + } + if (!configurationService.getValue('sync.enableUIState')) { + userDataSyncEnablementService.setResourceEnablement('globalState', false); + } + if (!configurationService.getValue('sync.enableExtensions')) { + userDataSyncEnablementService.setResourceEnablement('extensions', false); + } + if (configurationService.getValue('sync.enable')) { + userDataSyncEnablementService.setEnablement(true); + } + this.removeFromConfiguration(); + } + + private async removeFromConfiguration(): Promise { + await this.configurationService.updateValue('sync.enable', undefined, ConfigurationTarget.USER); + await this.configurationService.updateValue('sync.enableSettings', undefined, ConfigurationTarget.USER); + await this.configurationService.updateValue('sync.enableKeybindings', undefined, ConfigurationTarget.USER); + await this.configurationService.updateValue('sync.enableUIState', undefined, ConfigurationTarget.USER); + await this.configurationService.updateValue('sync.enableExtensions', undefined, ConfigurationTarget.USER); + } +} const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(UserDataSyncWorkbenchContribution, LifecyclePhase.Ready); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncSettingsMigrationContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 06e6bb5f764..bb73095e39e 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IUserDataSyncService, SyncStatus, SyncSource, CONTEXT_SYNC_STATE, IUserDataSyncStore, registerConfiguration, getUserDataSyncStore, ISyncConfiguration, IUserDataAuthTokenService, IUserDataAutoSyncService, USER_DATA_SYNC_SCHEME, toRemoteContentResource, getSyncSourceFromRemoteContentResource, UserDataSyncErrorCode, UserDataSyncError, getSyncSourceFromPreviewResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, SyncSource, CONTEXT_SYNC_STATE, IUserDataSyncStore, registerConfiguration, getUserDataSyncStore, ISyncConfiguration, IUserDataAuthTokenService, IUserDataAutoSyncService, USER_DATA_SYNC_SCHEME, toRemoteContentResource, getSyncSourceFromRemoteContentResource, UserDataSyncErrorCode, UserDataSyncError, getSyncSourceFromPreviewResource, IUserDataSyncEnablementService, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; import { localize } from 'vs/nls'; import { Disposable, MutableDisposable, toDisposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions'; import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey, ContextKeyRegexExpr } from 'vs/platform/contextkey/common/contextkey'; import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; @@ -51,10 +51,11 @@ const enum AuthStatus { SignedOut = 'SignedOut', Unavailable = 'Unavailable' } +const CONTEXT_SYNC_ENABLEMENT = new RawContextKey('syncEnabled', false); const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthStatus.Initializing); const CONTEXT_CONFLICTS_SOURCES = new RawContextKey('conflictsSources', ''); -type ConfigureSyncQuickPickItem = { id: string, label: string, description?: string }; +type ConfigureSyncQuickPickItem = { id: ResourceKey, label: string, description?: string }; function getSyncAreaLabel(source: SyncSource): string { switch (source) { @@ -71,9 +72,8 @@ type FirstTimeSyncClassification = { export class UserDataSyncWorkbenchContribution extends Disposable implements IWorkbenchContribution { - private static readonly ENABLEMENT_SETTING = 'sync.enable'; - private readonly userDataSyncStore: IUserDataSyncStore | undefined; + private readonly syncEnablementContext: IContextKey; private readonly syncStatusContext: IContextKey; private readonly authenticationState: IContextKey; private readonly conflictsSources: IContextKey; @@ -83,12 +83,13 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private _activeAccount: AuthenticationSession | undefined; constructor( + @IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService, @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IAuthenticationService private readonly authenticationService: IAuthenticationService, @IContextKeyService contextKeyService: IContextKeyService, @IActivityService private readonly activityService: IActivityService, @INotificationService private readonly notificationService: INotificationService, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IConfigurationService configurationService: IConfigurationService, @IEditorService private readonly editorService: IEditorService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IDialogService private readonly dialogService: IDialogService, @@ -103,6 +104,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo ) { super(); this.userDataSyncStore = getUserDataSyncStore(configurationService); + this.syncEnablementContext = CONTEXT_SYNC_ENABLEMENT.bindTo(contextKeyService); this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); this.authenticationState = CONTEXT_AUTH_TOKEN_STATE.bindTo(contextKeyService); this.conflictsSources = CONTEXT_CONFLICTS_SOURCES.bindTo(contextKeyService); @@ -110,9 +112,10 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo registerConfiguration(); this.onDidChangeSyncStatus(this.userDataSyncService.status); this.onDidChangeConflicts(this.userDataSyncService.conflictsSources); + this.onDidChangeEnablement(this.userDataSyncEnablementService.isEnabled()); this._register(Event.debounce(userDataSyncService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeSyncStatus(this.userDataSyncService.status))); this._register(userDataSyncService.onDidChangeConflicts(() => this.onDidChangeConflicts(this.userDataSyncService.conflictsSources))); - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING))(() => this.onDidChangeEnablement())); + this._register(this.userDataSyncEnablementService.onDidChangeEnablement(enabled => this.onDidChangeEnablement(enabled))); this._register(this.authenticationService.onDidRegisterAuthenticationProvider(e => this.onDidRegisterAuthenticationProvider(e))); this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(e => this.onDidUnregisterAuthenticationProvider(e))); this._register(this.authenticationService.onDidChangeSessions(e => this.onDidChangeSessions(e))); @@ -288,9 +291,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } } - private onDidChangeEnablement() { + private onDidChangeEnablement(enabled: boolean) { + this.syncEnablementContext.set(enabled); this.updateBadge(); - const enabled = this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING); if (enabled) { if (this.authenticationState.get() === AuthStatus.SignedOut) { const displayName = this.authenticationService.getDisplayName(this.userDataSyncStore!.authenticationProviderId); @@ -334,7 +337,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo let clazz: string | undefined; let priority: number | undefined = undefined; - if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.configurationService.getValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING) && this.authenticationState.get() === AuthStatus.SignedOut) { + if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.userDataSyncEnablementService.isEnabled() && this.authenticationState.get() === AuthStatus.SignedOut) { badge = new NumberBadge(1, () => localize('sign in to sync', "Sign in to Sync")); } else if (this.userDataSyncService.conflictsSources.length) { badge = new NumberBadge(this.userDataSyncService.conflictsSources.length, () => localize('has conflicts', "Sync: Conflicts Detected")); @@ -369,10 +372,10 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo quickPick.ignoreFocusOut = true; const items = this.getConfigureSyncQuickPickItems(); quickPick.items = items; - quickPick.selectedItems = items.filter(item => this.configurationService.getValue(item.id)); + quickPick.selectedItems = items.filter(item => this.userDataSyncEnablementService.isResourceEnabled(item.id)); disposables.add(Event.any(quickPick.onDidAccept, quickPick.onDidCustom)(async () => { if (quickPick.selectedItems.length) { - await this.updateConfiguration(items, quickPick.selectedItems); + this.updateConfiguration(items, quickPick.selectedItems); this.doTurnOn().then(c, e); quickPick.hide(); } @@ -387,32 +390,32 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo await this.signIn(); } await this.handleFirstTimeSync(); - await this.enableSync(); + this.userDataSyncEnablementService.setEnablement(true); } private getConfigureSyncQuickPickItems(): ConfigureSyncQuickPickItem[] { return [{ - id: 'sync.enableSettings', + id: 'settings', label: getSyncAreaLabel(SyncSource.Settings) }, { - id: 'sync.enableKeybindings', + id: 'keybindings', label: getSyncAreaLabel(SyncSource.Keybindings) }, { - id: 'sync.enableExtensions', + id: 'extensions', label: getSyncAreaLabel(SyncSource.Extensions) }, { - id: 'sync.enableUIState', + id: 'globalState', label: getSyncAreaLabel(SyncSource.GlobalState), description: localize('ui state description', "only 'Display Language' for now") }]; } - private async updateConfiguration(items: ConfigureSyncQuickPickItem[], selectedItems: ReadonlyArray): Promise { + private updateConfiguration(items: ConfigureSyncQuickPickItem[], selectedItems: ReadonlyArray): void { for (const item of items) { - const wasEnabled = this.configurationService.getValue(item.id); + const wasEnabled = this.userDataSyncEnablementService.isResourceEnabled(item.id); const isEnabled = !!selectedItems.filter(selected => selected.id === item.id)[0]; if (wasEnabled !== isEnabled) { - await this.configurationService.updateValue(item.id!, isEnabled); + this.userDataSyncEnablementService.setResourceEnablement(item.id!, isEnabled); } } } @@ -426,9 +429,10 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo quickPick.placeholder = localize('configure sync placeholder', "Choose what to sync"); quickPick.canSelectMany = true; quickPick.ignoreFocusOut = true; + quickPick.ok = true; const items = this.getConfigureSyncQuickPickItems(); quickPick.items = items; - quickPick.selectedItems = items.filter(item => this.configurationService.getValue(item.id)); + quickPick.selectedItems = items.filter(item => this.userDataSyncEnablementService.isResourceEnabled(item.id)); disposables.add(quickPick.onDidAccept(async () => { if (quickPick.selectedItems.length) { await this.updateConfiguration(items, quickPick.selectedItems); @@ -475,10 +479,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } } - private enableSync(): Promise { - return this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, true); - } - private async turnOff(): Promise { const result = await this.dialogService.confirm({ type: 'info', @@ -500,15 +500,17 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } } - private disableSync(source?: SyncSource): Promise { - let key: string = UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING; - switch (source) { - case SyncSource.Settings: key = 'sync.enableSettings'; break; - case SyncSource.Keybindings: key = 'sync.enableKeybindings'; break; - case SyncSource.Extensions: key = 'sync.enableExtensions'; break; - case SyncSource.GlobalState: key = 'sync.enableUIState'; break; + private disableSync(source?: SyncSource): void { + if (source === undefined) { + this.userDataSyncEnablementService.setEnablement(false); + } else { + switch (source) { + case SyncSource.Settings: return this.userDataSyncEnablementService.setResourceEnablement('settings', false); + case SyncSource.Keybindings: return this.userDataSyncEnablementService.setResourceEnablement('keybindings', false); + case SyncSource.Extensions: return this.userDataSyncEnablementService.setResourceEnablement('extensions', false); + case SyncSource.GlobalState: return this.userDataSyncEnablementService.setResourceEnablement('globalState', false); + } } - return this.configurationService.updateValue(key, false, ConfigurationTarget.USER); } private async signIn(): Promise { @@ -573,7 +575,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private registerActions(): void { const turnOnSyncCommandId = 'workbench.userData.actions.syncStart'; - const turnOnSyncWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.notEqualsTo(AuthStatus.Initializing)); + const turnOnSyncWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT.toNegated(), CONTEXT_AUTH_TOKEN_STATE.notEqualsTo(AuthStatus.Initializing)); CommandsRegistry.registerCommand(turnOnSyncCommandId, async () => { try { await this.turnOn(); @@ -600,7 +602,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo }); const signInCommandId = 'workbench.userData.actions.signin'; - const signInWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthStatus.SignedOut)); + const signInWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT, CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthStatus.SignedOut)); CommandsRegistry.registerCommand(signInCommandId, () => this.signIn()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', @@ -626,14 +628,14 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo id: stopSyncCommandId, title: localize('global activity stop sync', "Turn off Sync") }, - when: ContextKeyExpr.and(ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`), CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthStatus.SignedIn), CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.HasConflicts)) + when: ContextKeyExpr.and(CONTEXT_SYNC_ENABLEMENT, CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthStatus.SignedIn), CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.HasConflicts)) }); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: stopSyncCommandId, title: localize('stop sync', "Sync: Turn off Sync") }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT), }); const resolveSettingsConflictsCommandId = 'workbench.userData.actions.resolveSettingsConflicts'; @@ -692,7 +694,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo id: configureSyncCommandId, title: localize('configure sync', "Sync: Configure") }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has(`config.${UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING}`)), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT), }); const showSyncLogCommandId = 'workbench.userData.actions.showSyncLog'; diff --git a/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts b/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts index e4b220be0ab..c168d05c76a 100644 --- a/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts +++ b/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts @@ -11,7 +11,6 @@ import { FormattingOptions } from 'vs/base/common/jsonFormatter'; import { URI } from 'vs/base/common/uri'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourcePropertiesService, ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService'; -import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; class UserDataSyncUtilService implements IUserDataSyncUtilService { @@ -22,13 +21,8 @@ class UserDataSyncUtilService implements IUserDataSyncUtilService { @ITextModelService private readonly textModelService: ITextModelService, @ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService, @ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService, - @IConfigurationService private readonly configurationService: IConfigurationService, ) { } - public async updateConfigurationValue(key: string, value: any): Promise { - await this.configurationService.updateValue(key, value, ConfigurationTarget.USER); - } - public async resolveUserBindings(userBindings: string[]): Promise> { const keys: IStringDictionary = {}; for (const userbinding of userBindings) { diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 7a4159c2e8f..340f89e717d 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -111,7 +111,10 @@ import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadService } from 'vs/platform/download/common/downloadService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService'; +registerSingleton(IUserDataSyncEnablementService, UserDataSyncEnablementService); registerSingleton(IGlobalExtensionEnablementService, GlobalExtensionEnablementService); registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); registerSingleton(IContextViewService, ContextViewService, true);