diff --git a/extensions/azurecore/src/azureResource/commands.ts b/extensions/azurecore/src/azureResource/commands.ts index 6301aca5b8..c4cf29578b 100644 --- a/extensions/azurecore/src/azureResource/commands.ts +++ b/extensions/azurecore/src/azureResource/commands.ts @@ -23,7 +23,10 @@ import { AzureResourceGroupService } from './providers/resourceGroup/resourceGro export function registerAzureResourceCommands(appContext: AppContext, tree: AzureResourceTreeProvider): void { // Resource Management commands - appContext.apiWrapper.registerCommand('azure.accounts.getSubscriptions', async (account: azdata.Account) => { + appContext.apiWrapper.registerCommand('azure.accounts.getSubscriptions', async (account?: azdata.Account): Promise => { + if (!account) { + return []; + } const subscriptions = []; try { const subscriptionService = appContext.getService(AzureResourceServiceNames.subscriptionService); @@ -41,7 +44,10 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur return subscriptions; }); - appContext.apiWrapper.registerCommand('azure.accounts.getResourceGroups', async (account: azdata.Account, subscription: azureResource.AzureResourceSubscription) => { + appContext.apiWrapper.registerCommand('azure.accounts.getResourceGroups', async (account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription): Promise => { + if (!account || !subscription) { + return []; + } try { const service = new AzureResourceGroupService(); const resourceGroups: azureResource.AzureResourceResourceGroup[] = []; diff --git a/extensions/resource-deployment/src/ui/modelViewUtils.ts b/extensions/resource-deployment/src/ui/modelViewUtils.ts index 824e7f38c6..7b7899ae5b 100644 --- a/extensions/resource-deployment/src/ui/modelViewUtils.ts +++ b/extensions/resource-deployment/src/ui/modelViewUtils.ts @@ -421,32 +421,28 @@ function processCheckboxField(context: FieldContext): void { context.onNewInputComponentCreated(context.fieldInfo.variableName!, checkbox); } -// Values used for the Azure Account field inputs -let selectedAccount: azdata.Account | undefined; -let subscriptionDropdown: azdata.DropDownComponent; -let resourceGroupDropdown: azdata.DropDownComponent; -const accountValueToAccountMap = new Map(); -const subscriptionValueToSubscriptionMap = new Map(); - /** * An Azure Account field consists of 3 separate dropdown fields - Account, Subscription and Resource Group * @param context The context to use to create the field */ function processAzureAccountField(context: AzureAccountFieldContext): void { - if (subscriptionDropdown) { - throw new Error(localize('onlyOneAzureAccountField', "Only one Azure Account field is supported at this time")); - } + const accountValueToAccountMap = new Map(); + const subscriptionValueToSubscriptionMap = new Map(); const accountDropdown = createAzureAccountDropdown(context); - createAzureSubscriptionDropdown(context, accountDropdown); - createAzureResourceGroupsDropdown(context, subscriptionDropdown); + const subscriptionDropdown = createAzureSubscriptionDropdown(context, accountDropdown, accountValueToAccountMap, subscriptionValueToSubscriptionMap); + const resourceGroupDropdown = createAzureResourceGroupsDropdown(context, accountDropdown, accountValueToAccountMap, subscriptionDropdown, subscriptionValueToSubscriptionMap); + accountDropdown.onValueChanged(selectedItem => { + const selectedAccount = accountValueToAccountMap.get(selectedItem.selected)!; + handleSelectedAccountChanged(selectedAccount, subscriptionDropdown, subscriptionValueToSubscriptionMap, resourceGroupDropdown); + }); azdata.accounts.getAllAccounts().then((accounts: azdata.Account[]) => { - accountDropdown.values = accounts.map(account => { + accountDropdown.values = [localize('localDeploy', "Local Deploy")].concat(accounts.map(account => { const displayName = `${account.displayInfo.displayName} (${account.displayInfo.userId})`; accountValueToAccountMap.set(displayName, account); return displayName; - }); - selectedAccount = accounts.length > 0 ? accounts[0] : undefined; - handleSelectedAccountChanged(); + })); + const selectedAccount = accountDropdown.value ? accountValueToAccountMap.get(accountDropdown.value.toString()) : undefined; + handleSelectedAccountChanged(selectedAccount, subscriptionDropdown, subscriptionValueToSubscriptionMap, resourceGroupDropdown); }, (err: any) => console.log(`Unexpected error fetching accounts: ${err}`)); } @@ -469,14 +465,18 @@ function createAzureAccountDropdown(context: AzureAccountFieldContext): azdata.D return accountDropdown; } -function createAzureSubscriptionDropdown(context: AzureAccountFieldContext, accountDropdown: azdata.DropDownComponent): void { +function createAzureSubscriptionDropdown( + context: AzureAccountFieldContext, + accountDropdown: azdata.DropDownComponent, + accountValueToAccountMap: Map, + subscriptionValueToSubscriptionMap: Map): azdata.DropDownComponent { const label = createLabel(context.view, { text: loc.subscription, required: context.fieldInfo.required, width: context.fieldInfo.labelWidth, fontWeight: context.fieldInfo.labelFontWeight }); - subscriptionDropdown = createDropdown(context.view, { + const subscriptionDropdown = createDropdown(context.view, { width: context.fieldInfo.inputWidth, editable: false, required: context.fieldInfo.required, @@ -486,13 +486,15 @@ function createAzureSubscriptionDropdown(context: AzureAccountFieldContext, acco return subscriptionValueToSubscriptionMap.get(inputValue)?.id || inputValue; }); addLabelInputPairToContainer(context.view, context.components, label, subscriptionDropdown, context.fieldInfo.labelPosition); - accountDropdown.onValueChanged(selectedItem => { - selectedAccount = accountValueToAccountMap.get(selectedItem.selected); - handleSelectedAccountChanged(); - }); + return subscriptionDropdown; } -function handleSelectedAccountChanged(): void { +function handleSelectedAccountChanged( + selectedAccount: azdata.Account | undefined, + subscriptionDropdown: azdata.DropDownComponent, + subscriptionValueToSubscriptionMap: Map, + resourceGroupDropdown: azdata.DropDownComponent +): void { subscriptionValueToSubscriptionMap.clear(); subscriptionDropdown.values = []; vscode.commands.executeCommand('azure.accounts.getSubscriptions', selectedAccount).then(subscriptions => { @@ -502,18 +504,23 @@ function handleSelectedAccountChanged(): void { return displayName; }).sort((a: string, b: string) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase())); const selectedSubscription = subscriptionDropdown.values.length > 0 ? subscriptionValueToSubscriptionMap.get(subscriptionDropdown.values[0]) : undefined; - handleSelectedSubscriptionChanged(selectedSubscription); + handleSelectedSubscriptionChanged(selectedAccount, selectedSubscription, resourceGroupDropdown); }, err => { console.log(`Unexpected error fetching subscriptions for account ${selectedAccount?.displayInfo.displayName} (${selectedAccount?.key.accountId}): ${err}`); }); } -function createAzureResourceGroupsDropdown(context: AzureAccountFieldContext, subscriptionDropdown: azdata.DropDownComponent): void { +function createAzureResourceGroupsDropdown( + context: AzureAccountFieldContext, + accountDropdown: azdata.DropDownComponent, + accountValueToAccountMap: Map, + subscriptionDropdown: azdata.DropDownComponent, + subscriptionValueToSubscriptionMap: Map): azdata.DropDownComponent { const label = createLabel(context.view, { text: loc.resourceGroup, required: context.fieldInfo.required, width: context.fieldInfo.labelWidth, fontWeight: context.fieldInfo.labelFontWeight }); - resourceGroupDropdown = createDropdown(context.view, { + const resourceGroupDropdown = createDropdown(context.view, { width: context.fieldInfo.inputWidth, editable: false, required: context.fieldInfo.required, @@ -522,12 +529,14 @@ function createAzureResourceGroupsDropdown(context: AzureAccountFieldContext, su context.onNewInputComponentCreated(context.fieldInfo.resourceGroupVariableName!, resourceGroupDropdown); addLabelInputPairToContainer(context.view, context.components, label, resourceGroupDropdown, context.fieldInfo.labelPosition); subscriptionDropdown.onValueChanged(selectedItem => { + const selectedAccount = !accountDropdown || !accountDropdown.value ? undefined : accountValueToAccountMap.get(accountDropdown.value.toString()); const selectedSubscription = subscriptionValueToSubscriptionMap.get(selectedItem.selected); - handleSelectedSubscriptionChanged(selectedSubscription); + handleSelectedSubscriptionChanged(selectedAccount, selectedSubscription, resourceGroupDropdown); }); + return resourceGroupDropdown; } -function handleSelectedSubscriptionChanged(selectedSubscription: azureResource.AzureResourceSubscription | undefined): void { +function handleSelectedSubscriptionChanged(selectedAccount: azdata.Account | undefined, selectedSubscription: azureResource.AzureResourceSubscription | undefined, resourceGroupDropdown: azdata.DropDownComponent): void { resourceGroupDropdown.values = []; vscode.commands.executeCommand('azure.accounts.getResourceGroups', selectedAccount, selectedSubscription).then(resourceGroups => { resourceGroupDropdown.values = (resourceGroups).map(resourceGroup => resourceGroup.name).sort((a: string, b: string) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()));