Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes for tenants view #964

Open
wants to merge 5 commits into
base: meganmott/tenantView
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@
"@azure/arm-resources": "^5.2.0",
"@azure/arm-resources-profile-2020-09-01-hybrid": "^2.1.0",
"@azure/ms-rest-js": "^2.7.0",
"@microsoft/vscode-azext-azureauth": "file:../vscode-azuretools/auth/microsoft-vscode-azext-azureauth-2.5.0.tgz",
"@microsoft/vscode-azext-azureauth": "^3.1.0",
"@microsoft/vscode-azext-azureutils": "^3.1.1",
"@microsoft/vscode-azext-utils": "^2.5.7",
"buffer": "^6.0.3",
Expand Down
12 changes: 3 additions & 9 deletions src/commands/accounts/selectSubscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AzureSubscription } from "@microsoft/vscode-azext-azureauth";
import { IActionContext, IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
import * as vscode from "vscode";
import { ext } from "../../extensionVariables";
import { isTenantFilteredOut } from "../../tree/tenants/registerTenantTree";
import { localize } from "../../utils/localize";
import { settingUtils } from "../../utils/settingUtils";

Expand Down Expand Up @@ -89,15 +90,8 @@ async function setSelectedTenantAndSubscriptionIds(tenantAndSubscriptionIds: str

// This function is also used to filter subscription tree items in AzureResourceTreeDataProvider
export function getTenantFilteredSubscriptions(allSubscriptions: AzureSubscription[]): AzureSubscription[] | undefined {
const tenants = ext.context.globalState.get<string[]>('unselectedTenants');
if (tenants && tenants.length > 0) {
allSubscriptions = allSubscriptions.filter(subscription => !tenants.includes(`${subscription.tenantId}/${subscription.account?.id}`));
if (allSubscriptions.length > 0) {
return allSubscriptions;
}
}

return undefined;
const filteredSubscriptions = allSubscriptions.filter(subscription => !isTenantFilteredOut(subscription.tenantId, subscription.account.id));
return filteredSubscriptions.length > 0 ? filteredSubscriptions : allSubscriptions;
}

export function getDuplicateSubscriptions(subscriptions: AzureSubscription[]): AzureSubscription[] {
Expand Down
6 changes: 3 additions & 3 deletions src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { signInToTenant } from '@microsoft/vscode-azext-azureauth';
import { AzExtTreeItem, IActionContext, isAzExtTreeItem, openUrl, registerCommand, registerErrorHandler, registerReportIssueCommand } from '@microsoft/vscode-azext-utils';
import { commands } from 'vscode';
import { AuthenticationSessionAccountInformation, commands } from 'vscode';
import { uploadFileToCloudShell } from '../cloudConsole/uploadFileToCloudShell';
import { ext } from '../extensionVariables';
import { BranchDataItemWrapper } from '../tree/BranchDataItemWrapper';
Expand Down Expand Up @@ -70,8 +70,8 @@ export function registerCommands(): void {
ext.actions.refreshTenantTree(node);
});

registerCommand('azureTenant.signInToTenant', async (_context, node: TenantTreeItem) => {
await (await ext.subscriptionProviderFactory()).signIn(node.tenantId);
registerCommand('azureTenant.signInToTenant', async (_context, node: TenantTreeItem, account?: AuthenticationSessionAccountInformation) => {
await (await ext.subscriptionProviderFactory()).signIn(node.tenantId, account);
ext.actions.refreshTenantTree(node);
});

Expand Down
15 changes: 15 additions & 0 deletions src/tree/GenericItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ export interface GenericItemOptions {
readonly iconPath?: TreeItemIconPath;
readonly description?: string;
readonly collapsibleState?: vscode.TreeItemCollapsibleState;
readonly checkboxState?: vscode.TreeItemCheckboxState | {
/**
* The {@link TreeItemCheckboxState} of the tree item
*/
readonly state: vscode.TreeItemCheckboxState;
/**
* A tooltip for the checkbox
*/
readonly tooltip?: string;
/**
* Accessibility information used when screen readers interact with this checkbox
*/
readonly accessibilityInformation?: vscode.AccessibilityInformation;
};
}

export class GenericItem implements ResourceGroupsItem {
Expand All @@ -41,6 +55,7 @@ export class GenericItem implements ResourceGroupsItem {
treeItem.description = this.options?.description;
treeItem.contextValue = this.options?.contextValue;
treeItem.iconPath = this.options?.iconPath;
treeItem.checkboxState = this.options?.checkboxState;

return treeItem;
}
Expand Down
24 changes: 7 additions & 17 deletions src/tree/tenants/TenantResourceTreeDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { nonNullProp, nonNullValueAndProp } from '@microsoft/vscode-azext-utils'
import { ResourceModelBase } from 'api/src';
import * as vscode from 'vscode';
import { TenantResourceProviderManager } from '../../api/ResourceProviderManagers';
import { ext } from '../../extensionVariables';
import { BranchDataItemCache } from '../BranchDataItemCache';
import { GenericItem } from '../GenericItem';
import { getAzureSubscriptionProvider, OnGetChildrenBase } from '../OnGetChildrenBase';
import { ResourceGroupsItem } from '../ResourceGroupsItem';
import { ResourceTreeDataProviderBase } from "../ResourceTreeDataProviderBase";
import { TenantResourceBranchDataProviderManager } from "./TenantResourceBranchDataProviderManager";
import { TenantTreeItem } from './TenantTreeItem';
import { isTenantFilteredOut } from './registerTenantTree';

export class TenantResourceTreeDataProvider extends ResourceTreeDataProviderBase {
public subscriptionProvider: AzureSubscriptionProvider | undefined;
Expand Down Expand Up @@ -55,34 +55,24 @@ export class TenantResourceTreeDataProvider extends ResourceTreeDataProviderBase
const tenants = await subscriptionProvider.getTenants(account);
const tenantItems: ResourceGroupsItem[] = [];
for await (const tenant of tenants) {
const isSignedIn = await subscriptionProvider.isSignedIn(nonNullProp(tenant, 'tenantId'));
tenantItems.push(new TenantTreeItem(nonNullProp(tenant, 'displayName'), nonNullProp(tenant, 'tenantId'), nonNullProp(account, 'id'), {
const isSignedIn = await subscriptionProvider.isSignedIn(nonNullProp(tenant, 'tenantId'), account);
tenantItems.push(new TenantTreeItem(nonNullProp(tenant, 'displayName'), nonNullProp(tenant, 'tenantId'), account, {
contextValue: isSignedIn ? 'tenantName' : 'tenantNameNotSignedIn',
checkboxState: (!(isSignedIn) || this.checkUnselectedTenants(nonNullProp(tenant, 'tenantId'))) ?
vscode.TreeItemCheckboxState.Unchecked : vscode.TreeItemCheckboxState.Checked, // Make sure tenants which are not signed in are unchecked
description: tenant.defaultDomain
checkboxState: (!isSignedIn || isTenantFilteredOut(nonNullProp(tenant, 'tenantId'), account.id)) ?
vscode.TreeItemCheckboxState.Unchecked : vscode.TreeItemCheckboxState.Checked,
description: tenant.tenantId
}));
}

children.push(new GenericItem(nonNullValueAndProp(account, 'label'), {
children: tenantItems,
iconPath: new vscode.ThemeIcon('account'),
contextValue: 'accountName',
collapsibleState: vscode.TreeItemCollapsibleState.Expanded
collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
}));
}
}
return children;
}
}

private checkUnselectedTenants(tenantId: string): boolean {
const settings = ext.context.globalState.get<string[]>('unselectedTenants');
if (settings) {
if (settings.includes(tenantId)) {
return true;
}
}
return false;
}
}
4 changes: 2 additions & 2 deletions src/tree/tenants/TenantTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export interface TenantItemOptions extends GenericItemOptions {
}

export class TenantTreeItem implements ResourceGroupsItem {
constructor(public readonly label: string, public tenantId: string, public account: string, private readonly options?: TenantItemOptions) {
constructor(public readonly label: string, public tenantId: string, public readonly account: vscode.AuthenticationSessionAccountInformation, private readonly options?: TenantItemOptions) {
}

readonly id: string = this.tenantId;
readonly accountId: string = this.account
readonly accountId = this.account.id;

getChildren(): vscode.ProviderResult<ResourceGroupsItem[]> {
return this.options?.children;
Expand Down
62 changes: 53 additions & 9 deletions src/tree/tenants/registerTenantTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,64 @@ export function registerTenantTree(context: vscode.ExtensionContext, options: Re
}

async function updateTenantsSetting(_context: IActionContext, tenants: vscode.TreeCheckboxChangeEvent<TenantTreeItem>) {
const unselectedTenants = ext.context.globalState.get<string[]>('unselectedTenants') || [];
const unselectedTenants = getUnselectedTenants();
const unselectedTenantsSet = new Set(unselectedTenants);

for (const item of tenants.items) {
if (item[1] === vscode.TreeItemCheckboxState.Unchecked) {
unselectedTenants.push(`${item[0].id}/${item[0].accountId}`);
} else if (item[1] === vscode.TreeItemCheckboxState.Checked) {
const treeItem = await item[0].getTreeItem();
for (const [tenantTreeItem, state] of tenants.items) {
if (state === vscode.TreeItemCheckboxState.Unchecked) {
unselectedTenantsSet.add(getKeyForTenant(tenantTreeItem.tenantId, tenantTreeItem.account.id));
} else if (state === vscode.TreeItemCheckboxState.Checked) {
const treeItem = await tenantTreeItem.getTreeItem();
if (treeItem?.contextValue === 'tenantNameNotSignedIn') {
await vscode.commands.executeCommand('azureTenant.signInToTenant', item[0]);
await vscode.commands.executeCommand('azureTenant.signInToTenant', tenantTreeItem, tenantTreeItem.account);
ext.actions.refreshTenantTree();
}
unselectedTenants.splice(unselectedTenants.indexOf(item[0].id), 1);
unselectedTenantsSet.delete(getKeyForTenant(tenantTreeItem.tenantId, tenantTreeItem.account.id));
}
}

await ext.context.globalState.update('unselectedTenants', unselectedTenants);
await setUnselectedTenants(Array.from(unselectedTenantsSet));
}

function removeDuplicates(arr: string[]): string[] {
return Array.from(new Set(arr));
}

export async function setUnselectedTenants(tenantIds: string[]): Promise<void> {
printTenants(tenantIds);
await ext.context.globalState.update('unselectedTenants', removeDuplicates(tenantIds));
}

export function getUnselectedTenants(): string[] {
const value = ext.context.globalState.get<string[]>('unselectedTenants');

if (!value || !Array.isArray(value)) {
return [];
}

// remove any duplicates
return removeDuplicates(value);
}

export function isTenantFilteredOut(tenantId: string, accountId: string): boolean {
const settings = ext.context.globalState.get<string[]>('unselectedTenants');
if (settings) {
if (settings.includes(getKeyForTenant(tenantId, accountId))) {
return true;
}
}
return false;
}

export function getKeyForTenant(tenantId: string, accountId: string): string {
return `${tenantId}/${accountId}`;
}

function printTenants(unselectedTenants: string[]): void {
let str = '';
str += 'Unselected tenants:\n';
for (const tenant of unselectedTenants) {
str += `- ${tenant}\n`;
}
ext.outputChannel.appendLine(str);
}