mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 27ada910e121e23a6d95ecca9cae595fb98ab568
This commit is contained in:
@@ -29,19 +29,18 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import {
|
||||
CONTEXT_SYNC_STATE, ISyncConfiguration, IUserDataAutoSyncService, IUserDataSyncService, registerConfiguration,
|
||||
CONTEXT_SYNC_STATE, IUserDataAutoSyncService, IUserDataSyncService, registerConfiguration,
|
||||
SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_SCHEME, IUserDataSyncEnablementService, CONTEXT_SYNC_ENABLEMENT,
|
||||
SyncResourceConflicts, Conflict, getSyncResourceFromLocalPreview
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets';
|
||||
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IEditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
|
||||
import { IOutputService } from 'vs/workbench/contrib/output/common/output';
|
||||
import { UserDataSyncTrigger } from 'vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger';
|
||||
import { IActivityService, IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
@@ -76,36 +75,33 @@ type FirstTimeSyncClassification = {
|
||||
action: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
};
|
||||
|
||||
const getActivityTitle = (label: string, userDataSyncService: IUserDataSyncService): string => {
|
||||
if (userDataSyncService.status === SyncStatus.Syncing) {
|
||||
return localize('sync is on with syncing', "{0} (syncing)", label);
|
||||
}
|
||||
if (userDataSyncService.lastSyncTime) {
|
||||
return localize('sync is on with time', "{0} (synced {1})", label, fromNow(userDataSyncService.lastSyncTime, true));
|
||||
}
|
||||
return label;
|
||||
};
|
||||
const getIdentityTitle = (label: string, userDataSyncAccountService: UserDataSyncAccounts, authenticationService: IAuthenticationService) => {
|
||||
const account = userDataSyncAccountService.current;
|
||||
return account ? `${label} (${authenticationService.getDisplayName(account.authenticationProviderId)}:${account.accountName})` : label;
|
||||
};
|
||||
const turnOnSyncCommand = { id: 'workbench.userData.actions.syncStart', title: localize('turn on sync with category', "Preferences Sync: Turn On...") };
|
||||
const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title(userDataSyncAccountService: UserDataSyncAccounts, authenticationService: IAuthenticationService) { return getIdentityTitle(localize('stop sync', "Preferences Sync: Turn Off"), userDataSyncAccountService, authenticationService); } };
|
||||
const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title: localize('stop sync', "Preferences Sync: Turn Off") };
|
||||
const resolveSettingsConflictsCommand = { id: 'workbench.userData.actions.resolveSettingsConflicts', title: localize('showConflicts', "Preferences Sync: Show Settings Conflicts") };
|
||||
const resolveKeybindingsConflictsCommand = { id: 'workbench.userData.actions.resolveKeybindingsConflicts', title: localize('showKeybindingsConflicts', "Preferences Sync: Show Keybindings Conflicts") };
|
||||
const resolveSnippetsConflictsCommand = { id: 'workbench.userData.actions.resolveSnippetsConflicts', title: localize('showSnippetsConflicts', "Preferences Sync: Show User Snippets Conflicts") };
|
||||
const configureSyncCommand = { id: 'workbench.userData.actions.configureSync', title: localize('configure sync', "Preferences Sync: Configure...") };
|
||||
const showSyncActivityCommand = {
|
||||
id: 'workbench.userData.actions.showSyncActivity', title(userDataSyncService: IUserDataSyncService): string {
|
||||
return getActivityTitle(localize('show sync log', "Preferences Sync: Show Log"), userDataSyncService);
|
||||
id: 'workbench.userData.actions.showSyncActivity',
|
||||
title: localize('show sync log', "Preferences Sync: Show Log"),
|
||||
description(userDataSyncService: IUserDataSyncService): string | undefined {
|
||||
if (userDataSyncService.status === SyncStatus.Syncing) {
|
||||
return localize('sync is on with syncing', "syncing");
|
||||
}
|
||||
if (userDataSyncService.lastSyncTime) {
|
||||
return localize('sync is on with time', "synced {0}", fromNow(userDataSyncService.lastSyncTime, true));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
const showSyncSettingsCommand = { id: 'workbench.userData.actions.syncSettings', title: localize('sync settings', "Preferences Sync: Show Settings"), };
|
||||
|
||||
const CONTEXT_TURNING_ON_STATE = new RawContextKey<false>('userDataSyncTurningOn', false);
|
||||
const CONTEXT_ACCOUNT_STATE = new RawContextKey<string>('userDataSyncAccountStatus', AccountStatus.Uninitialized);
|
||||
|
||||
export class UserDataSyncWorkbenchContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private readonly turningOnSyncContext: IContextKey<boolean>;
|
||||
private readonly syncEnablementContext: IContextKey<boolean>;
|
||||
private readonly syncStatusContext: IContextKey<string>;
|
||||
private readonly accountStatusContext: IContextKey<string>;
|
||||
@@ -138,6 +134,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
) {
|
||||
super();
|
||||
|
||||
this.turningOnSyncContext = CONTEXT_TURNING_ON_STATE.bindTo(contextKeyService);
|
||||
this.syncEnablementContext = CONTEXT_SYNC_ENABLEMENT.bindTo(contextKeyService);
|
||||
this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService);
|
||||
this.accountStatusContext = CONTEXT_ACCOUNT_STATE.bindTo(contextKeyService);
|
||||
@@ -391,34 +388,67 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
badge = new NumberBadge(1, () => localize('sign in to sync preferences', "Sign in to Sync Preferences"));
|
||||
} else 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"));
|
||||
} else if (this.turningOnSync) {
|
||||
badge = new ProgressBadge(() => localize('turning on syncing', "Turning on Preferences Sync..."));
|
||||
clazz = 'progress-badge';
|
||||
priority = 1;
|
||||
}
|
||||
|
||||
if (badge) {
|
||||
this.badgeDisposable.value = this.activityService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz, priority);
|
||||
this.badgeDisposable.value = this.activityService.showGlobalActivity({ badge, clazz, priority });
|
||||
}
|
||||
}
|
||||
|
||||
private async turnOn(): Promise<void> {
|
||||
if (!this.storageService.getBoolean('sync.donotAskPreviewConfirmation', StorageScope.GLOBAL, false)) {
|
||||
const result = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
localize('sync preview message', "Synchronizing your preferences is a preview feature, please read the documentation before turning it on."),
|
||||
[
|
||||
localize('open doc', "Open Documentation"),
|
||||
localize('turn on', "Turn On"),
|
||||
localize('cancel', "Cancel"),
|
||||
],
|
||||
{
|
||||
cancelId: 2
|
||||
}
|
||||
);
|
||||
switch (result.choice) {
|
||||
case 0: this.openerService.open(URI.parse('https://aka.ms/vscode-settings-sync-help')); return;
|
||||
case 2: return;
|
||||
}
|
||||
}
|
||||
private get turningOnSync(): boolean {
|
||||
return !!this.turningOnSyncContext.get();
|
||||
}
|
||||
|
||||
return new Promise((c, e) => {
|
||||
private set turningOnSync(turningOn: boolean) {
|
||||
this.turningOnSyncContext.set(turningOn);
|
||||
this.updateBadge();
|
||||
}
|
||||
|
||||
private async turnOn(): Promise<void> {
|
||||
this.turningOnSync = true;
|
||||
try {
|
||||
if (!this.storageService.getBoolean('sync.donotAskPreviewConfirmation', StorageScope.GLOBAL, false)) {
|
||||
if (!await this.askForConfirmation()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const turnOn = await this.askToConfigure();
|
||||
if (!turnOn) {
|
||||
return;
|
||||
}
|
||||
await this.doTurnOn();
|
||||
this.storageService.store('sync.donotAskPreviewConfirmation', true, StorageScope.GLOBAL);
|
||||
} finally {
|
||||
this.turningOnSync = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async askForConfirmation(): Promise<boolean> {
|
||||
const result = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
localize('sync preview message', "Synchronizing your preferences is a preview feature, please read the documentation before turning it on."),
|
||||
[
|
||||
localize('open doc', "Open Documentation"),
|
||||
localize('turn on', "Turn On"),
|
||||
localize('cancel', "Cancel"),
|
||||
],
|
||||
{
|
||||
cancelId: 2
|
||||
}
|
||||
);
|
||||
switch (result.choice) {
|
||||
case 0: this.openerService.open(URI.parse('https://aka.ms/vscode-settings-sync-help')); return false;
|
||||
case 2: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async askToConfigure(): Promise<boolean> {
|
||||
return new Promise<boolean>((c, e) => {
|
||||
const disposables: DisposableStore = new DisposableStore();
|
||||
const quickPick = this.quickInputService.createQuickPick<ConfigureSyncQuickPickItem>();
|
||||
disposables.add(quickPick);
|
||||
@@ -441,14 +471,23 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
const items = this.getConfigureSyncQuickPickItems();
|
||||
quickPick.items = items;
|
||||
quickPick.selectedItems = items.filter(item => this.userDataSyncEnablementService.isResourceEnabled(item.id));
|
||||
disposables.add(Event.any(quickPick.onDidAccept, quickPick.onDidCustom)(async () => {
|
||||
if (quickPick.selectedItems.length) {
|
||||
this.updateConfiguration(items, quickPick.selectedItems);
|
||||
this.doTurnOn().then(c, e);
|
||||
quickPick.hide();
|
||||
let accepted: boolean = false;
|
||||
disposables.add(Event.any(quickPick.onDidAccept, quickPick.onDidCustom)(() => {
|
||||
accepted = true;
|
||||
quickPick.hide();
|
||||
}));
|
||||
disposables.add(quickPick.onDidHide(() => {
|
||||
try {
|
||||
if (accepted) {
|
||||
this.updateConfiguration(items, quickPick.selectedItems);
|
||||
}
|
||||
c(accepted);
|
||||
} catch (error) {
|
||||
e(error);
|
||||
} finally {
|
||||
disposables.dispose();
|
||||
}
|
||||
}));
|
||||
disposables.add(quickPick.onDidHide(() => disposables.dispose()));
|
||||
quickPick.show();
|
||||
});
|
||||
}
|
||||
@@ -467,7 +506,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
await this.handleFirstTimeSync();
|
||||
this.userDataSyncEnablementService.setEnablement(true);
|
||||
this.notificationService.info(localize('sync turned on', "Preferences sync is turned on"));
|
||||
this.storageService.store('sync.donotAskPreviewConfirmation', true, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private getConfigureSyncQuickPickItems(): ConfigureSyncQuickPickItem[] {
|
||||
@@ -499,7 +537,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
}
|
||||
}
|
||||
|
||||
private async configureSyncOptions(): Promise<ISyncConfiguration> {
|
||||
private async configureSyncOptions(): Promise<void> {
|
||||
return new Promise((c, e) => {
|
||||
const disposables: DisposableStore = new DisposableStore();
|
||||
const quickPick = this.quickInputService.createQuickPick<ConfigureSyncQuickPickItem>();
|
||||
@@ -514,7 +552,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
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);
|
||||
this.updateConfiguration(items, quickPick.selectedItems);
|
||||
quickPick.hide();
|
||||
}
|
||||
}));
|
||||
@@ -656,6 +694,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
this.registerTurnOnSyncAction();
|
||||
this.registerTurnOffSyncAction();
|
||||
}
|
||||
this.registerTurninOnSyncAction();
|
||||
this.registerSignInAction(); // When Sync is turned on from CLI
|
||||
this.registerShowSettingsConflictsAction();
|
||||
this.registerShowKeybindingsConflictsAction();
|
||||
@@ -668,7 +707,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
}
|
||||
|
||||
private registerTurnOnSyncAction(): void {
|
||||
const turnOnSyncWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT.toNegated(), CONTEXT_ACCOUNT_STATE.notEqualsTo(AccountStatus.Uninitialized));
|
||||
const turnOnSyncWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT.toNegated(), CONTEXT_ACCOUNT_STATE.notEqualsTo(AccountStatus.Uninitialized), CONTEXT_TURNING_ON_STATE.negate());
|
||||
CommandsRegistry.registerCommand(turnOnSyncCommand.id, async () => {
|
||||
try {
|
||||
await this.turnOn();
|
||||
@@ -709,6 +748,30 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
});
|
||||
}
|
||||
|
||||
private registerTurninOnSyncAction(): void {
|
||||
const when = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT.toNegated(), CONTEXT_ACCOUNT_STATE.notEqualsTo(AccountStatus.Uninitialized), CONTEXT_TURNING_ON_STATE);
|
||||
this._register(registerAction2(class TurningOnSyncAction extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.userData.actions.turningOn',
|
||||
title: localize('turnin on sync', "Turning on Preferences Sync..."),
|
||||
precondition: ContextKeyExpr.false(),
|
||||
menu: [{
|
||||
group: '5_sync',
|
||||
id: MenuId.GlobalActivity,
|
||||
when,
|
||||
order: 2
|
||||
}, {
|
||||
group: '1_sync',
|
||||
id: MenuId.AccountsContext,
|
||||
when,
|
||||
}]
|
||||
});
|
||||
}
|
||||
async run(): Promise<any> { }
|
||||
}));
|
||||
}
|
||||
|
||||
private registerSignInAction(): void {
|
||||
const that = this;
|
||||
const id = 'workbench.userData.actions.signin';
|
||||
@@ -883,10 +946,11 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
}
|
||||
items.push({ id: configureSyncCommand.id, label: configureSyncCommand.title });
|
||||
items.push({ id: showSyncSettingsCommand.id, label: showSyncSettingsCommand.title });
|
||||
items.push({ id: showSyncActivityCommand.id, label: showSyncActivityCommand.title(that.userDataSyncService) });
|
||||
items.push({ id: showSyncActivityCommand.id, label: showSyncActivityCommand.title, description: showSyncActivityCommand.description(that.userDataSyncService) });
|
||||
items.push({ type: 'separator' });
|
||||
if (that.userDataSyncEnablementService.canToggleEnablement()) {
|
||||
items.push({ id: stopSyncCommand.id, label: stopSyncCommand.title(that.userDataSyncAccounts, that.authenticationService) });
|
||||
const account = that.userDataSyncAccounts.current;
|
||||
items.push({ id: stopSyncCommand.id, label: stopSyncCommand.title, description: account ? `${account.accountName} (${that.authenticationService.getDisplayName(account.authenticationProviderId)})` : undefined });
|
||||
}
|
||||
quickPick.items = items;
|
||||
disposables.add(quickPick.onDidAccept(() => {
|
||||
@@ -911,7 +975,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
constructor() {
|
||||
super({
|
||||
id: stopSyncCommand.id,
|
||||
title: stopSyncCommand.title(that.userDataSyncAccounts, that.authenticationService),
|
||||
title: stopSyncCommand.title,
|
||||
menu: {
|
||||
id: MenuId.CommandPalette,
|
||||
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT),
|
||||
@@ -953,7 +1017,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
constructor() {
|
||||
super({
|
||||
id: showSyncActivityCommand.id,
|
||||
get title() { return showSyncActivityCommand.title(that.userDataSyncService); },
|
||||
title: showSyncActivityCommand.title,
|
||||
menu: {
|
||||
id: MenuId.CommandPalette,
|
||||
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized)),
|
||||
|
||||
@@ -29,12 +29,16 @@ type UserAccountEvent = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
type AccountQuickPickItem = { label: string, authenticationProvider: IAuthenticationProvider, account?: IUserDataSyncAccount, detail?: string };
|
||||
type AccountQuickPickItem = { label: string, authenticationProvider: IAuthenticationProvider, account?: UserDataSyncAccount, description?: string };
|
||||
|
||||
export interface IUserDataSyncAccount {
|
||||
readonly authenticationProviderId: string;
|
||||
readonly sessionId: string;
|
||||
readonly accountName: string;
|
||||
export class UserDataSyncAccount {
|
||||
|
||||
constructor(readonly authenticationProviderId: string, private readonly session: AuthenticationSession) { }
|
||||
|
||||
get sessionId(): string { return this.session.id; }
|
||||
get accountName(): string { return this.session.account.displayName; }
|
||||
get accountId(): string { return this.session.account.id; }
|
||||
getToken(): Thenable<string> { return this.session.getAccessToken(); }
|
||||
}
|
||||
|
||||
export const enum AccountStatus {
|
||||
@@ -60,10 +64,10 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
private readonly _onDidSignOut = this._register(new Emitter<void>());
|
||||
readonly onDidSignOut = this._onDidSignOut.event;
|
||||
|
||||
private _all: Map<string, IUserDataSyncAccount[]> = new Map<string, IUserDataSyncAccount[]>();
|
||||
get all(): IUserDataSyncAccount[] { return flatten(values(this._all)); }
|
||||
private _all: Map<string, UserDataSyncAccount[]> = new Map<string, UserDataSyncAccount[]>();
|
||||
get all(): UserDataSyncAccount[] { return flatten(values(this._all)); }
|
||||
|
||||
get current(): IUserDataSyncAccount | undefined { return this.all.filter(account => this.isCurrentAccount(account))[0]; }
|
||||
get current(): UserDataSyncAccount | undefined { return this.all.filter(account => this.isCurrentAccount(account))[0]; }
|
||||
|
||||
constructor(
|
||||
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
|
||||
@@ -123,19 +127,58 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
}
|
||||
|
||||
private async update(): Promise<void> {
|
||||
const allAccounts: Map<string, IUserDataSyncAccount[]> = new Map<string, IUserDataSyncAccount[]>();
|
||||
const allAccounts: Map<string, UserDataSyncAccount[]> = new Map<string, UserDataSyncAccount[]>();
|
||||
for (const { id } of this.authenticationProviders) {
|
||||
const accounts = await this.getAccounts(id);
|
||||
allAccounts.set(id, accounts);
|
||||
}
|
||||
|
||||
this._all = allAccounts;
|
||||
const status = this.current ? AccountStatus.Available : AccountStatus.Unavailable;
|
||||
const current = this.current;
|
||||
await this.updateToken(current);
|
||||
this.updateStatus(current);
|
||||
}
|
||||
|
||||
if (this._status === AccountStatus.Unavailable) {
|
||||
await this.authenticationTokenService.setToken(undefined);
|
||||
private async getAccounts(authenticationProviderId: string): Promise<UserDataSyncAccount[]> {
|
||||
let accounts: Map<string, UserDataSyncAccount> = new Map<string, UserDataSyncAccount>();
|
||||
let currentAccount: UserDataSyncAccount | null = null;
|
||||
|
||||
const sessions = await this.authenticationService.getSessions(authenticationProviderId) || [];
|
||||
for (const session of sessions) {
|
||||
const account: UserDataSyncAccount = new UserDataSyncAccount(authenticationProviderId, session);
|
||||
accounts.set(account.accountName, account);
|
||||
if (this.isCurrentAccount(account)) {
|
||||
currentAccount = account;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentAccount) {
|
||||
// Always use current account if available
|
||||
accounts.set(currentAccount.accountName, currentAccount);
|
||||
}
|
||||
|
||||
return values(accounts);
|
||||
}
|
||||
|
||||
private async updateToken(current: UserDataSyncAccount | undefined): Promise<void> {
|
||||
let value: { token: string, authenticationProviderId: string } | undefined = undefined;
|
||||
if (current) {
|
||||
try {
|
||||
this.logService.trace('Preferences Sync: Updating the token for the account', current.accountName);
|
||||
const token = await current.getToken();
|
||||
this.logService.trace('Preferences Sync: Token updated for the account', current.accountName);
|
||||
value = { token, authenticationProviderId: current.authenticationProviderId };
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
await this.authenticationTokenService.setToken(value);
|
||||
}
|
||||
|
||||
private updateStatus(current: UserDataSyncAccount | undefined): void {
|
||||
// set status
|
||||
const status: AccountStatus = current ? AccountStatus.Available : AccountStatus.Unavailable;
|
||||
|
||||
if (this._status !== status) {
|
||||
const previous = this._status;
|
||||
this.logService.debug('Sync account status changed', previous, status);
|
||||
@@ -149,41 +192,7 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private async getAccounts(authenticationProviderId: string): Promise<IUserDataSyncAccount[]> {
|
||||
|
||||
let accounts: Map<string, IUserDataSyncAccount> = new Map<string, IUserDataSyncAccount>();
|
||||
let currentAccount: IUserDataSyncAccount | null = null;
|
||||
let currentSession: AuthenticationSession | undefined = undefined;
|
||||
|
||||
const sessions = await this.authenticationService.getSessions(authenticationProviderId) || [];
|
||||
for (const session of sessions) {
|
||||
const account: IUserDataSyncAccount = { authenticationProviderId, sessionId: session.id, accountName: session.account.displayName };
|
||||
accounts.set(account.accountName, account);
|
||||
if (this.isCurrentAccount(account)) {
|
||||
currentAccount = account;
|
||||
currentSession = session;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentAccount) {
|
||||
// Always use current account if available
|
||||
accounts.set(currentAccount.accountName, currentAccount);
|
||||
}
|
||||
|
||||
// update access token
|
||||
if (currentSession) {
|
||||
try {
|
||||
const token = await currentSession.getAccessToken();
|
||||
await this.authenticationTokenService.setToken({ token, authenticationProviderId });
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
return values(accounts);
|
||||
}
|
||||
|
||||
private isCurrentAccount(account: IUserDataSyncAccount): boolean {
|
||||
private isCurrentAccount(account: UserDataSyncAccount): boolean {
|
||||
return account.sessionId === this.currentSessionId;
|
||||
}
|
||||
|
||||
@@ -192,20 +201,22 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
let sessionId: string, accountName: string;
|
||||
let sessionId: string, accountName: string, accountId: string;
|
||||
if (isAuthenticationProvider(result)) {
|
||||
const session = await this.authenticationService.login(result.id, result.scopes);
|
||||
sessionId = session.id;
|
||||
accountName = session.account.displayName;
|
||||
accountId = session.account.id;
|
||||
} else {
|
||||
sessionId = result.sessionId;
|
||||
accountName = result.accountName;
|
||||
accountId = result.accountId;
|
||||
}
|
||||
await this.switch(sessionId, accountName);
|
||||
await this.switch(sessionId, accountName, accountId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private async doPick(): Promise<IUserDataSyncAccount | IAuthenticationProvider | undefined> {
|
||||
private async doPick(): Promise<UserDataSyncAccount | IAuthenticationProvider | undefined> {
|
||||
if (this.authenticationProviders.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -217,8 +228,8 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
return this.authenticationProviders[0];
|
||||
}
|
||||
|
||||
return new Promise<IUserDataSyncAccount | IAuthenticationProvider | undefined>(async (c, e) => {
|
||||
let result: IUserDataSyncAccount | IAuthenticationProvider | undefined;
|
||||
return new Promise<UserDataSyncAccount | IAuthenticationProvider | undefined>(async (c, e) => {
|
||||
let result: UserDataSyncAccount | IAuthenticationProvider | undefined;
|
||||
const disposables: DisposableStore = new DisposableStore();
|
||||
const quickPick = this.quickInputService.createQuickPick<AccountQuickPickItem>();
|
||||
disposables.add(quickPick);
|
||||
@@ -243,38 +254,42 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
|
||||
private createQuickpickItems(): (AccountQuickPickItem | IQuickPickSeparator)[] {
|
||||
const quickPickItems: (AccountQuickPickItem | IQuickPickSeparator)[] = [];
|
||||
const authenticationProviders = [...this.authenticationProviders].sort(({ id }) => id === this.current?.authenticationProviderId ? -1 : 1);
|
||||
for (const authenticationProvider of authenticationProviders) {
|
||||
const providerName = this.authenticationService.getDisplayName(authenticationProvider.id);
|
||||
if (this.all.length) {
|
||||
quickPickItems.push({ type: 'separator', label: providerName });
|
||||
const accounts = this._all.get(authenticationProvider.id) || [];
|
||||
|
||||
// Signed in Accounts
|
||||
if (this.all.length) {
|
||||
const authenticationProviders = [...this.authenticationProviders].sort(({ id }) => id === this.current?.authenticationProviderId ? -1 : 1);
|
||||
quickPickItems.push({ type: 'separator', label: localize('signed in', "Signed in") });
|
||||
for (const authenticationProvider of authenticationProviders) {
|
||||
const accounts = (this._all.get(authenticationProvider.id) || []).sort(({ sessionId }) => sessionId === this.current?.sessionId ? -1 : 1);
|
||||
const providerName = this.authenticationService.getDisplayName(authenticationProvider.id);
|
||||
for (const account of accounts) {
|
||||
quickPickItems.push({
|
||||
label: account.accountName,
|
||||
detail: account.sessionId === this.current?.sessionId ? localize('last used', "Last Used") : undefined,
|
||||
label: `${account.accountName} (${providerName})`,
|
||||
description: account.sessionId === this.current?.sessionId ? localize('last used', "Last Used with Sync") : undefined,
|
||||
account,
|
||||
authenticationProvider,
|
||||
});
|
||||
}
|
||||
quickPickItems.push({
|
||||
label: accounts.length ? localize('use another', "Use another {0} Account", providerName) : localize('use provider account', "Use {0} Account", providerName),
|
||||
authenticationProvider,
|
||||
});
|
||||
} else {
|
||||
quickPickItems.push({ label: providerName, authenticationProvider });
|
||||
}
|
||||
quickPickItems.push({ type: 'separator', label: localize('others', "Others") });
|
||||
}
|
||||
|
||||
// Account proviers
|
||||
for (const authenticationProvider of this.authenticationProviders) {
|
||||
const providerName = this.authenticationService.getDisplayName(authenticationProvider.id);
|
||||
quickPickItems.push({ label: localize('sign in using account', "Sign in with {0}", providerName), authenticationProvider });
|
||||
}
|
||||
|
||||
return quickPickItems;
|
||||
}
|
||||
|
||||
private async switch(sessionId: string, accountName: string): Promise<void> {
|
||||
private async switch(sessionId: string, accountName: string, accountId: string): Promise<void> {
|
||||
const currentAccount = this.current;
|
||||
if (this.userDataSyncEnablementService.isEnabled() && (currentAccount && currentAccount.accountName !== accountName)) {
|
||||
// accounts are switched while sync is enabled.
|
||||
}
|
||||
this.currentSessionId = sessionId;
|
||||
this.telemetryService.publicLog2<UserAccountEvent, UserAccountClassification>('sync.userAccount', { id: sessionId.split('/')[1] });
|
||||
this.telemetryService.publicLog2<UserAccountEvent, UserAccountClassification>('sync.userAccount', { id: accountId });
|
||||
await this.update();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IViewsRegistry, Extensions, ITreeViewDescriptor, ITreeViewDataProvider, ITreeItem, TreeItemCollapsibleState, IViewsService, TreeViewItemHandleArg, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views';
|
||||
import { IViewsRegistry, Extensions, ITreeViewDescriptor, ITreeViewDataProvider, ITreeItem, TreeItemCollapsibleState, IViewsService, TreeViewItemHandleArg, IViewContainersRegistry, ViewContainerLocation, ViewContainer, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { localize } from 'vs/nls';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { TreeViewPane, TreeView } from 'vs/workbench/browser/parts/views/treeView';
|
||||
@@ -89,8 +89,24 @@ export class UserDataSyncViewContribution implements IWorkbenchContribution {
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const viewDescriptorService = accessor.get(IViewDescriptorService);
|
||||
const viewsService = accessor.get(IViewsService);
|
||||
viewEnablementContext.set(true);
|
||||
accessor.get(IViewsService).openView(id, true);
|
||||
const viewContainer = viewDescriptorService.getViewContainerByViewId(id);
|
||||
if (viewContainer) {
|
||||
const model = viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
if (model.activeViewDescriptors.some(viewDescriptor => viewDescriptor.id === id)) {
|
||||
viewsService.openView(id, true);
|
||||
} else {
|
||||
const disposable = model.onDidChangeActiveViewDescriptors(e => {
|
||||
if (e.added.some(viewDescriptor => viewDescriptor.id === id)) {
|
||||
disposable.dispose();
|
||||
viewsService.openView(id, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user