@IStorageService private readonly storageService: IStorageService, @IKeybindingService keybindingService: IKeybindingService, @ICredentialsService private readonly credentialsService: ICredentialsService, <ins> @ILogService private readonly logService: ILogService </ins> ) { super(MenuId.AccountsContext, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); <ins> this.registerListeners(); this.initialize(); } private registerListeners(): void { this._register(this.authenticationService.onDidRegisterAuthenticationProvider(async (e) => { await this.addAccountsFromProvider(e.id); })); this._register(this.authenticationService.onDidUnregisterAuthenticationProvider((e) => { this.groupedAccounts.delete(e.id); this.problematicProviders.delete(e.id); })); this._register(this.authenticationService.onDidChangeSessions(async e => { const promises = []; for (const changed of e.event.changed) { promises.push(this.addOrUpdateAccount(e.providerId, changed.account)); } for (const added of e.event.added) { promises.push(this.addOrUpdateAccount(e.providerId, added.account)); } const result = await Promise.allSettled(promises); for (const r of result) { if (r.status === 'rejected') { this.logService.error(r.reason); } } for (const removed of e.event.removed) { this.removeAccount(e.providerId, removed.account); } })); } // This function exists to ensure that the accounts are added for auth providers that had already been registered // before the menu was created. private async initialize(): Promise<void> { const providerIds = this.authenticationService.getProviderIds(); const results = await Promise.allSettled(providerIds.map(providerId => this.addAccountsFromProvider(providerId))); // Log any errors that occurred while initializing. We try to be best effort here to show the most amount of accounts for (const result of results) { if (result.status === 'rejected') { this.logService.error(result.reason); } } this.initialized = true; </ins> } <ins> //#region overrides </ins> protected override async resolveMainMenuActions(accountsMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> { await super.resolveMainMenuActions(accountsMenu, disposables); <del> const otherCommands = accountsMenu.getActions(); </del> const providers = this.authenticationService.getProviderIds(); <del> const allSessions = providers.map(async providerId => { try { const sessions = await this.authenticationService.getSessions(providerId); const groupedSessions: { [label: string]: AuthenticationSession[] } = {}; sessions.forEach(session => { if (groupedSessions[session.account.label]) { groupedSessions[session.account.label].push(session); } else { groupedSessions[session.account.label] = [session]; } }); </del> <ins> const otherCommands = accountsMenu.getActions(); let menus: IAction[] = []; </ins> <del> return { providerId, sessions: groupedSessions }; } catch { return { providerId }; </del> <ins> for (const providerId of providers) { if (!this.initialized) { const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('loading', "Loading..."), undefined, false)); menus.push(noAccountsAvailableAction); break; } const providerLabel = this.authenticationService.getLabel(providerId); const accounts = this.groupedAccounts.get(providerId); if (!accounts) { if (this.problematicProviders.has(providerId)) { const providerUnavailableAction = disposables.add(new Action('providerUnavailable', localize('authProviderUnavailable', '{0} is currently unavailable', providerLabel), undefined, false)); menus.push(providerUnavailableAction); // try again in the background so that if the failure was intermittent, we can resolve it on the next showing of the menu try { await this.addAccountsFromProvider(providerId); } catch (e) { this.logService.error(e); } } continue; </ins> } <del> }); const result = await Promise.all(allSessions); let menus: IAction[] = []; const authenticationSession = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService); result.forEach(sessionInfo => { const providerDisplayName = this.authenticationService.getLabel(sessionInfo.providerId); if (sessionInfo.sessions) { Object.keys(sessionInfo.sessions).forEach(accountName => { const manageExtensionsAction = disposables.add(new Action(`configureSessions${accountName}`, localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, () => { return this.authenticationService.manageTrustedExtensionsForAccount(sessionInfo.providerId, accountName); })); const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), '', true, () => { return this.authenticationService.removeAccountSessions(sessionInfo.providerId, accountName, sessionInfo.sessions[accountName]); })); </del> <ins> for (const account of accounts) { const manageExtensionsAction = disposables.add(new Action(`configureSessions${account.label}`, localize('manageTrustedExtensions', "Manage Trusted Extensions"), undefined, true, () => { return this.authenticationService.manageTrustedExtensionsForAccount(providerId, account.label); })); </ins> <del> const providerSubMenuActions = [manageExtensionsAction]; </del> <ins> const providerSubMenuActions: Action[] = [manageExtensionsAction]; </ins> <del> const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id)); if (!hasEmbedderAccountSession || authenticationSession?.canSignOut) { providerSubMenuActions.push(signOutAction); } </del> <ins> if (account.canSignOut) { const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), undefined, true, async () => { const allSessions = await this.authenticationService.getSessions(providerId); const sessionsForAccount = allSessions.filter(s => s.account.id === account.id); return await this.authenticationService.removeAccountSessions(providerId, account.label, sessionsForAccount); })); providerSubMenuActions.push(signOutAction); } </ins> <del> const providerSubMenu = new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, providerSubMenuActions); menus.push(providerSubMenu); }); } else { const providerUnavailableAction = disposables.add(new Action('providerUnavailable', localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName))); menus.push(providerUnavailableAction); </del> <ins> const providerSubMenu = new SubmenuAction('activitybar.submenu', `${account.label} (${providerLabel})`, providerSubMenuActions); menus.push(providerSubMenu); </ins> } <del> }); </del> <ins> } </ins> if (providers.length && !menus.length) { const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('noAccounts', "You are not signed in to any accounts"), undefined, false));