Skip to content
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
2 changes: 2 additions & 0 deletions api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).

## Unreleased

* Add `focusResourceGroup` function to the resources API.

## [3.0.0] - 2025-10-06

* Package is now a combined CJS+ESM package.
Expand Down
21 changes: 14 additions & 7 deletions api/docs/vscode-azureresources-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ export declare interface AzureAuthentication {
/**
* Gets a VS Code authentication session for an Azure subscription.
*
* @param scopes - The scopes for which the authentication is needed. Use AuthenticationWwwAuthenticateRequest for supporting challenge requests.
* Note: use of AuthenticationWwwAuthenticateRequest requires VS Code v1.104
* @param scopeListOrRequest - The scopes for which the authentication is needed. Use AuthenticationWwwAuthenticateRequest for supporting challenge requests.
* Note: use of AuthenticationWwwAuthenticateRequest requires VS Code v1.105.0
*
* @returns A VS Code authentication session or undefined, if none could be obtained.
*/
getSessionWithScopes(scopes: string[] | vscode.AuthenticationWwwAuthenticateRequest): vscode.ProviderResult<vscode.AuthenticationSession>;
getSessionWithScopes(scopeListOrRequest: string[] | vscode.AuthenticationWwwAuthenticateRequest): vscode.ProviderResult<vscode.AuthenticationSession>;
}

export declare interface AzureExtensionApi {
Expand Down Expand Up @@ -174,7 +174,7 @@ export declare interface AzureResource extends ResourceBase {
/**
* A copy of the raw resource.
*/
readonly raw: {};
readonly raw: unknown;
}

/**
Expand Down Expand Up @@ -401,6 +401,13 @@ export declare interface ResourcesApi {
* @param options - Options for revealing the resource. See {@link vscode.TreeView.reveal}
*/
revealWorkspaceResource(id: string, options?: VSCodeRevealOptions): Promise<void>;
/**
* Focus on a resource group in the Focused Resources view.
* This opens the Focused Resources view and filters it to show only resources from the specified resource group.
*
* @param resourceGroupId - The Azure Resource Group ID to focus on.
*/
focusResourceGroup(resourceGroupId: string): Promise<void>;
/**
* Gets a list of node IDs for nodes recently used/interacted with in the Azure tree view.
*
Expand Down Expand Up @@ -428,14 +435,14 @@ export declare interface ViewPropertiesModelAsync {
/**
* Async function to get the raw data associated with the resource to populate the properties file.
*/
getData: () => Promise<{}>;
getData: () => Promise<unknown>;
}

export declare interface ViewPropertiesModelSync {
/**
* Raw data associated with the resource to populate the properties file.
*/
data: {};
data: unknown;
}

export declare type VSCodeRevealOptions = Parameters<vscode.TreeView<unknown>['reveal']>['1'];
Expand Down Expand Up @@ -495,4 +502,4 @@ export declare interface Wrapper {
unwrap<T>(): T;
}

export { };
export { }
25 changes: 18 additions & 7 deletions api/package-lock.json

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

4 changes: 2 additions & 2 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@microsoft/vscode-azureresources-api",
"version": "3.0.0",
"version": "3.1.0",
"description": "Type declarations and client library for the Azure Resources extension API",
"repository": {
"type": "git",
Expand All @@ -23,7 +23,7 @@
"vscode": "^1.105.0"
},
"devDependencies": {
"@types/node": "^16.0.0",
"@types/node": "22.x",
"@types/vscode": "1.105.0"
},
"peerDependencies": {
Expand Down
10 changes: 10 additions & 0 deletions api/src/resources/resourcesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ export interface ResourcesApi {
*/
revealWorkspaceResource(id: string, options?: VSCodeRevealOptions): Promise<void>;

/**
* Focus on a resource group in the Focused Resources view.
* This opens the Focused Resources view and filters it to show only resources from the specified resource group.
*
* @param resourceGroupId - The Azure Resource Group ID to focus on, in the form
* `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}`.
* The promise is rejected with an error if the ID is not in the expected format.
*/
focusResourceGroup(resourceGroupId: string): Promise<void>;

/**
* Gets a list of node IDs for nodes recently used/interacted with in the Azure tree view.
*
Expand Down
10 changes: 1 addition & 9 deletions package-lock.json

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

9 changes: 9 additions & 0 deletions src/api/createAzureResourcesHostApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ export function createAzureResourcesHostApi(
});
},

focusResourceGroup: (resourceGroupId: string) => {
return callWithTelemetryAndErrorHandling('internalFocusResourceGroup', context => {
context.errorHandling.rethrow = true;
context.errorHandling.suppressDisplay = true;
context.errorHandling.suppressReportIssue = true;
return vscode.commands.executeCommand('azureResourceGroups.focusGroup', resourceGroupId);
});
},

getRecentlyUsedAzureNodes: () => {
return getRecentlyUsedAzureNodes();
},
Expand Down
1 change: 1 addition & 0 deletions src/api/createWrappedAzureResourcesExtensionApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function createWrappedAzureResourcesExtensionApi(api: AzureResourcesApiIn
...wrapFunctionsInTelemetry({
revealAzureResource: api.resources.revealAzureResource.bind(api) as typeof api.resources.revealAzureResource,
revealWorkspaceResource: api.resources.revealWorkspaceResource.bind(api) as typeof api.resources.revealWorkspaceResource,
focusResourceGroup: api.resources.focusResourceGroup.bind(api) as typeof api.resources.focusResourceGroup,
}, wrapOptions),
...wrapFunctionsInTelemetrySync({
registerAzureResourceBranchDataProvider: api.resources.registerAzureResourceBranchDataProvider.bind(api) as typeof api.resources.registerAzureResourceBranchDataProvider,
Expand Down
31 changes: 28 additions & 3 deletions src/commands/focus/focusGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,42 @@
*--------------------------------------------------------------------------------------------*/

import { contextValueExperience, IActionContext } from "@microsoft/vscode-azext-utils";
import { AzExtResourceType } from "api/src/AzExtResourceType";
import { AzExtResourceType } from "api/src";
import * as vscode from 'vscode';
import { canFocusContextValue, hasFocusedGroupContextKey } from "../../constants";
import { ext } from "../../extensionVariables";
import { GroupingItem } from "../../tree/azure/grouping/GroupingItem";
import { isLocationGroupingItem } from "../../tree/azure/grouping/LocationGroupingItem";
import { isResourceGroupGroupingItem } from "../../tree/azure/grouping/ResourceGroupGroupingItem";
import { isResourceTypeGroupingItem } from "../../tree/azure/grouping/ResourceTypeGroupingItem";
import { validateResourceGroupId } from "../../utils/azureUtils";

export async function focusGroup(context: IActionContext, item?: GroupingItem): Promise<void> {
item ??= await contextValueExperience<GroupingItem>(context, ext.v2.api.resources.azureResourceTreeDataProvider, {
export async function focusGroup(context: IActionContext, itemOrId?: GroupingItem | string): Promise<void> {
if (typeof itemOrId === 'string') {
// When called with a resource group ID string, validate it and set focus state directly
// This works regardless of the current tree grouping mode
context.errorHandling.rethrow = true;
context.errorHandling.suppressDisplay = true;
context.errorHandling.suppressReportIssue = true;

validateResourceGroupId(itemOrId);

ext.focusedGroup = {
kind: 'resourceGroup',
id: itemOrId.toLowerCase(),
};

context.telemetry.properties.calledWithId = 'true';
context.telemetry.properties.groupKind = 'resourceGroup';

await vscode.commands.executeCommand('setContext', hasFocusedGroupContextKey, true);
ext.actions.refreshFocusTree();
await ext.focusView.reveal(undefined);
return;
}

// When called with a tree item or no arguments, use the tree-based approach
const item = itemOrId ?? await contextValueExperience<GroupingItem>(context, ext.v2.api.resources.azureResourceTreeDataProvider, {
include: canFocusContextValue,
});

Expand Down
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo
},
extensionVariables: {
getOutputChannel: () => ext.outputChannel,
getFocusedGroup: () => ext.focusedGroup,
},
testing: {
setOverrideAzureServiceFactory: (factory) => {
Expand Down
6 changes: 6 additions & 0 deletions src/testApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { AzureSubscriptionProvider } from "@microsoft/vscode-azext-azureauth";
import type { AzExtLocation } from "@microsoft/vscode-azext-azureutils";
import { AzExtTreeDataProvider, IActionContext, IAzExtLogOutputChannel, ISubscriptionActionContext } from "@microsoft/vscode-azext-utils";
import { GroupingKind } from "./extensionVariables";
import { AzureResourcesApiInternal } from "./hostapi.v2.internal";
import { AzureResourcesServiceFactory } from "./services/AzureResourcesService";
import { SubscriptionItem } from "./tree/azure/SubscriptionItem";
Expand Down Expand Up @@ -44,6 +45,11 @@ export interface TestApi {
* Get the output channel
*/
getOutputChannel(): IAzExtLogOutputChannel;

/**
* Get the focused group
*/
getFocusedGroup(): GroupingKind | undefined;
};

/**
Expand Down
7 changes: 7 additions & 0 deletions src/utils/azureUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import { IAzExtMetadata, legacyTypeMap } from '../azureExtensions';
import { localize } from './localize';
import { treeUtils } from './treeUtils';

export function validateResourceGroupId(resourceGroupId: string): void {
const match = resourceGroupId.match(/^\/subscriptions\/[^/]+\/resourceGroups\/[^/]+$/i);
if (!match) {
throw new Error(`Invalid resource group ID format: ${resourceGroupId}. Expected format: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}`);
}
}

export function createGroupConfigFromResource(resource: AppResource, subscriptionId: string | undefined): GroupingConfig {
const id = nonNullProp(resource, 'id');
const unknown = localize('unknown', 'Unknown');
Expand Down
Loading