Merge from vscode 8a997f7321ae6612fc0e6eb3eac4f358a6233bfb

This commit is contained in:
ADS Merger
2020-02-11 07:08:19 +00:00
parent 0f934081e1
commit 085752f111
217 changed files with 2561 additions and 2063 deletions

View File

@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
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 } 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 } from 'vs/base/common/lifecycle';
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 } from 'vs/platform/contextkey/common/contextkey';
import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey, ContextKeyRegexExpr } from 'vs/platform/contextkey/common/contextkey';
import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity';
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
@@ -51,9 +51,11 @@ const enum AuthStatus {
SignedOut = 'SignedOut',
Unavailable = 'Unavailable'
}
const CONTEXT_SYNC_ENABLEMENT = new RawContextKey<boolean>('syncEnabled', false);
const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey<string>('authTokenStatus', AuthStatus.Initializing);
const CONTEXT_CONFLICTS_SOURCES = new RawContextKey<string>('conflictsSources', '');
type ConfigureSyncQuickPickItem = { id: string, label: string, description?: string };
type ConfigureSyncQuickPickItem = { id: ResourceKey, label: string, description?: string };
function getSyncAreaLabel(source: SyncSource): string {
switch (source) {
@@ -70,23 +72,24 @@ 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<boolean>;
private readonly syncStatusContext: IContextKey<string>;
private readonly authenticationState: IContextKey<string>;
private readonly conflictsSources: IContextKey<string>;
private readonly conflictsDisposables = new Map<SyncSource, IDisposable>();
private readonly badgeDisposable = this._register(new MutableDisposable());
private readonly conflictsWarningDisposable = this._register(new MutableDisposable());
private readonly signInNotificationDisposable = this._register(new MutableDisposable());
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,
@@ -101,13 +104,18 @@ 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);
if (this.userDataSyncStore) {
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(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING))(() => this.onDidChangeEnablement()));
this._register(userDataSyncService.onDidChangeConflicts(() => this.onDidChangeConflicts(this.userDataSyncService.conflictsSources)));
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)));
@@ -221,44 +229,71 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
private onDidChangeSyncStatus(status: SyncStatus) {
this.syncStatusContext.set(status);
if (status === SyncStatus.Syncing) {
// Show syncing progress if takes more than 1s.
timeout(1000).then(() => this.updateBadge());
} else {
this.updateBadge();
}
}
if (this.userDataSyncService.status === SyncStatus.HasConflicts) {
const conflictsEditorInput = this.getConflictsEditorInput(this.userDataSyncService.conflictsSource!);
if (!conflictsEditorInput && !this.conflictsWarningDisposable.value) {
const conflictsArea = getSyncAreaLabel(this.userDataSyncService.conflictsSource!);
const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts in {0}. Please resolve them to continue.", conflictsArea),
[
{
label: localize('show conflicts', "Show Conflicts"),
run: () => {
this.telemetryService.publicLog2('sync/showConflicts');
this.handleConflicts();
private onDidChangeConflicts(conflicts: SyncSource[]) {
this.updateBadge();
if (conflicts.length) {
this.conflictsSources.set(this.userDataSyncService.conflictsSources.join(','));
// Clear and dispose conflicts those were cleared
this.conflictsDisposables.forEach((disposable, conflictsSource) => {
if (this.userDataSyncService.conflictsSources.indexOf(conflictsSource) === -1) {
disposable.dispose();
this.conflictsDisposables.delete(conflictsSource);
}
});
for (const conflictsSource of this.userDataSyncService.conflictsSources) {
const conflictsEditorInput = this.getConflictsEditorInput(conflictsSource);
if (!conflictsEditorInput && !this.conflictsDisposables.has(conflictsSource)) {
const conflictsArea = getSyncAreaLabel(conflictsSource);
const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts in {0}. Please resolve them to continue.", conflictsArea),
[
{
label: localize('show conflicts', "Show Conflicts"),
run: () => {
this.telemetryService.publicLog2('sync/showConflicts');
this.handleConflicts(conflictsSource);
}
}
],
{
sticky: true
}
],
{
sticky: true
}
);
this.conflictsWarningDisposable.value = toDisposable(() => handle.close());
handle.onDidClose(() => this.conflictsWarningDisposable.clear());
);
this.conflictsDisposables.set(conflictsSource, toDisposable(() => {
// close the conflicts warning notification
handle.close();
// close opened conflicts editor previews
const conflictsEditorInput = this.getConflictsEditorInput(conflictsSource);
if (conflictsEditorInput) {
conflictsEditorInput.dispose();
}
this.conflictsDisposables.delete(conflictsSource);
}));
}
}
} else {
this.conflictsSources.reset();
this.getAllConflictsEditorInputs().forEach(input => input.dispose());
this.conflictsWarningDisposable.clear();
this.conflictsDisposables.forEach(disposable => disposable.dispose());
this.conflictsDisposables.clear();
}
}
private onDidChangeEnablement() {
private onDidChangeEnablement(enabled: boolean) {
this.syncEnablementContext.set(enabled);
this.updateBadge();
const enabled = this.configurationService.getValue<boolean>(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING);
if (enabled) {
if (this.authenticationState.get() === AuthStatus.SignedOut) {
const displayName = this.authenticationService.getDisplayName(this.userDataSyncStore!.authenticationProviderId);
@@ -302,10 +337,10 @@ 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<boolean>(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.status === SyncStatus.HasConflicts) {
badge = new NumberBadge(1, () => localize('show conflicts', "Show Conflicts"));
} else if (this.userDataSyncService.conflictsSources.length) {
badge = new NumberBadge(this.userDataSyncService.conflictsSources.length, () => localize('has conflicts', "Sync: Conflicts Detected"));
} else if (this.userDataSyncService.status === SyncStatus.Syncing) {
badge = new ProgressBadge(() => localize('syncing', "Synchronizing User Configuration..."));
clazz = 'progress-badge';
@@ -337,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();
}
@@ -355,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<ConfigureSyncQuickPickItem>): Promise<void> {
private updateConfiguration(items: ConfigureSyncQuickPickItem[], selectedItems: ReadonlyArray<ConfigureSyncQuickPickItem>): 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);
}
}
}
@@ -394,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);
@@ -412,12 +448,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}
private async handleFirstTimeSync(): Promise<void> {
const hasRemote = await this.userDataSyncService.hasRemoteData();
if (!hasRemote) {
return;
}
const isFirstSyncAndHasUserData = await this.userDataSyncService.isFirstTimeSyncAndHasUserData();
if (!isFirstSyncAndHasUserData) {
const isFirstSyncWithMerge = await this.userDataSyncService.isFirstTimeSyncWithMerge();
if (!isFirstSyncWithMerge) {
return;
}
const result = await this.dialogService.show(
@@ -447,10 +479,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}
}
private enableSync(): Promise<void> {
return this.configurationService.updateValue(UserDataSyncWorkbenchContribution.ENABLEMENT_SETTING, true);
}
private async turnOff(): Promise<void> {
const result = await this.dialogService.confirm({
type: 'info',
@@ -472,15 +500,17 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}
}
private disableSync(source?: SyncSource): Promise<void> {
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<void> {
@@ -513,18 +543,18 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
});
}
private async handleConflicts(): Promise<void> {
private async handleConflicts(source: SyncSource): Promise<void> {
let previewResource: URI | undefined = undefined;
let label: string = '';
if (this.userDataSyncService.conflictsSource === SyncSource.Settings) {
if (source === SyncSource.Settings) {
previewResource = this.workbenchEnvironmentService.settingsSyncPreviewResource;
label = localize('settings conflicts preview', "Settings Conflicts (Remote ↔ Local)");
} else if (this.userDataSyncService.conflictsSource === SyncSource.Keybindings) {
} else if (source === SyncSource.Keybindings) {
previewResource = this.workbenchEnvironmentService.keybindingsSyncPreviewResource;
label = localize('keybindings conflicts preview', "Keybindings Conflicts (Remote ↔ Local)");
}
if (previewResource) {
const remoteContentResource = toRemoteContentResource(this.userDataSyncService.conflictsSource!);
const remoteContentResource = toRemoteContentResource(source);
await this.editorService.openEditor({
leftResource: remoteContentResource,
rightResource: previewResource,
@@ -545,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();
@@ -572,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',
@@ -598,33 +628,52 @@ 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 resolveConflictsCommandId = 'workbench.userData.actions.resolveConflicts';
const resolveConflictsWhenContext = CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts);
CommandsRegistry.registerCommand(resolveConflictsCommandId, () => this.handleConflicts());
const resolveSettingsConflictsCommandId = 'workbench.userData.actions.resolveSettingsConflicts';
const resolveSettingsConflictsWhenContext = ContextKeyRegexExpr.create(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*settings.*/i);
CommandsRegistry.registerCommand(resolveSettingsConflictsCommandId, () => this.handleConflicts(SyncSource.Settings));
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: resolveConflictsCommandId,
title: localize('resolveConflicts_global', "Show Sync Conflicts (1)"),
id: resolveSettingsConflictsCommandId,
title: localize('resolveConflicts_global', "Sync: Show Settings Conflicts (1)"),
},
when: resolveConflictsWhenContext,
when: resolveSettingsConflictsWhenContext,
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: resolveConflictsCommandId,
title: localize('showConflicts', "Sync: Show Sync Conflicts"),
id: resolveSettingsConflictsCommandId,
title: localize('showConflicts', "Sync: Show Settings Conflicts"),
},
when: resolveConflictsWhenContext,
when: resolveSettingsConflictsWhenContext,
});
const resolveKeybindingsConflictsCommandId = 'workbench.userData.actions.resolveKeybindingsConflicts';
const resolveKeybindingsConflictsWhenContext = ContextKeyRegexExpr.create(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*keybindings.*/i);
CommandsRegistry.registerCommand(resolveKeybindingsConflictsCommandId, () => this.handleConflicts(SyncSource.Keybindings));
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: resolveKeybindingsConflictsCommandId,
title: localize('resolveKeybindingsConflicts_global', "Sync: Show Keybindings Conflicts (1)"),
},
when: resolveKeybindingsConflictsWhenContext,
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: resolveKeybindingsConflictsCommandId,
title: localize('showKeybindingsConflicts', "Sync: Show Keybindings Conflicts"),
},
when: resolveKeybindingsConflictsWhenContext,
});
const signOutMenuItem: IMenuItem = {
@@ -645,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';
@@ -745,7 +794,7 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
return false; // we need a model
}
if (this.isSyncPreviewResource(model.uri)) {
if (getSyncSourceFromPreviewResource(model.uri, this.environmentService) !== undefined) {
return true;
}
@@ -756,50 +805,37 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
return false;
}
private isSyncPreviewResource(uri: URI): boolean {
if (isEqual(uri, this.environmentService.settingsSyncPreviewResource)) {
return true;
}
if (isEqual(uri, this.environmentService.keybindingsSyncPreviewResource)) {
return true;
}
return false;
}
private createAcceptChangesWidgetRenderer(): void {
if (!this.acceptChangesButton) {
const isRemote = getSyncSourceFromRemoteContentResource(this.editor.getModel()!.uri) !== undefined;
const acceptRemoteLabel = localize('accept remote', "Accept Remote");
const acceptLocalLabel = localize('accept local', "Accept Local");
this.acceptChangesButton = this.instantiationService.createInstance(FloatingClickWidget, this.editor, getSyncSourceFromRemoteContentResource(this.editor.getModel()!.uri) !== undefined ? acceptRemoteLabel : acceptLocalLabel, null);
this.acceptChangesButton = this.instantiationService.createInstance(FloatingClickWidget, this.editor, isRemote ? acceptRemoteLabel : acceptLocalLabel, null);
this._register(this.acceptChangesButton.onClick(async () => {
const model = this.editor.getModel();
if (model) {
const conflictsSource = this.userDataSyncService.conflictsSource;
const syncSource = getSyncSourceFromRemoteContentResource(model.uri);
this.telemetryService.publicLog2<{ source: string, action: string }, SyncConflictsClassification>('sync/handleConflicts', { source: conflictsSource!, action: syncSource !== undefined ? 'acceptRemote' : 'acceptLocal' });
const syncAreaLabel = getSyncAreaLabel(conflictsSource!);
const conflictsSource = (getSyncSourceFromPreviewResource(model.uri, this.environmentService) || getSyncSourceFromRemoteContentResource(model.uri))!;
this.telemetryService.publicLog2<{ source: string, action: string }, SyncConflictsClassification>('sync/handleConflicts', { source: conflictsSource, action: isRemote ? 'acceptRemote' : 'acceptLocal' });
const syncAreaLabel = getSyncAreaLabel(conflictsSource);
const result = await this.dialogService.confirm({
type: 'info',
title: syncSource !== undefined
title: isRemote
? localize('Sync accept remote', "Sync: {0}", acceptRemoteLabel)
: localize('Sync accept local', "Sync: {0}", acceptLocalLabel),
message: syncSource !== undefined
message: isRemote
? localize('confirm replace and overwrite local', "Would you like to accept Remote {0} and replace Local {1}?", syncAreaLabel, syncAreaLabel)
: localize('confirm replace and overwrite remote', "Would you like to accept Local {0} and replace Remote {1}?", syncAreaLabel, syncAreaLabel),
primaryButton: syncSource !== undefined ? acceptRemoteLabel : acceptLocalLabel
primaryButton: isRemote ? acceptRemoteLabel : acceptLocalLabel
});
if (result.confirmed) {
try {
await this.userDataSyncService.accept(conflictsSource!, model.getValue());
await this.userDataSyncService.accept(conflictsSource, model.getValue());
} catch (e) {
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.NewLocal) {
this.userDataSyncService.restart().then(() => {
if (conflictsSource === this.userDataSyncService.conflictsSource) {
this.notificationService.warn(localize('update conflicts', "Could not resolve conflicts as there is new local version available. Please try again."));
}
});
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.LocalPreconditionFailed) {
if (this.userDataSyncService.conflictsSources.indexOf(conflictsSource) !== -1) {
this.notificationService.warn(localize('update conflicts', "Could not resolve conflicts as there is new local version available. Please try again."));
}
} else {
this.notificationService.error(e);
}