mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 01:25:38 -05:00
Merge from vscode 8a997f7321ae6612fc0e6eb3eac4f358a6233bfb
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user