diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 7f6c5992c40..8d6f6d3754c 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -358,8 +358,6 @@ export interface IUserDataSyncResourceEnablementService { setResourceEnablement(resource: SyncResource, enabled: boolean): void; } -export type SyncResourceConflicts = { syncResource: SyncResource, conflicts: IResourcePreview[] }; - export interface ISyncTask { readonly manifest: IUserDataManifest | null; run(): Promise; @@ -384,8 +382,8 @@ export interface IUserDataSyncService { readonly onDidChangeStatus: Event; readonly onSynchronizeResource: Event; - readonly conflicts: SyncResourceConflicts[]; - readonly onDidChangeConflicts: Event; + readonly conflicts: [SyncResource, IResourcePreview[]][]; + readonly onDidChangeConflicts: Event<[SyncResource, IResourcePreview[]][]>; readonly onDidChangeLocal: Event; readonly onSyncErrors: Event<[SyncResource, UserDataSyncError][]>; diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index e02647b4373..132f3d06f48 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncResource, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncErrorCode, UserDataSyncError, SyncResourceConflicts, ISyncResourceHandle, IUserDataManifest, ISyncTask, Change, IResourcePreview, IManualSyncTask, ISyncResourcePreview } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncResource, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncErrorCode, UserDataSyncError, ISyncResourceHandle, IUserDataManifest, ISyncTask, Change, IResourcePreview, IManualSyncTask, ISyncResourcePreview } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Emitter, Event } from 'vs/base/common/event'; @@ -47,10 +47,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ readonly onDidChangeLocal: Event; - private _conflicts: SyncResourceConflicts[] = []; - get conflicts(): SyncResourceConflicts[] { return this._conflicts; } - private _onDidChangeConflicts: Emitter = this._register(new Emitter()); - readonly onDidChangeConflicts: Event = this._onDidChangeConflicts.event; + private _conflicts: [SyncResource, IResourcePreview[]][] = []; + get conflicts(): [SyncResource, IResourcePreview[]][] { return this._conflicts; } + private _onDidChangeConflicts: Emitter<[SyncResource, IResourcePreview[]][]> = this._register(new Emitter<[SyncResource, IResourcePreview[]][]>()); + readonly onDidChangeConflicts: Event<[SyncResource, IResourcePreview[]][]> = this._onDidChangeConflicts.event; private _syncErrors: [SyncResource, UserDataSyncError][] = []; private _onSyncErrors: Emitter<[SyncResource, UserDataSyncError][]> = this._register(new Emitter<[SyncResource, UserDataSyncError][]>()); @@ -393,7 +393,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ private updateConflicts(): void { const conflicts = this.computeConflicts(); - if (!equals(this._conflicts, conflicts, (a, b) => a.syncResource === b.syncResource && equals(a.conflicts, b.conflicts, (a, b) => isEqual(a.previewResource, b.previewResource)))) { + if (!equals(this._conflicts, conflicts, ([syncResourceA, conflictsA], [syncResourceB, conflictsB]) => syncResourceA === syncResourceA && equals(conflictsA, conflictsB, (a, b) => isEqual(a.previewResource, b.previewResource)))) { this._conflicts = this.computeConflicts(); this._onDidChangeConflicts.fire(conflicts); } @@ -438,9 +438,9 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ this.logService.error(`${source}: ${toErrorMessage(e)}`); } - private computeConflicts(): SyncResourceConflicts[] { + private computeConflicts(): [SyncResource, IResourcePreview[]][] { return this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts) - .map(s => ({ syncResource: s.resource, conflicts: s.conflicts.map(toStrictResourcePreview) })); + .map(s => ([s.resource, s.conflicts.map(toStrictResourcePreview)])); } getSynchroniser(source: SyncResource): IUserDataSynchroniser { diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts index d05b8b5026e..0fa55f6be9c 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts @@ -420,7 +420,7 @@ suite('UserDataSyncService', () => { await (await testObject.createSyncTask()).run(); assert.deepEqual(testObject.status, SyncStatus.HasConflicts); - assert.deepEqual(testObject.conflicts.map(({ syncResource }) => syncResource), [SyncResource.Settings]); + assert.deepEqual(testObject.conflicts.map(([syncResource]) => syncResource), [SyncResource.Settings]); }); test('test sync will sync other non conflicted areas', async () => { diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 3df289d8e9f..b58d587c678 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, - SyncResourceConflicts, getSyncResourceFromLocalPreview, IResourcePreview + getSyncResourceFromLocalPreview, IResourcePreview } from 'vs/platform/userDataSync/common/userDataSync'; import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -155,10 +155,10 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private readonly conflictsDisposables = new Map(); - private onDidChangeConflicts(conflicts: SyncResourceConflicts[]) { + private onDidChangeConflicts(conflicts: [SyncResource, IResourcePreview[]][]) { this.updateGlobalActivityBadge(); if (conflicts.length) { - const conflictsSources: SyncResource[] = conflicts.map(conflict => conflict.syncResource); + const conflictsSources: SyncResource[] = conflicts.map(([syncResource]) => syncResource); this.conflictsSources.set(conflictsSources.join(',')); if (conflictsSources.indexOf(SyncResource.Snippets) !== -1) { this.registerShowSnippetsConflictsAction(); @@ -172,7 +172,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } }); - for (const { syncResource, conflicts } of this.userDataSyncService.conflicts) { + for (const [syncResource, conflicts] of this.userDataSyncService.conflicts) { const conflictsEditorInputs = this.getConflictsEditorInputs(syncResource); // close stale conflicts editor previews @@ -207,7 +207,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo label: localize('show conflicts', "Show Conflicts"), run: () => { this.telemetryService.publicLog2<{ source: string, action?: string }, SyncConflictsClassification>('sync/showConflicts', { source: syncResource }); - this.handleConflicts({ syncResource, conflicts }); + this.handleConflicts([syncResource, conflicts]); } } ], @@ -376,7 +376,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo let priority: number | undefined = undefined; if (this.userDataSyncService.conflicts.length) { - badge = new NumberBadge(this.userDataSyncService.conflicts.reduce((result, syncResourceConflict) => { return result + syncResourceConflict.conflicts.length; }, 0), () => localize('has conflicts', "Preferences Sync: Conflicts Detected")); + badge = new NumberBadge(this.userDataSyncService.conflicts.reduce((result, [, conflicts]) => { return result + conflicts.length; }, 0), () => localize('has conflicts', "Preferences Sync: Conflicts Detected")); } else if (this.turningOnSync) { badge = new ProgressBadge(() => localize('turning on syncing', "Turning on Preferences Sync...")); clazz = 'progress-badge'; @@ -611,13 +611,13 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private async handleSyncResourceConflicts(resource: SyncResource): Promise { - const syncResourceCoflicts = this.userDataSyncService.conflicts.filter(({ syncResource }) => syncResource === resource)[0]; + const syncResourceCoflicts = this.userDataSyncService.conflicts.filter(([syncResource]) => syncResource === resource)[0]; if (syncResourceCoflicts) { this.handleConflicts(syncResourceCoflicts); } } - private async handleConflicts({ syncResource, conflicts }: SyncResourceConflicts): Promise { + private async handleConflicts([syncResource, conflicts]: [SyncResource, IResourcePreview[]]): Promise { for (const conflict of conflicts) { let label: string | undefined = undefined; if (syncResource === SyncResource.Settings) { @@ -814,7 +814,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private registerShowSnippetsConflictsAction(): void { this._snippetsConflictsActionsDisposable.clear(); const resolveSnippetsConflictsWhenContext = ContextKeyExpr.regex(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*snippets.*/i); - const conflicts: IResourcePreview[] | undefined = this.userDataSyncService.conflicts.filter(({ syncResource }) => syncResource === SyncResource.Snippets)[0]?.conflicts; + const conflicts: IResourcePreview[] | undefined = this.userDataSyncService.conflicts.filter(([syncResource]) => syncResource === SyncResource.Snippets)[0]?.[1]; this._snippetsConflictsActionsDisposable.add(CommandsRegistry.registerCommand(resolveSnippetsConflictsCommand.id, () => this.handleSyncResourceConflicts(SyncResource.Snippets))); this._snippetsConflictsActionsDisposable.add(MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', @@ -878,7 +878,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo disposables.add(quickPick); const items: Array = []; if (that.userDataSyncService.conflicts.length) { - for (const { syncResource } of that.userDataSyncService.conflicts) { + for (const [syncResource] of that.userDataSyncService.conflicts) { switch (syncResource) { case SyncResource.Settings: items.push({ id: resolveSettingsConflictsCommand.id, label: resolveSettingsConflictsCommand.title }); @@ -1127,11 +1127,11 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio return false; } - if (syncResourceConflicts.conflicts.some(({ previewResource }) => isEqual(previewResource, model.uri))) { + if (syncResourceConflicts[1].some(({ previewResource }) => isEqual(previewResource, model.uri))) { return true; } - if (syncResourceConflicts.conflicts.some(({ remoteResource }) => isEqual(remoteResource, model.uri))) { + if (syncResourceConflicts[1].some(({ remoteResource }) => isEqual(remoteResource, model.uri))) { return this.configurationService.getValue('diffEditor.renderSideBySide'); } @@ -1141,16 +1141,16 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio private createAcceptChangesWidgetRenderer(): void { if (!this.acceptChangesButton) { const resource = this.editor.getModel()!.uri; - const syncResourceConflicts = this.getSyncResourceConflicts(resource)!; - const isRemote = syncResourceConflicts.conflicts.some(({ remoteResource }) => isEqual(remoteResource, resource)); + const [syncResource, conflicts] = this.getSyncResourceConflicts(resource)!; + const isRemote = conflicts.some(({ remoteResource }) => isEqual(remoteResource, resource)); const acceptRemoteLabel = localize('accept remote', "Accept Remote"); const acceptLocalLabel = localize('accept local', "Accept Local"); 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) { - this.telemetryService.publicLog2<{ source: string, action: string }, SyncConflictsClassification>('sync/handleConflicts', { source: syncResourceConflicts.syncResource, action: isRemote ? 'acceptRemote' : 'acceptLocal' }); - const syncAreaLabel = getSyncAreaLabel(syncResourceConflicts.syncResource); + this.telemetryService.publicLog2<{ source: string, action: string }, SyncConflictsClassification>('sync/handleConflicts', { source: syncResource, action: isRemote ? 'acceptRemote' : 'acceptLocal' }); + const syncAreaLabel = getSyncAreaLabel(syncResource); const result = await this.dialogService.confirm({ type: 'info', title: isRemote @@ -1163,11 +1163,11 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio }); if (result.confirmed) { try { - await this.userDataSyncService.acceptPreviewContent(syncResourceConflicts.syncResource, model.uri, model.getValue()); + await this.userDataSyncService.acceptPreviewContent(syncResource, model.uri, model.getValue()); } catch (e) { if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.LocalPreconditionFailed) { - const syncResourceCoflicts = this.userDataSyncService.conflicts.filter(({ syncResource }) => syncResource === syncResourceConflicts.syncResource)[0]; - if (syncResourceCoflicts && syncResourceCoflicts.conflicts.some(conflict => isEqual(conflict.previewResource, model.uri) || isEqual(conflict.remoteResource, model.uri))) { + const syncResourceCoflicts = this.userDataSyncService.conflicts.filter(syncResourceCoflicts => syncResourceCoflicts[0] === syncResource)[0]; + if (syncResourceCoflicts && conflicts.some(conflict => isEqual(conflict.previewResource, model.uri) || isEqual(conflict.remoteResource, model.uri))) { this.notificationService.warn(localize('update conflicts', "Could not resolve conflicts as there is new local version available. Please try again.")); } } else { @@ -1182,8 +1182,8 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio } } - private getSyncResourceConflicts(resource: URI): SyncResourceConflicts | undefined { - return this.userDataSyncService.conflicts.filter(({ conflicts }) => conflicts.some(({ previewResource, remoteResource }) => isEqual(previewResource, resource) || isEqual(remoteResource, resource)))[0]; + private getSyncResourceConflicts(resource: URI): [SyncResource, IResourcePreview[]] | undefined { + return this.userDataSyncService.conflicts.filter(([, conflicts]) => conflicts.some(({ previewResource, remoteResource }) => isEqual(previewResource, resource) || isEqual(remoteResource, resource)))[0]; } private disposeAcceptChangesWidgetRenderer(): void { diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts index fe3f20be488..9c5bad31ae5 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SyncStatus, SyncResource, IUserDataSyncService, UserDataSyncError, SyncResourceConflicts, ISyncResourceHandle, ISyncTask, IManualSyncTask, IUserDataManifest, ISyncResourcePreview } from 'vs/platform/userDataSync/common/userDataSync'; +import { SyncStatus, SyncResource, IUserDataSyncService, UserDataSyncError, ISyncResourceHandle, ISyncTask, IManualSyncTask, IUserDataManifest, ISyncResourcePreview, IResourcePreview } from 'vs/platform/userDataSync/common/userDataSync'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; @@ -25,10 +25,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } - private _conflicts: SyncResourceConflicts[] = []; - get conflicts(): SyncResourceConflicts[] { return this._conflicts; } - private _onDidChangeConflicts: Emitter = this._register(new Emitter()); - readonly onDidChangeConflicts: Event = this._onDidChangeConflicts.event; + private _conflicts: [SyncResource, IResourcePreview[]][] = []; + get conflicts(): [SyncResource, IResourcePreview[]][] { return this._conflicts; } + private _onDidChangeConflicts: Emitter<[SyncResource, IResourcePreview[]][]> = this._register(new Emitter<[SyncResource, IResourcePreview[]][]>()); + readonly onDidChangeConflicts: Event<[SyncResource, IResourcePreview[]][]> = this._onDidChangeConflicts.event; private _lastSyncTime: number | undefined = undefined; get lastSyncTime(): number | undefined { return this._lastSyncTime; } @@ -54,7 +54,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return userDataSyncChannel.listen(event, arg); } }; - this.channel.call<[SyncStatus, SyncResourceConflicts[], number | undefined]>('_getInitialData').then(([status, conflicts, lastSyncTime]) => { + this.channel.call<[SyncStatus, [SyncResource, IResourcePreview[]][], number | undefined]>('_getInitialData').then(([status, conflicts, lastSyncTime]) => { this.updateStatus(status); this.updateConflicts(conflicts); if (lastSyncTime) { @@ -63,7 +63,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); this._register(this.channel.listen('onDidChangeLastSyncTime')(lastSyncTime => this.updateLastSyncTime(lastSyncTime))); }); - this._register(this.channel.listen('onDidChangeConflicts')(conflicts => this.updateConflicts(conflicts))); + this._register(this.channel.listen<[SyncResource, IResourcePreview[]][]>('onDidChangeConflicts')(conflicts => this.updateConflicts(conflicts))); this._register(this.channel.listen<[SyncResource, Error][]>('onSyncErrors')(errors => this._onSyncErrors.fire(errors.map(([source, error]) => ([source, UserDataSyncError.toUserDataSyncError(error)]))))); } @@ -136,19 +136,19 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ this._onDidChangeStatus.fire(status); } - private async updateConflicts(conflicts: SyncResourceConflicts[]): Promise { + private async updateConflicts(conflicts: [SyncResource, IResourcePreview[]][]): Promise { // Revive URIs - this._conflicts = conflicts.map(c => - ({ - syncResource: c.syncResource, - conflicts: c.conflicts.map(r => + this._conflicts = conflicts.map(([syncResource, conflicts]) => + ([ + syncResource, + conflicts.map(r => ({ ...r, localResource: URI.revive(r.localResource), remoteResource: URI.revive(r.remoteResource), previewResource: URI.revive(r.previewResource), })) - })); + ])); this._onDidChangeConflicts.fire(conflicts); }