Skip to content

Commit fc7ac81

Browse files
author
Rachel Macfarlane
committed
Deduplicate account name entries in account context menu
1 parent 5f0cfc3 commit fc7ac81

3 files changed

Lines changed: 54 additions & 36 deletions

File tree

src/vs/workbench/api/browser/mainThreadAuthentication.ts

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [
3434

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

3940
constructor(
4041
private readonly _proxy: ExtHostAuthenticationShape,
@@ -44,10 +45,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
4445
) {
4546
super();
4647

47-
if (!dependents.length) {
48-
return;
49-
}
50-
5148
this.registerCommandsAndContextMenuItems();
5249
}
5350

@@ -86,29 +83,40 @@ export class MainThreadAuthenticationProvider extends Disposable {
8683
}
8784

8885
private registerCommandsAndContextMenuItems(): void {
89-
this._register(CommandsRegistry.registerCommand({
90-
id: `signIn${this.id}`,
91-
handler: (accessor, args) => {
92-
this.setPermissionsForAccount(accessor.get(IQuickInputService), true);
93-
},
94-
}));
95-
96-
this._register(MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
97-
group: '2_providers',
98-
command: {
86+
if (this.dependents.length) {
87+
this._register(CommandsRegistry.registerCommand({
9988
id: `signIn${this.id}`,
100-
title: nls.localize('addAccount', "Sign in to {0}", this.displayName)
101-
},
102-
order: 3
103-
}));
89+
handler: (accessor, args) => {
90+
this.setPermissionsForAccount(accessor.get(IQuickInputService), true);
91+
},
92+
}));
93+
94+
this._register(MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
95+
group: '2_providers',
96+
command: {
97+
id: `signIn${this.id}`,
98+
title: nls.localize('addAccount', "Sign in to {0}", this.displayName)
99+
},
100+
order: 3
101+
}));
102+
}
104103

105104
this._proxy.$getSessions(this.id).then(sessions => {
106105
sessions.forEach(session => this.registerSession(session));
107106
});
108107
}
109108

110109
private registerSession(session: modes.AuthenticationSession) {
111-
this._sessionIds.push(session.id);
110+
this._sessions.set(session.id, session.accountName);
111+
112+
const existingSessionsForAccount = this._accounts.get(session.accountName);
113+
if (existingSessionsForAccount) {
114+
this._accounts.set(session.accountName, existingSessionsForAccount.concat(session.id));
115+
return;
116+
} else {
117+
this._accounts.set(session.accountName, [session.id]);
118+
}
119+
112120
const menuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
113121
group: '1_accounts',
114122
command: {
@@ -131,7 +139,8 @@ export class MainThreadAuthenticationProvider extends Disposable {
131139
quickPick.onDidAccept(e => {
132140
const selected = quickPick.selectedItems[0];
133141
if (selected.label === 'Sign Out') {
134-
this.logout(session.id);
142+
const sessionsForAccount = this._accounts.get(session.accountName);
143+
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
135144
}
136145

137146
quickPick.dispose();
@@ -145,7 +154,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
145154
},
146155
});
147156

148-
this._sessionMenuItems.set(session.id, [menuItem, manageCommand]);
157+
this._sessionMenuItems.set(session.accountName, [menuItem, manageCommand]);
149158
}
150159

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

161-
async updateSessionItems(): Promise<void> {
162-
const currentSessions = await this._proxy.$getSessions(this.id);
163-
const removedSessionIds = this._sessionIds.filter(id => !currentSessions.some(session => session.id === id));
164-
const addedSessions = currentSessions.filter(session => !this._sessionIds.some(id => id === session.id));
165-
166-
removedSessionIds.forEach(id => {
167-
const disposeables = this._sessionMenuItems.get(id);
168-
if (disposeables) {
169-
disposeables.forEach(disposeable => disposeable.dispose());
170-
this._sessionMenuItems.delete(id);
170+
async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise<void> {
171+
const { added, removed } = event;
172+
const session = await this._proxy.$getSessions(this.id);
173+
const addedSessions = session.filter(session => added.some(id => id === session.id));
174+
175+
removed.forEach(sessionId => {
176+
const accountName = this._sessions.get(sessionId);
177+
if (accountName) {
178+
let sessionsForAccount = this._accounts.get(accountName) || [];
179+
const sessionIndex = sessionsForAccount.indexOf(sessionId);
180+
sessionsForAccount.splice(sessionIndex);
181+
182+
if (!sessionsForAccount.length) {
183+
const disposeables = this._sessionMenuItems.get(accountName);
184+
if (disposeables) {
185+
disposeables.forEach(disposeable => disposeable.dispose());
186+
this._sessionMenuItems.delete(accountName);
187+
}
188+
}
171189
}
172190
});
173191

174192
addedSessions.forEach(session => this.registerSession(session));
175-
176-
this._sessionIds = currentSessions.map(session => session.id);
177193
}
178194

179195
login(scopes: string[]): Promise<modes.AuthenticationSession> {

src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
5353
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
5454
import { IOpenerService } from 'vs/platform/opener/common/opener';
5555
import { timeout } from 'vs/base/common/async';
56+
import { distinct } from 'vs/base/common/arrays';
5657

5758
const enum AuthStatus {
5859
Initializing = 'Initializing',
@@ -251,7 +252,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
251252
const quickPick = this.quickInputService.createQuickPick<{ label: string, session: AuthenticationSession }>();
252253
quickPick.title = localize('chooseAccountTitle', "Preferences Sync: Choose Account");
253254
quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for settings sync");
254-
quickPick.items = sessions.map(session => {
255+
const dedupedSessions = distinct(sessions, (session) => session.accountName);
256+
quickPick.items = dedupedSessions.map(session => {
255257
return {
256258
label: session.accountName,
257259
session: session

src/vs/workbench/services/authentication/browser/authenticationService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class AuthenticationService extends Disposable implements IAuthentication
8888
this._onDidChangeSessions.fire({ providerId: id, event: event });
8989
const provider = this._authenticationProviders.get(id);
9090
if (provider) {
91-
provider.updateSessionItems();
91+
provider.updateSessionItems(event);
9292
}
9393
}
9494

0 commit comments

Comments
 (0)