diff --git a/extensions/azurecore/src/azureResource/services/subscriptionFilterService.ts b/extensions/azurecore/src/azureResource/services/subscriptionFilterService.ts index 6c00468db7..c5ad18120e 100644 --- a/extensions/azurecore/src/azureResource/services/subscriptionFilterService.ts +++ b/extensions/azurecore/src/azureResource/services/subscriptionFilterService.ts @@ -50,7 +50,7 @@ export class AzureResourceSubscriptionFilterService implements IAzureResourceSub const filters: string[] = []; for (const accountId in selectedSubscriptionsCache) { - filters.push(...selectedSubscriptionsCache[accountId].map((subcription) => `${accountId}/${subcription.id}/${subcription.name}`)); + filters.push(...selectedSubscriptionsCache[accountId].map((subscription) => `${accountId}/${subscription.id}/${subscription.name}`)); } } diff --git a/extensions/azurecore/src/azureResource/utils.ts b/extensions/azurecore/src/azureResource/utils.ts index 4b8da53e55..0f31689055 100644 --- a/extensions/azurecore/src/azureResource/utils.ts +++ b/extensions/azurecore/src/azureResource/utils.ts @@ -3,17 +3,16 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as azdata from 'azdata'; -import * as nls from 'vscode-nls'; -import { azureResource } from 'azureResource'; -import { GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult } from 'azurecore'; -import { isArray } from 'util'; -import { AzureResourceGroupService } from './providers/resourceGroup/resourceGroupService'; -import { TokenCredentials } from '@azure/ms-rest-js'; -import { AppContext } from '../appContext'; -import { IAzureResourceSubscriptionService } from './interfaces'; -import { AzureResourceServiceNames } from './constants'; import { ResourceGraphClient } from '@azure/arm-resourcegraph'; +import { TokenCredentials } from '@azure/ms-rest-js'; +import * as azdata from 'azdata'; +import { GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult } from 'azurecore'; +import { azureResource } from 'azureResource'; +import * as nls from 'vscode-nls'; +import { AppContext } from '../appContext'; +import { AzureResourceServiceNames } from './constants'; +import { IAzureResourceSubscriptionFilterService, IAzureResourceSubscriptionService } from './interfaces'; +import { AzureResourceGroupService } from './providers/resourceGroup/resourceGroupService'; const localize = nls.loadMessageBundle(); @@ -106,7 +105,7 @@ export function equals(one: any, other: any): boolean { export async function getResourceGroups(appContext: AppContext, account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors: boolean = false): Promise { const result: GetResourceGroupsResult = { resourceGroups: [], errors: [] }; - if (!account?.properties?.tenants || !isArray(account.properties.tenants) || !subscription) { + if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants) || !subscription) { const error = new Error(localize('azure.accounts.getResourceGroups.invalidParamsError', "Invalid account or subscription")); if (!ignoreErrors) { throw error; @@ -146,7 +145,7 @@ export async function runResourceQuery> { const result: ResourceQueryResult = { resources: [], errors: [] }; - if (!account?.properties?.tenants || !isArray(account.properties.tenants)) { + if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) { const error = new Error(localize('azure.accounts.runResourceQuery.errors.invalidAccount', "Invalid account")); if (!ignoreErrors) { throw error; @@ -227,7 +226,7 @@ export async function runResourceQuery { const result: GetSubscriptionsResult = { subscriptions: [], errors: [] }; - if (!account?.properties?.tenants || !isArray(account.properties.tenants)) { + if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) { const error = new Error(localize('azure.accounts.getSubscriptions.invalidParamsError', "Invalid account")); if (!ignoreErrors) { throw error; @@ -258,3 +257,30 @@ export async function getSubscriptions(appContext: AppContext, account?: azdata. })); return result; } + +export async function getSelectedSubscriptions(appContext: AppContext, account?: azdata.Account, ignoreErrors: boolean = false): Promise { + const result: GetSubscriptionsResult = { subscriptions: [], errors: [] }; + if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) { + const error = new Error(localize('azure.accounts.getSelectedSubscriptions.invalidParamsError', "Invalid account")); + if (!ignoreErrors) { + throw error; + } + result.errors.push(error); + return result; + } + + const subscriptionFilterService = appContext.getService(AzureResourceServiceNames.subscriptionFilterService); + try { + result.subscriptions.push(...await subscriptionFilterService.getSelectedSubscriptions(account)); + } catch (err) { + const error = new Error(localize('azure.accounts.getSelectedSubscriptions.queryError', "Error fetching subscriptions for account {0} : {1}", + account.displayInfo.displayName, + err instanceof Error ? err.message : err)); + console.warn(error); + if (!ignoreErrors) { + throw error; + } + result.errors.push(error); + } + return result; +} diff --git a/extensions/azurecore/src/azurecore.d.ts b/extensions/azurecore/src/azurecore.d.ts index bf929bb7d6..9ea32442f2 100644 --- a/extensions/azurecore/src/azurecore.d.ts +++ b/extensions/azurecore/src/azurecore.d.ts @@ -63,7 +63,7 @@ declare module 'azurecore' { } export interface IExtension { - getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean): Thenable; + getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean, selectedOnly?: boolean): Thenable; getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Thenable; /** * Converts a region value (@see AzureRegion) into the localized Display Name diff --git a/extensions/azurecore/src/extension.ts b/extensions/azurecore/src/extension.ts index a5a080d106..6d9a4c438b 100644 --- a/extensions/azurecore/src/extension.ts +++ b/extensions/azurecore/src/extension.ts @@ -147,7 +147,11 @@ export async function activate(context: vscode.ExtensionContext): Promise { return azureResourceUtils.getSubscriptions(appContext, account, ignoreErrors); }, + getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean, selectedOnly: boolean = false): Thenable { + return selectedOnly + ? azureResourceUtils.getSelectedSubscriptions(appContext, account, ignoreErrors) + : azureResourceUtils.getSubscriptions(appContext, account, ignoreErrors); + }, getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Thenable { return azureResourceUtils.getResourceGroups(appContext, account, subscription, ignoreErrors); }, provideResources(): azureResource.IAzureResourceProvider[] { const arcFeaturedEnabled = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('enableArcFeatures'); diff --git a/extensions/machine-learning/src/test/stubs.ts b/extensions/machine-learning/src/test/stubs.ts index cd5b8623b6..c11c09a166 100644 --- a/extensions/machine-learning/src/test/stubs.ts +++ b/extensions/machine-learning/src/test/stubs.ts @@ -11,7 +11,7 @@ export class AzurecoreApiStub implements azurecore.IExtension { runGraphQuery(_account: azdata.Account, _subscriptions: azureResource.AzureResourceSubscription[], _ignoreErrors: boolean, _query: string): Promise> { throw new Error('Method not implemented.'); } - getSubscriptions(_account?: azdata.Account | undefined, _ignoreErrors?: boolean | undefined): Thenable { + getSubscriptions(_account?: azdata.Account | undefined, _ignoreErrors?: boolean | undefined, _selectedOnly?: boolean | undefined): Thenable { throw new Error('Method not implemented.'); } getResourceGroups(_account?: azdata.Account | undefined, _subscription?: azureResource.AzureResourceSubscription | undefined, _ignoreErrors?: boolean | undefined): Thenable { diff --git a/extensions/resource-deployment/src/localizedConstants.ts b/extensions/resource-deployment/src/localizedConstants.ts index 33bf67a1da..659246847e 100644 --- a/extensions/resource-deployment/src/localizedConstants.ts +++ b/extensions/resource-deployment/src/localizedConstants.ts @@ -10,7 +10,8 @@ import { FieldType, OptionsType } from './interfaces'; const localize = nls.loadMessageBundle(); export const account = localize('azure.account', "Azure Account"); -export const subscription = localize('azure.account.subscription', "Subscription"); +export const subscription = localize('azure.account.subscription', "Subscription (selected subset)"); +export const subscriptionDescription = localize('azure.account.subscriptionDescription', "Change the currently selected subscriptions through the 'Select Subscriptions' action on an account listed in the 'Azure' tree view of the 'Connections' viewlet"); export const resourceGroup = localize('azure.account.resourceGroup', "Resource Group"); export const location = localize('azure.account.location', "Azure Location"); export const browse = localize('filePicker.browse', "Browse"); diff --git a/extensions/resource-deployment/src/ui/modelViewUtils.ts b/extensions/resource-deployment/src/ui/modelViewUtils.ts index 415dc9e0b6..542f11bc27 100644 --- a/extensions/resource-deployment/src/ui/modelViewUtils.ts +++ b/extensions/resource-deployment/src/ui/modelViewUtils.ts @@ -1010,6 +1010,7 @@ function createAzureSubscriptionDropdown( subscriptionValueToSubscriptionMap: Map): azdata.DropDownComponent { const label = createLabel(context.view, { text: loc.subscription, + description: loc.subscriptionDescription, required: context.fieldInfo.required, width: context.fieldInfo.labelWidth, cssStyles: context.fieldInfo.labelCSSStyles @@ -1069,7 +1070,7 @@ async function handleSelectedAccountChanged( } try { - const response = await apiService.azurecoreApi.getSubscriptions(selectedAccount, true); + const response = await apiService.azurecoreApi.getSubscriptions(selectedAccount, true, false); if (!response) { return; }