Skip to content

Commit

Permalink
Deduplicate account name entries in account context menu
Browse files Browse the repository at this point in the history
  • Loading branch information
Rachel Macfarlane committed Mar 26, 2020
1 parent 5f0cfc3 commit fc7ac81
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 36 deletions.
84 changes: 50 additions & 34 deletions src/vs/workbench/api/browser/mainThreadAuthentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [

export class MainThreadAuthenticationProvider extends Disposable {
private _sessionMenuItems = new Map<string, IDisposable[]>();
private _sessionIds: string[] = [];
private _accounts = new Map<string, string[]>(); // Map account name to session ids
private _sessions = new Map<string, string>(); // Map account id to name

constructor(
private readonly _proxy: ExtHostAuthenticationShape,
Expand All @@ -44,10 +45,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
) {
super();

if (!dependents.length) {
return;
}

this.registerCommandsAndContextMenuItems();
}

Expand Down Expand Up @@ -86,29 +83,40 @@ export class MainThreadAuthenticationProvider extends Disposable {
}

private registerCommandsAndContextMenuItems(): void {
this._register(CommandsRegistry.registerCommand({
id: `signIn${this.id}`,
handler: (accessor, args) => {
this.setPermissionsForAccount(accessor.get(IQuickInputService), true);
},
}));

this._register(MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
group: '2_providers',
command: {
if (this.dependents.length) {
this._register(CommandsRegistry.registerCommand({
id: `signIn${this.id}`,
title: nls.localize('addAccount', "Sign in to {0}", this.displayName)
},
order: 3
}));
handler: (accessor, args) => {
this.setPermissionsForAccount(accessor.get(IQuickInputService), true);
},
}));

this._register(MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
group: '2_providers',
command: {
id: `signIn${this.id}`,
title: nls.localize('addAccount', "Sign in to {0}", this.displayName)
},
order: 3
}));
}

this._proxy.$getSessions(this.id).then(sessions => {
sessions.forEach(session => this.registerSession(session));
});
}

private registerSession(session: modes.AuthenticationSession) {
this._sessionIds.push(session.id);
this._sessions.set(session.id, session.accountName);

const existingSessionsForAccount = this._accounts.get(session.accountName);
if (existingSessionsForAccount) {
this._accounts.set(session.accountName, existingSessionsForAccount.concat(session.id));
return;
} else {
this._accounts.set(session.accountName, [session.id]);
}

const menuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
group: '1_accounts',
command: {
Expand All @@ -131,7 +139,8 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.onDidAccept(e => {
const selected = quickPick.selectedItems[0];
if (selected.label === 'Sign Out') {
this.logout(session.id);
const sessionsForAccount = this._accounts.get(session.accountName);
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
}

quickPick.dispose();
Expand All @@ -145,7 +154,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
},
});

this._sessionMenuItems.set(session.id, [menuItem, manageCommand]);
this._sessionMenuItems.set(session.accountName, [menuItem, manageCommand]);
}

async getSessions(): Promise<ReadonlyArray<modes.AuthenticationSession>> {
Expand All @@ -158,22 +167,29 @@ export class MainThreadAuthenticationProvider extends Disposable {
});
}

async updateSessionItems(): Promise<void> {
const currentSessions = await this._proxy.$getSessions(this.id);
const removedSessionIds = this._sessionIds.filter(id => !currentSessions.some(session => session.id === id));
const addedSessions = currentSessions.filter(session => !this._sessionIds.some(id => id === session.id));

removedSessionIds.forEach(id => {
const disposeables = this._sessionMenuItems.get(id);
if (disposeables) {
disposeables.forEach(disposeable => disposeable.dispose());
this._sessionMenuItems.delete(id);
async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise<void> {
const { added, removed } = event;
const session = await this._proxy.$getSessions(this.id);
const addedSessions = session.filter(session => added.some(id => id === session.id));

removed.forEach(sessionId => {
const accountName = this._sessions.get(sessionId);
if (accountName) {
let sessionsForAccount = this._accounts.get(accountName) || [];
const sessionIndex = sessionsForAccount.indexOf(sessionId);
sessionsForAccount.splice(sessionIndex);

if (!sessionsForAccount.length) {
const disposeables = this._sessionMenuItems.get(accountName);
if (disposeables) {
disposeables.forEach(disposeable => disposeable.dispose());
this._sessionMenuItems.delete(accountName);
}
}
}
});

addedSessions.forEach(session => this.registerSession(session));

this._sessionIds = currentSessions.map(session => session.id);
}

login(scopes: string[]): Promise<modes.AuthenticationSession> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { timeout } from 'vs/base/common/async';
import { distinct } from 'vs/base/common/arrays';

const enum AuthStatus {
Initializing = 'Initializing',
Expand Down Expand Up @@ -251,7 +252,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
const quickPick = this.quickInputService.createQuickPick<{ label: string, session: AuthenticationSession }>();
quickPick.title = localize('chooseAccountTitle', "Preferences Sync: Choose Account");
quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for settings sync");
quickPick.items = sessions.map(session => {
const dedupedSessions = distinct(sessions, (session) => session.accountName);
quickPick.items = dedupedSessions.map(session => {
return {
label: session.accountName,
session: session
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class AuthenticationService extends Disposable implements IAuthentication
this._onDidChangeSessions.fire({ providerId: id, event: event });
const provider = this._authenticationProviders.get(id);
if (provider) {
provider.updateSessionItems();
provider.updateSessionItems(event);
}
}

Expand Down

0 comments on commit fc7ac81

Please sign in to comment.