diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 9574d24e4195c1bd6e18a598ccba3d92ff6d1f23..82df24ea01ff189bf4d3d8bf81889c42df2fb5e1 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -114,10 +114,23 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i ) { super(storageService, environmentService, userDataSyncStoreManagementService); this.syncTriggerDelayer = this._register(new Delayer(0)); + this.lastSyncUrl = this.syncUrl; this.syncUrl = userDataSyncStoreManagementService.userDataSyncStore?.url; - if (userDataSyncStoreManagementService.userDataSyncStore) { + if (this.syncUrl) { + + this.logService.info('Using settings sync service', this.syncUrl.toString()); + this._register(userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => { + if (!isEqual(this.syncUrl, userDataSyncStoreManagementService.userDataSyncStore?.url)) { + this.lastSyncUrl = this.syncUrl; + this.syncUrl = userDataSyncStoreManagementService.userDataSyncStore?.url; + if (this.syncUrl) { + this.logService.info('Using settings sync service', this.syncUrl.toString()); + } + } + })); + if (this.isEnabled()) { this.logService.info('Auto Sync is enabled.'); } else { diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 642c49800e5bd8692dc46ef8d8d2894f0d8909c9..f98181038df33b89d745fb6a1fd7805c4b8dff10 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -158,6 +158,7 @@ export type UserDataSyncStoreType = 'insiders' | 'stable'; export const IUserDataSyncStoreManagementService = createDecorator('IUserDataSyncStoreManagementService'); export interface IUserDataSyncStoreManagementService { readonly _serviceBrand: undefined; + readonly onDidChangeUserDataSyncStore: Event; readonly userDataSyncStore: IUserDataSyncStore | undefined; switch(type: UserDataSyncStoreType): Promise; getPreviousUserDataSyncStore(): Promise; diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 08a8243bb421870f73b14523ecc748baba09319c..aaa4a8543f1ab406045e272e39ef91db30abae23 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -271,6 +271,9 @@ export class UserDataSyncStoreManagementServiceChannel implements IServerChannel constructor(private readonly service: IUserDataSyncStoreManagementService) { } listen(_: unknown, event: string): Event { + switch (event) { + case 'onDidChangeUserDataSyncStore': return this.service.onDidChangeUserDataSyncStore; + } throw new Error(`Event not found: ${event}`); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 20ffff9cffd7c91b0ca6b5bc270b0a19c01eb644..59e8d8fb0d2195b062da145f81109aa39ce19ec8 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -36,7 +36,10 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa _serviceBrand: any; - readonly userDataSyncStore: UserDataSyncStore | undefined; + private readonly _onDidChangeUserDataSyncStore = this._register(new Emitter()); + readonly onDidChangeUserDataSyncStore = this._onDidChangeUserDataSyncStore.event; + private _userDataSyncStore: UserDataSyncStore | undefined; + get userDataSyncStore(): UserDataSyncStore | undefined { return this._userDataSyncStore; } constructor( @IProductService protected readonly productService: IProductService, @@ -44,7 +47,12 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa @IStorageService protected readonly storageService: IStorageService, ) { super(); - this.userDataSyncStore = this.toUserDataSyncStore(productService[CONFIGURATION_SYNC_STORE_KEY], configurationService.getValue(CONFIGURATION_SYNC_STORE_KEY)); + this.updateUserDataSyncStore(); + } + + protected updateUserDataSyncStore(): void { + this._userDataSyncStore = this.toUserDataSyncStore(this.productService[CONFIGURATION_SYNC_STORE_KEY], this.configurationService.getValue(CONFIGURATION_SYNC_STORE_KEY)); + this._onDidChangeUserDataSyncStore.fire(); } protected toUserDataSyncStore(productStore: ConfigurationSyncStore | undefined, configuredStore?: ConfigurationSyncStore): UserDataSyncStore | undefined { @@ -69,7 +77,7 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa defaultUrl: URI.parse(syncStore.url), stableUrl: URI.parse(syncStore.stableUrl), insidersUrl: URI.parse(syncStore.insidersUrl), - canSwitch: !!syncStore.canSwitch, + canSwitch: !!syncStore.canSwitch && !configuredStore?.url, authenticationProviders: Object.keys(syncStore.authenticationProviders).reduce((result, id) => { result.push({ id, scopes: syncStore!.authenticationProviders[id].scopes }); return result; @@ -92,7 +100,6 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, @IStorageService storageService: IStorageService, - @IUserDataSyncLogService logService: IUserDataSyncLogService, ) { super(productService, configurationService, storageService); @@ -107,10 +114,6 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor } else { this.storageService.remove(SYNC_PREVIOUS_STORE, StorageScope.GLOBAL); } - - if (this.userDataSyncStore) { - logService.info('Using settings sync service', this.userDataSyncStore.url.toString()); - } } async switch(type: UserDataSyncStoreType): Promise { @@ -120,6 +123,7 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor } else { this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL); } + this.updateUserDataSyncStore(); } } @@ -130,7 +134,7 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor export class UserDataSyncStoreClient extends Disposable implements IUserDataSyncStoreClient { - private readonly userDataSyncStoreUrl: URI | undefined; + private userDataSyncStoreUrl: URI | undefined; private authToken: { token: string, type: string } | undefined; private readonly commonHeadersPromise: Promise<{ [key: string]: string; }>; @@ -157,7 +161,7 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync @IStorageService private readonly storageService: IStorageService, ) { super(); - this.userDataSyncStoreUrl = userDataSyncStoreUrl ? joinPath(userDataSyncStoreUrl, 'v1') : undefined; + this.updateUserDataSyncStoreUrl(userDataSyncStoreUrl); this.commonHeadersPromise = getServiceMachineId(environmentService, fileService, storageService) .then(uuid => { const headers: IHeaders = { @@ -180,6 +184,10 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync this.authToken = { token, type }; } + protected updateUserDataSyncStoreUrl(userDataSyncStoreUrl: URI | undefined): void { + this.userDataSyncStoreUrl = userDataSyncStoreUrl ? joinPath(userDataSyncStoreUrl, 'v1') : undefined; + } + private initDonotMakeRequestsUntil(): void { const donotMakeRequestsUntil = this.storageService.getNumber(DONOT_MAKE_REQUESTS_UNTIL_KEY, StorageScope.GLOBAL); if (donotMakeRequestsUntil && Date.now() < donotMakeRequestsUntil) { @@ -465,6 +473,7 @@ export class UserDataSyncStoreService extends UserDataSyncStoreClient implements @IStorageService storageService: IStorageService, ) { super(userDataSyncStoreManagementService.userDataSyncStore?.url, productService, requestService, logService, environmentService, fileService, storageService); + this._register(userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => this.updateUserDataSyncStoreUrl(userDataSyncStoreManagementService.userDataSyncStore?.url))); } } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index ec3c96b7a56e640f1e2317fd5e7f63fdc0f5f8f6..52a0041eafa0863d77b44fea7cd0b64c112d1172 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -30,7 +30,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IUserDataAutoSyncService, IUserDataSyncService, registerConfiguration, SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_SCHEME, IUserDataSyncResourceEnablementService, - getSyncResourceFromLocalPreview, IResourcePreview, IUserDataSyncStoreManagementService, UserDataSyncStoreType + getSyncResourceFromLocalPreview, IResourcePreview, IUserDataSyncStoreManagementService, UserDataSyncStoreType, IUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync'; import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -54,7 +54,6 @@ import { Codicon } from 'vs/base/common/codicons'; import { ViewContainerLocation, IViewContainersRegistry, Extensions, ViewContainer } from 'vs/workbench/common/views'; import { UserDataSyncViewPaneContainer, UserDataSyncDataViews } from 'vs/workbench/contrib/userDataSync/browser/userDataSyncViews'; import { IUserDataSyncWorkbenchService, getSyncAreaLabel, AccountStatus, CONTEXT_SYNC_STATE, CONTEXT_SYNC_ENABLEMENT, CONTEXT_ACCOUNT_STATE, CONFIGURE_SYNC_COMMAND_ID, SHOW_SYNC_LOG_COMMAND_ID, SYNC_VIEW_CONTAINER_ID, SYNC_TITLE } from 'vs/workbench/services/userDataSync/common/userDataSync'; -import { isNative } from 'vs/base/common/platform'; const CONTEXT_CONFLICTS_SOURCES = new RawContextKey('conflictsSources', ''); @@ -443,6 +442,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (!turnOn) { return; } + if (this.userDataSyncStoreManagementService.userDataSyncStore?.canSwitch) { + await this.selectSettingsSyncService(this.userDataSyncStoreManagementService.userDataSyncStore); + } await this.userDataSyncWorkbenchService.turnOn(); this.storageService.store('sync.donotAskPreviewConfirmation', true, StorageScope.GLOBAL); } catch (e) { @@ -674,52 +676,46 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo return this.outputService.showChannel(Constants.userDataSyncLogChannelId); } - private async switchSyncService(): Promise { - const userDataSyncStore = this.userDataSyncStoreManagementService.userDataSyncStore; - if (userDataSyncStore?.canSwitch && ![userDataSyncStore.insidersUrl, userDataSyncStore.stableUrl].includes(userDataSyncStore.url)) { - return new Promise((c, e) => { - const disposables: DisposableStore = new DisposableStore(); - const quickPick = disposables.add(this.quickInputService.createQuickPick<{ id: UserDataSyncStoreType, label: string, description?: string }>()); - quickPick.title = localize('switchSyncService.title', "Select Settings Sync Service..."); - quickPick.placeholder = localize('choose sync service', "Choose settings sync Service to use"); - quickPick.description = isNative ? - localize('choose sync service description', "Switching settings sync service requires restarting {0}", this.productService.nameLong) : - localize('choose sync service description web', "Switching settings sync service requires reloading {0}", this.productService.nameLong); - quickPick.hideInput = true; - const getDescription = (url: URI): string | undefined => { - const isCurrent = isEqual(url, userDataSyncStore.url); - const isDefault = isEqual(url, userDataSyncStore.defaultUrl); - if (isCurrent && isDefault) { - return localize('default and current', "Default & Current"); - } - if (isDefault) { - return localize('default', "Default"); - } - if (isCurrent) { - return localize('current', "Current"); - } - return undefined; - }; - quickPick.items = [ - { - id: 'insiders', - label: localize('insiders', "Insiders"), - description: getDescription(userDataSyncStore.insidersUrl!) - }, - { - id: 'stable', - label: localize('stable', "Stable"), - description: getDescription(userDataSyncStore.stableUrl!) - } - ]; - disposables.add(quickPick.onDidAccept(() => { - this.userDataSyncWorkbenchService.switchSyncService(quickPick.selectedItems[0].id); + private async selectSettingsSyncService(userDataSyncStore: IUserDataSyncStore): Promise { + return new Promise((c, e) => { + const disposables: DisposableStore = new DisposableStore(); + const quickPick = disposables.add(this.quickInputService.createQuickPick<{ id: UserDataSyncStoreType, label: string, description?: string }>()); + quickPick.title = localize('switchSyncService.title', "{0}: Select Service", SYNC_TITLE); + quickPick.description = localize('switchSyncService.description', "Ensure you are using the same settings sync service when syncing with multiple environments"); + quickPick.hideInput = true; + quickPick.ignoreFocusOut = true; + const getDescription = (url: URI): string | undefined => { + const isDefault = isEqual(url, userDataSyncStore.defaultUrl); + if (isDefault) { + return localize('default', "Default"); + } + return undefined; + }; + quickPick.items = [ + { + id: 'insiders', + label: localize('insiders', "Insiders"), + description: getDescription(userDataSyncStore.insidersUrl) + }, + { + id: 'stable', + label: localize('stable', "Stable"), + description: getDescription(userDataSyncStore.stableUrl) + } + ]; + disposables.add(quickPick.onDidAccept(async () => { + try { + await this.userDataSyncStoreManagementService.switch(quickPick.selectedItems[0].id); + c(); + } catch (error) { + e(error); + } finally { quickPick.hide(); - })); - disposables.add(quickPick.onDidHide(() => disposables.dispose())); - quickPick.show(); - }); - } + } + })); + disposables.add(quickPick.onDidHide(() => disposables.dispose())); + quickPick.show(); + }); } private registerActions(): void { @@ -738,7 +734,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this.registerSyncNowAction(); this.registerConfigureSyncAction(); this.registerShowSettingsAction(); - this.registerSwitchSyncServiceAction(); this.registerShowLogAction(); } @@ -1117,28 +1112,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo })); } - private registerSwitchSyncServiceAction(): void { - const that = this; - const userDataSyncStore = this.userDataSyncStoreManagementService.userDataSyncStore; - if (userDataSyncStore?.canSwitch && ![userDataSyncStore.insidersUrl, userDataSyncStore.stableUrl].includes(userDataSyncStore.url)) { - this._register(registerAction2(class ShowSyncSettingsAction extends Action2 { - constructor() { - super({ - id: 'workbench.userDataSync.actions.switchSyncService', - title: { value: localize('workbench.userDataSync.actions.switchSyncService', "{0}: Select Service...", SYNC_TITLE), original: 'Settings Sync: Select Service...' }, - menu: { - id: MenuId.CommandPalette, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized)), - }, - }); - } - run(accessor: ServicesAccessor): any { - return that.switchSyncService(); - } - })); - } - } - private registerViews(): void { const container = this.registerViewContainer(); this.registerDataViews(container); diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index 2a920acf4458663c46fbe34e22daf064468eb4f5..663cc04ddc9514448d165365ba2358673c76cb01 100644 --- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -752,6 +752,8 @@ class SimpleIUserDataSyncStoreManagementService implements IUserDataSyncStoreMan declare readonly _serviceBrand: undefined; + onDidChangeUserDataSyncStore = Event.None; + userDataSyncStore: IUserDataSyncStore | undefined = undefined; async switch(type: UserDataSyncStoreType): Promise { } diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index 1f4df831651c361d1563d79d18fac0065de573ee..e8b4924fe5a224f836bc884abb91131c526c6283 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, IAuthenticationProvider, isAuthenticationProvider, IUserDataAutoSyncService, SyncResource, IResourcePreview, ISyncResourcePreview, Change, IManualSyncTask, IUserDataSyncStoreManagementService, UserDataSyncStoreType, SyncStatus } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, IAuthenticationProvider, isAuthenticationProvider, IUserDataAutoSyncService, SyncResource, IResourcePreview, ISyncResourcePreview, Change, IManualSyncTask, IUserDataSyncStoreManagementService, SyncStatus } from 'vs/platform/userDataSync/common/userDataSync'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUserDataSyncWorkbenchService, IUserDataSyncAccount, AccountStatus, CONTEXT_SYNC_ENABLEMENT, CONTEXT_SYNC_STATE, CONTEXT_ACCOUNT_STATE, SHOW_SYNC_LOG_COMMAND_ID, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, CONTEXT_ENABLE_SYNC_MERGES_VIEW, SYNC_MERGES_VIEW_ID, CONTEXT_ENABLE_ACTIVITY_VIEWS, SYNC_VIEW_CONTAINER_ID, SYNC_TITLE } from 'vs/workbench/services/userDataSync/common/userDataSync'; @@ -29,8 +29,6 @@ import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/ import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IViewsService, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views'; -import { isNative } from 'vs/base/common/platform'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; type UserAccountClassification = { @@ -108,7 +106,6 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat @IViewsService private readonly viewsService: IViewsService, @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService, - @IHostService private readonly hostService: IHostService, @ILifecycleService private readonly lifecycleService: ILifecycleService, ) { super(); @@ -444,29 +441,6 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat await this.viewsService.openViewContainer(SYNC_VIEW_CONTAINER_ID); } - async switchSyncService(type: UserDataSyncStoreType): Promise { - if (!this.userDataSyncStoreManagementService.userDataSyncStore - || !this.userDataSyncStoreManagementService.userDataSyncStore.canSwitch) { - return; - } - await this.userDataSyncStoreManagementService.switch(type); - const res = await this.dialogService.confirm({ - type: 'info', - message: isNative ? - localize('relaunchMessage', "Switching settings sync service requires a restart to take effect.") : - localize('relaunchMessageWeb', "Switching settings sync service requires a reload to take effect."), - detail: isNative ? - localize('relaunchDetail', "Press the restart button to restart {0} and switch.", this.productService.nameLong) : - localize('relaunchDetailWeb', "Press the reload button to reload {0} and switch.", this.productService.nameLong), - primaryButton: isNative ? - localize('restart', "&&Restart") : - localize('restartWeb', "&&Reload"), - }); - if (res.confirmed) { - this.hostService.restart(); - } - } - private async waitForActiveSyncViews(): Promise { const viewContainer = this.viewDescriptorService.getViewContainerById(SYNC_VIEW_CONTAINER_ID); if (viewContainer) { diff --git a/src/vs/workbench/services/userDataSync/common/userDataSync.ts b/src/vs/workbench/services/userDataSync/common/userDataSync.ts index aaaad9acf407c7d9d90ee0c73d4756db34c04fe0..4e0e54f625202ac93ebd738d85690a4974a35453 100644 --- a/src/vs/workbench/services/userDataSync/common/userDataSync.ts +++ b/src/vs/workbench/services/userDataSync/common/userDataSync.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IAuthenticationProvider, SyncStatus, SyncResource, Change, MergeState, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; +import { IAuthenticationProvider, SyncStatus, SyncResource, Change, MergeState } from 'vs/platform/userDataSync/common/userDataSync'; import { Event } from 'vs/base/common/event'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { localize } from 'vs/nls'; @@ -58,7 +58,6 @@ export interface IUserDataSyncWorkbenchService { turnOn(): Promise; turnoff(everyWhere: boolean): Promise; signIn(): Promise; - switchSyncService(type: UserDataSyncStoreType): Promise; resetSyncedData(): Promise; showSyncActivity(): Promise; diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreManagementService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreManagementService.ts index d5df2210df5feb6f14fc14635d0fb1be7299978b..7b2e238f6844eef7b31d1179f071d5d68a07b556 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreManagementService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreManagementService.ts @@ -25,6 +25,7 @@ class UserDataSyncStoreManagementService extends AbstractUserDataSyncStoreManage ) { super(productService, configurationService, storageService); this.channel = sharedProcessService.getChannel('userDataSyncStoreManagement'); + this._register(this.channel.listen('onDidChangeUserDataSyncStore')(() => this.updateUserDataSyncStore())); } async switch(type: UserDataSyncStoreType): Promise {