提交 52259152 编写于 作者: S Sandeep Somavarapu

#90218 Handle local errors

上级 194dae55
......@@ -187,6 +187,7 @@ export enum UserDataSyncErrorCode {
// Local Errors
LocalPreconditionFailed = 'LocalPreconditionFailed',
LocalInvalidContent = 'LocalInvalidContent',
LocalError = 'LocalError',
Incompatible = 'Incompatible',
Unknown = 'Unknown',
......@@ -293,6 +294,7 @@ export interface IUserDataSyncService {
readonly onDidChangeConflicts: Event<SyncSource[]>;
readonly onDidChangeLocal: Event<void>;
readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]>;
readonly lastSyncTime: number | undefined;
readonly onDidChangeLastSyncTime: Event<number>;
......
......@@ -20,6 +20,7 @@ export class UserDataSyncChannel implements IServerChannel {
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime;
case 'onSyncErrors': return this.service.onSyncErrors;
}
throw new Error(`Event not found: ${event}`);
}
......
......@@ -41,6 +41,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
private _onDidChangeConflicts: Emitter<SyncSource[]> = this._register(new Emitter<SyncSource[]>());
readonly onDidChangeConflicts: Event<SyncSource[]> = this._onDidChangeConflicts.event;
private _syncErrors: [SyncSource, UserDataSyncError][] = [];
private _onSyncErrors: Emitter<[SyncSource, UserDataSyncError][]> = this._register(new Emitter<[SyncSource, UserDataSyncError][]>());
readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]> = this._onSyncErrors.event;
private _lastSyncTime: number | undefined = undefined;
get lastSyncTime(): number | undefined { return this._lastSyncTime; }
private _onDidChangeLastSyncTime: Emitter<number> = this._register(new Emitter<number>());
......@@ -101,6 +105,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
await this.checkEnablement();
const startTime = new Date().getTime();
this._syncErrors = [];
try {
this.logService.trace('Sync started.');
if (this.status !== SyncStatus.HasConflicts) {
......@@ -126,6 +131,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
await synchroniser.sync(manifest && manifest.latest ? manifest.latest[synchroniser.resourceKey] : undefined);
} catch (e) {
this.handleSyncError(e, synchroniser.source);
this._syncErrors.push([synchroniser.source, UserDataSyncError.toUserDataSyncError(e)]);
}
}
......@@ -144,6 +150,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
} finally {
this.updateStatus();
this._onSyncErrors.fire(this._syncErrors);
}
}
......
......@@ -37,11 +37,11 @@ class UserDataSyncSettingsMigrationContribution implements IWorkbenchContributio
}
private async removeFromConfiguration(): Promise<void> {
await this.configurationService.updateValue('sync.enable', undefined, ConfigurationTarget.USER);
await this.configurationService.updateValue('sync.enableSettings', undefined, ConfigurationTarget.USER);
await this.configurationService.updateValue('sync.enableKeybindings', undefined, ConfigurationTarget.USER);
await this.configurationService.updateValue('sync.enableUIState', undefined, ConfigurationTarget.USER);
await this.configurationService.updateValue('sync.enableExtensions', undefined, ConfigurationTarget.USER);
await this.configurationService.updateValue('sync.enable', undefined, {}, ConfigurationTarget.USER, true);
await this.configurationService.updateValue('sync.enableSettings', undefined, {}, ConfigurationTarget.USER, true);
await this.configurationService.updateValue('sync.enableKeybindings', undefined, {}, ConfigurationTarget.USER, true);
await this.configurationService.updateValue('sync.enableUIState', undefined, {}, ConfigurationTarget.USER, true);
await this.configurationService.updateValue('sync.enableExtensions', undefined, {}, ConfigurationTarget.USER, true);
}
}
......
......@@ -109,7 +109,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
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 signInNotificationDisposable = this._register(new MutableDisposable());
private _activeAccount: AuthenticationSession | undefined;
......@@ -149,6 +149,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
this.onDidChangeEnablement(this.userDataSyncEnablementService.isEnabled());
this._register(Event.debounce(userDataSyncService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeSyncStatus(this.userDataSyncService.status)));
this._register(userDataSyncService.onDidChangeConflicts(() => this.onDidChangeConflicts(this.userDataSyncService.conflictsSources)));
this._register(userDataSyncService.onSyncErrors(errors => this.onSyncErrors(errors)));
this._register(this.authTokenService.onTokenFailed(_ => this.authenticationService.getSessions(this.userDataSyncStore!.authenticationProviderId)));
this._register(this.userDataSyncEnablementService.onDidChangeEnablement(enabled => this.onDidChangeEnablement(enabled)));
this._register(this.authenticationService.onDidRegisterAuthenticationProvider(e => this.onDidRegisterAuthenticationProvider(e)));
......@@ -268,6 +269,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
this.updateBadge();
}
private readonly conflictsDisposables = new Map<SyncSource, IDisposable>();
private onDidChangeConflicts(conflicts: SyncSource[]) {
this.updateBadge();
if (conflicts.length) {
......@@ -405,7 +407,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
severity: Severity.Error,
message: localize('too large', "Disabled sync {0} because size of the {1} file to sync is larger than {2}. Please open the file and reduce the size and enable sync", sourceArea, sourceArea, '100kb'),
actions: {
primary: [new Action('open sync file', localize('open file', "Show {0} file", sourceArea), undefined, true,
primary: [new Action('open sync file', localize('open file', "Open {0} file", sourceArea), undefined, true,
() => error.source === SyncSource.Settings ? this.preferencesService.openGlobalSettings(true) : this.preferencesService.openGlobalKeybindingSettings(true))]
}
});
......@@ -421,6 +423,47 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}
}
private readonly invalidContentErrorDisposables = new Map<SyncSource, IDisposable>();
private onSyncErrors(errors: [SyncSource, UserDataSyncError][]): void {
if (errors.length) {
for (const [source, error] of errors) {
switch (error.code) {
case UserDataSyncErrorCode.LocalInvalidContent:
this.handleInvalidContentError(source);
break;
default:
const disposable = this.invalidContentErrorDisposables.get(source);
if (disposable) {
disposable.dispose();
this.invalidContentErrorDisposables.delete(source);
}
}
}
} else {
this.invalidContentErrorDisposables.forEach(disposable => disposable.dispose());
this.invalidContentErrorDisposables.clear();
}
}
private handleInvalidContentError(source: SyncSource): void {
if (!this.invalidContentErrorDisposables.has(source)) {
const errorArea = getSyncAreaLabel(source);
const handle = this.notificationService.notify({
severity: Severity.Error,
message: localize('errorInvalidConfiguration', "Unable to sync {0} because there are some errors/warnings in the file. Please open the file to correct errors/warnings in it.", errorArea),
actions: {
primary: [new Action('open sync file', localize('open file', "Open {0} file", errorArea), undefined, true,
() => source === SyncSource.Settings ? this.preferencesService.openGlobalSettings(true) : this.preferencesService.openGlobalKeybindingSettings(true))]
}
});
this.invalidContentErrorDisposables.set(source, toDisposable(() => {
// close the error warning notification
handle.close();
this.invalidContentErrorDisposables.delete(source);
}));
}
}
private async updateBadge(): Promise<void> {
this.badgeDisposable.clear();
......
......@@ -34,6 +34,9 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
private _onDidChangeLastSyncTime: Emitter<number> = this._register(new Emitter<number>());
readonly onDidChangeLastSyncTime: Event<number> = this._onDidChangeLastSyncTime.event;
private _onSyncErrors: Emitter<[SyncSource, UserDataSyncError][]> = this._register(new Emitter<[SyncSource, UserDataSyncError][]>());
readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]> = this._onSyncErrors.event;
constructor(
@ISharedProcessService sharedProcessService: ISharedProcessService
) {
......@@ -58,6 +61,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
this._register(this.channel.listen<number>('onDidChangeLastSyncTime')(lastSyncTime => this.updateLastSyncTime(lastSyncTime)));
});
this._register(this.channel.listen<SyncSource[]>('onDidChangeConflicts')(conflicts => this.updateConflicts(conflicts)));
this._register(this.channel.listen<[SyncSource, Error][]>('onSyncErrors')(errors => this._onSyncErrors.fire(errors.map(([source, error]) => ([source, UserDataSyncError.toUserDataSyncError(error)])))));
}
pull(): Promise<void> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册