Skip to content

Commit

Permalink
- contribute sync actions to global activity
Browse files Browse the repository at this point in the history
- implement status in settings sync
- Implement user data sync service
  • Loading branch information
sandy081 committed Sep 11, 2019
1 parent 65f1449 commit 3d9d3fe
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 158 deletions.
179 changes: 103 additions & 76 deletions src/vs/workbench/contrib/userData/common/userData.contribution.ts
Expand Up @@ -4,21 +4,22 @@
*--------------------------------------------------------------------------------------------*/

import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IUserDataSyncService, IRemoteUserDataService } from 'vs/workbench/services/userData/common/userData';
import { IUserDataSyncService, SyncStatus } from 'vs/workbench/services/userData/common/userData';
import { localize } from 'vs/nls';
import { Disposable } from 'vs/base/common/lifecycle';
import { Action } from 'vs/base/common/actions';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { Registry } from 'vs/platform/registry/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { RawContextKey, IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { FalseContext } from 'vs/platform/contextkey/common/contextkeys';
import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity';
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
import { timeout } from 'vs/base/common/async';

const CONTEXT_SYNC_ENABLED = new RawContextKey<boolean>('syncEnabled', false);
const CONTEXT_SYNC_STATE = new RawContextKey<string>('syncStatus', SyncStatus.Uninitialized);

Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
.registerConfiguration({
Expand All @@ -29,106 +30,132 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
properties: {
'userData.autoSync': {
type: 'boolean',
description: localize('userData.autoSync', "When enabled, automatically gets user data. User data is fetched from the installed user data sync extension."),
description: localize('userData.autoSync', "When enabled, automatically synchronises user configuration - Settings, Keybindings, Extensions & Snippets."),
default: false,
scope: ConfigurationScope.APPLICATION
}
}
});

class AutoSyncUserDataContribution extends Disposable implements IWorkbenchContribution {
class AutoSyncUserData extends Disposable implements IWorkbenchContribution {

constructor(
@IConfigurationService private readonly configurationService: IConfigurationService,
@IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
) {
super();
this.autoSync();
}

private async autoSync(): Promise<void> {
if (this.configurationService.getValue<boolean>('userData.autoSync')) {
this.userDataSyncService.synchronise();
private loopAutoSync(): void {
this.autoSync()
.then(() => timeout(1000 * 60 * 5)) // every five minutes
.then(() => this.loopAutoSync());
}

private autoSync(): Promise<any> {
if (this.userDataSyncService.status === SyncStatus.Idle && this.configurationService.getValue<boolean>('userData.autoSync')) {
return this.userDataSyncService.sync();
}
return Promise.resolve();
}


}

class UserDataSyncContextUpdateContribution extends Disposable implements IWorkbenchContribution {
class SyncContribution extends Disposable implements IWorkbenchContribution {

private syncEnablementContext: IContextKey<boolean>;
private readonly syncEnablementContext: IContextKey<string>;
private readonly badgeDisposable = this._register(new MutableDisposable());

constructor(
@IRemoteUserDataService remoteUserDataService: IRemoteUserDataService,
@IContextKeyService contextKeyService: IContextKeyService
@IUserDataSyncService userDataSyncService: IUserDataSyncService,
@IContextKeyService contextKeyService: IContextKeyService,
@IActivityService private readonly activityService: IActivityService
) {
super();
this.syncEnablementContext = CONTEXT_SYNC_ENABLED.bindTo(contextKeyService);
this.syncEnablementContext.set(remoteUserDataService.isEnabled());
this._register(remoteUserDataService.onDidChangeEnablement(enabled => this.syncEnablementContext.set(enabled)));
this.syncEnablementContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService);
this.onDidChangeStatus(userDataSyncService.status);
this._register(userDataSyncService.onDidChangeStatus(status => this.onDidChangeStatus(status)));
this.registerGlobalActivityActions();
}

}
private onDidChangeStatus(status: SyncStatus) {
this.syncEnablementContext.set(status);

const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(UserDataSyncContextUpdateContribution, LifecyclePhase.Starting);
workbenchRegistry.registerWorkbenchContribution(AutoSyncUserDataContribution, LifecyclePhase.Ready);

class ShowUserDataSyncActions extends Action {
let badge: IBadge | undefined = undefined;
let clazz: string | undefined;

public static ID: string = 'workbench.userData.actions.showUserDataSyncActions';
public static LABEL: string = localize('workbench.userData.actions.showUserDataSyncActions.label', "Show User Data Sync Actions");
if (status === SyncStatus.HasConflicts) {
badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts"));
} else if (status === SyncStatus.Syncing) {
badge = new ProgressBadge(() => localize('syncing', "Synchronising User Configuration..."));
clazz = 'progress-badge';
}

constructor(
@IQuickInputService private readonly quickInputService: IQuickInputService,
@ICommandService private commandService: ICommandService,
@IConfigurationService private configurationService: IConfigurationService,
) {
super(ShowUserDataSyncActions.ID, ShowUserDataSyncActions.LABEL);
}
this.badgeDisposable.clear();

async run(): Promise<void> {
return this.showSyncActions();
if (badge) {
this.badgeDisposable.value = this.activityService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz);
}
}

private async showSyncActions(): Promise<void> {
const autoSync = this.configurationService.getValue<boolean>('userData.autoSync');
const picks = [];
if (autoSync) {
picks.push({ label: localize('turn off sync', "Sync: Turn Off Sync"), id: 'workbench.userData.actions.stopAutoSync' });
} else {
picks.push({ label: localize('sync', "Sync: Start Sync"), id: 'workbench.userData.actions.startSync' });
picks.push({ label: localize('turn on sync', "Sync: Turn On Auto Sync"), id: 'workbench.userData.actions.startAutoSync' });
}
picks.push({ label: localize('customise', "Sync: Settings"), id: 'workbench.userData.actions.syncSettings' });
const result = await this.quickInputService.pick(picks, { canPickMany: false });
if (result && result.id) {
return this.commandService.executeCommand(result.id);
}
private registerGlobalActivityActions(): void {
CommandsRegistry.registerCommand('workbench.userData.actions.startSync', serviceAccessor => serviceAccessor.get(IUserDataSyncService).sync());
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: 'workbench.userData.actions.startSync',
title: localize('start sync', "Sync: Start")
},
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.Idle), ContextKeyExpr.not('config.userData.autoSync')),
order: 1
});

CommandsRegistry.registerCommand('workbench.userData.actions.turnOnAutoSync', serviceAccessor => serviceAccessor.get(IConfigurationService).updateValue('userData.autoSync', true));
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: 'workbench.userData.actions.turnOnAutoSync',
title: localize('turn on auto sync', "Turn On Auto Sync")
},
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not('config.userData.autoSync')),
order: 1
});

CommandsRegistry.registerCommand('workbench.userData.actions.turnOffAutoSync', serviceAccessor => serviceAccessor.get(IConfigurationService).updateValue('userData.autoSync', false));
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: 'workbench.userData.actions.turnOffAutoSync',
title: localize('turn off auto sync', "Turn Off Atuo Sync")
},
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has('config.userData.autoSync')),
order: 1
});

CommandsRegistry.registerCommand('sync.resolveConflicts', serviceAccessor => serviceAccessor.get(IUserDataSyncService).resolveConflicts());
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: 'sync.resolveConflicts',
title: localize('resolveConflicts', "Sync: Resolve Conflicts"),
},
when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts),
});

CommandsRegistry.registerCommand('sync.synchronising', () => { });
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: 'sync.synchronising',
title: localize('Synchronising', "Synchronising..."),
precondition: FalseContext
},
when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.Syncing)
});
}
}

CommandsRegistry.registerCommand(ShowUserDataSyncActions.ID, (serviceAccessor) => {
const instantiationService = serviceAccessor.get(IInstantiationService);
return instantiationService.createInstance(ShowUserDataSyncActions).run();
});

CommandsRegistry.registerCommand('workbench.userData.actions.stopAutoSync', (serviceAccessor) => {
const configurationService = serviceAccessor.get(IConfigurationService);
return configurationService.updateValue('userData.autoSync', false);
});

CommandsRegistry.registerCommand('workbench.userData.actions.startAutoSync', (serviceAccessor) => {
const configurationService = serviceAccessor.get(IConfigurationService);
return configurationService.updateValue('userData.autoSync', true);
});

MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: ShowUserDataSyncActions.ID,
title: localize('synchronise user data', "Sync...")
},
when: CONTEXT_SYNC_ENABLED,
order: 1
});
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(SyncContribution, LifecyclePhase.Starting);
workbenchRegistry.registerWorkbenchContribution(AutoSyncUserData, LifecyclePhase.Eventually);

0 comments on commit 3d9d3fe

Please sign in to comment.