diff --git a/package-lock.json b/package-lock.json index 00125520..db19d990 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,8 @@ "@azure/arm-resources-profile-2020-09-01-hybrid": "^2.1.0", "@azure/ms-rest-js": "^2.7.0", "@microsoft/vscode-azext-azureauth": "^4.0.3", - "@microsoft/vscode-azext-azureutils": "^3.1.4", - "@microsoft/vscode-azext-utils": "^2.6.3", + "@microsoft/vscode-azext-azureutils": "^3.2.0", + "@microsoft/vscode-azext-utils": "^3.0.1", "buffer": "^6.0.3", "form-data": "^4.0.1", "jsonc-parser": "^2.2.1", @@ -1047,9 +1047,9 @@ } }, "node_modules/@microsoft/vscode-azext-azureutils": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-3.1.4.tgz", - "integrity": "sha512-hExl+AL4lpBZ++ejSyuvpxLurGcRgIQVAC8UfWLZnPWqdfUrW9sAqpjrZBjOSpQ72Jr/E+3GnB2lVW7U1T5J2w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-3.2.0.tgz", + "integrity": "sha512-GiEMWjtzAo3Lrg1t02rPQa/OEDAj35PguFQEk3N5QoBubezK38oL5QNJDe2IxAvYniZwNU+XfjHxdFZtI2+PUA==", "dependencies": { "@azure/arm-authorization": "^9.0.0", "@azure/arm-authorization-profile-2020-09-01-hybrid": "^2.1.0", @@ -1062,7 +1062,7 @@ "@azure/core-client": "^1.6.0", "@azure/core-rest-pipeline": "^1.9.0", "@azure/logger": "^1.0.4", - "@microsoft/vscode-azext-utils": "^2.5.14", + "@microsoft/vscode-azext-utils": "^3.0.0", "semver": "^7.3.7", "uuid": "^9.0.0" }, @@ -1172,10 +1172,9 @@ } }, "node_modules/@microsoft/vscode-azext-utils": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-2.6.3.tgz", - "integrity": "sha512-eogbgZH1KQkGWstl9qb1Tq4DQH+JJCHLHZelIbnzIKE8JKxr8Et/byn3OuL5nL1qeITQQn3+AYVsbj2hbljM7w==", - "license": "MIT", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-3.0.1.tgz", + "integrity": "sha512-eO0tueSQqKn8GOUzFdNvNGF9aSjnQwS2xUftBv4BH3m6s18sAtViBgwVH/+k7aAjUBhqlkSwZNJOzf4A18L1/A==", "dependencies": { "@microsoft/vscode-azureresources-api": "^2.3.1", "@vscode/extension-telemetry": "^0.9.6", @@ -11010,9 +11009,9 @@ } }, "@microsoft/vscode-azext-azureutils": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-3.1.4.tgz", - "integrity": "sha512-hExl+AL4lpBZ++ejSyuvpxLurGcRgIQVAC8UfWLZnPWqdfUrW9sAqpjrZBjOSpQ72Jr/E+3GnB2lVW7U1T5J2w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-3.2.0.tgz", + "integrity": "sha512-GiEMWjtzAo3Lrg1t02rPQa/OEDAj35PguFQEk3N5QoBubezK38oL5QNJDe2IxAvYniZwNU+XfjHxdFZtI2+PUA==", "requires": { "@azure/arm-authorization": "^9.0.0", "@azure/arm-authorization-profile-2020-09-01-hybrid": "^2.1.0", @@ -11025,7 +11024,7 @@ "@azure/core-client": "^1.6.0", "@azure/core-rest-pipeline": "^1.9.0", "@azure/logger": "^1.0.4", - "@microsoft/vscode-azext-utils": "^2.5.14", + "@microsoft/vscode-azext-utils": "^3.0.0", "semver": "^7.3.7", "uuid": "^9.0.0" } @@ -11111,9 +11110,9 @@ } }, "@microsoft/vscode-azext-utils": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-2.6.3.tgz", - "integrity": "sha512-eogbgZH1KQkGWstl9qb1Tq4DQH+JJCHLHZelIbnzIKE8JKxr8Et/byn3OuL5nL1qeITQQn3+AYVsbj2hbljM7w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-3.0.1.tgz", + "integrity": "sha512-eO0tueSQqKn8GOUzFdNvNGF9aSjnQwS2xUftBv4BH3m6s18sAtViBgwVH/+k7aAjUBhqlkSwZNJOzf4A18L1/A==", "requires": { "@microsoft/vscode-azureresources-api": "^2.3.1", "@vscode/extension-telemetry": "^0.9.6", diff --git a/package.json b/package.json index 88f7c5d5..320a445a 100644 --- a/package.json +++ b/package.json @@ -914,8 +914,8 @@ "@azure/arm-resources-profile-2020-09-01-hybrid": "^2.1.0", "@azure/ms-rest-js": "^2.7.0", "@microsoft/vscode-azext-azureauth": "^4.0.3", - "@microsoft/vscode-azext-azureutils": "^3.1.4", - "@microsoft/vscode-azext-utils": "^2.6.3", + "@microsoft/vscode-azext-azureutils": "^3.2.0", + "@microsoft/vscode-azext-utils": "^3.0.1", "buffer": "^6.0.3", "form-data": "^4.0.1", "jsonc-parser": "^2.2.1", diff --git a/src/activityLog/ActivityLogsTreeItem.ts b/src/activityLog/ActivityLogsTreeItem.ts deleted file mode 100644 index cdfb1326..00000000 --- a/src/activityLog/ActivityLogsTreeItem.ts +++ /dev/null @@ -1,61 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { AzExtParentTreeItem, AzExtTreeItem, callWithTelemetryAndErrorHandling, IActionContext } from '@microsoft/vscode-azext-utils'; -import { Activity } from '@microsoft/vscode-azext-utils/hostapi'; -import { commands, Disposable } from 'vscode'; -import { localize } from '../utils/localize'; -import { settingUtils } from '../utils/settingUtils'; -import { ActivityStatus, ActivityTreeItem } from './ActivityTreeItem'; - -export class ActivityLogTreeItem extends AzExtParentTreeItem implements Disposable { - public label: string = localize('activityLog', 'Activity Log'); - public contextValue: string = 'azureActivityLog'; - - private activityTreeItems: Record<string, ActivityTreeItem> = {}; - - public constructor() { - super(undefined); - } - - public dispose(): void { - Object.values(this.activityTreeItems).forEach((activity: ActivityTreeItem) => { - activity.dispose(); - }); - } - - public async addActivity(activity: Activity): Promise<void> { - await callWithTelemetryAndErrorHandling('registerActivity', async (context: IActionContext) => { - this.activityTreeItems[activity.id] = new ActivityTreeItem(this, activity); - if ((await settingUtils.getWorkspaceSetting('autoOpenActivityPanel'))) { - await commands.executeCommand('azureActivityLog.focus'); - } - await this.refresh(context); - }); - } - - public async clearActivities(context: IActionContext): Promise<void> { - Object.entries(this.activityTreeItems).forEach(([id, activity]: [string, ActivityTreeItem]) => { - if (activity.status === ActivityStatus.Done) { - activity.dispose(); - delete this.activityTreeItems[id]; - } - }); - await this.refresh(context); - } - - public async loadMoreChildrenImpl(_clearCache: boolean, _context: IActionContext): Promise<AzExtTreeItem[]> { - // no status means activity hasn't started yet - return Object.values(this.activityTreeItems).filter((activity) => !!activity.status); - } - - public compareChildrenImpl(item1: ActivityTreeItem, item2: ActivityTreeItem): number { - return item1.startedAtMs - item2.startedAtMs; - } - - public hasMoreChildrenImpl(): boolean { - return false; - } -} diff --git a/src/api/ResourceProviderManagers.ts b/src/api/ResourceProviderManagers.ts index c1f9efba..12cc9d18 100644 --- a/src/api/ResourceProviderManagers.ts +++ b/src/api/ResourceProviderManagers.ts @@ -91,3 +91,6 @@ export class WorkspaceResourceProviderManager extends ResourceProviderManager<vo export class TenantResourceProviderManager extends ResourceProviderManager<void, TenantResource, TenantResourceProvider> { } + +export class ActivityLogResourceProviderManager extends ResourceProviderManager<void, ResourceBase, ResourceProvider<void, ResourceBase>> { +} diff --git a/src/api/compatibility/pickAppResource.ts b/src/api/compatibility/pickAppResource.ts index 131d2175..eef6c396 100644 --- a/src/api/compatibility/pickAppResource.ts +++ b/src/api/compatibility/pickAppResource.ts @@ -5,6 +5,7 @@ import { AzExtTreeItem, ContextValueFilter, ITreeItemPickerContext, PickTreeItemWithCompatibility } from "@microsoft/vscode-azext-utils"; import { PickAppResourceOptions } from "@microsoft/vscode-azext-utils/hostapi"; +import { TelemetryTrustedValue } from "vscode"; import { AzExtResourceType, getAzExtResourceType } from "../../../api/src/index"; import { ext } from "../../extensionVariables"; @@ -18,7 +19,7 @@ export function createCompatibilityPickAppResource() { childItemFilter: convertExpectedChildContextValueToContextValueFilter(options?.expectedChildContextValue) }); - context.telemetry.properties.resourceId = result.id; + context.telemetry.properties.resourceId = result.id ? new TelemetryTrustedValue(result.id) : undefined; try { // AzExtTreeItems throw when subscription is undefined. It's unlikely to happen here, but better safe than sorry. diff --git a/src/commands/activities/clearActivities.ts b/src/commands/activities/clearActivities.ts index 71a118a0..3a37d2ef 100644 --- a/src/commands/activities/clearActivities.ts +++ b/src/commands/activities/clearActivities.ts @@ -7,5 +7,5 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; import { ext } from "../../extensionVariables"; export async function clearActivities(context: IActionContext): Promise<void> { - await ext.activityLogTreeItem.clearActivities(context); + await ext.activityLogTree.clearActivities(context); } diff --git a/src/activityLog/registerActivity.ts b/src/commands/activities/registerActivity.ts similarity index 82% rename from src/activityLog/registerActivity.ts rename to src/commands/activities/registerActivity.ts index 5d5dc682..7825bbdf 100644 --- a/src/activityLog/registerActivity.ts +++ b/src/commands/activities/registerActivity.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Activity } from "@microsoft/vscode-azext-utils/hostapi"; -import { ext } from "../extensionVariables"; +import { ext } from "../../extensionVariables"; export async function registerActivity(activity: Activity): Promise<void> { - await ext.activityLogTreeItem.addActivity(activity); + await ext.activityLogTree.addActivity(activity); } diff --git a/src/commands/activities/registerActivityLogTree.ts b/src/commands/activities/registerActivityLogTree.ts new file mode 100644 index 00000000..9eaf6be9 --- /dev/null +++ b/src/commands/activities/registerActivityLogTree.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.md in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +import { AzExtTreeItem } from "@microsoft/vscode-azext-utils"; +import { Event, ExtensionContext, TreeView } from "vscode"; +import { ActivityLogResourceProviderManager } from "../../api/ResourceProviderManagers"; +import { ext } from "../../extensionVariables"; +import { ActivityLogTreeDataProvider } from "../../tree/activityLog/ActivityLogBranchDataProvider"; +import { ActivityLogResourceBranchDataProviderManager } from "../../tree/activityLog/ActivityLogBranchDataProviderManager"; +import { BranchDataItemCache } from "../../tree/BranchDataItemCache"; +import { createTreeView } from "../../tree/createTreeView"; +import { TreeDataItem } from "../../tree/ResourceGroupsItem"; +import { wrapTreeForVSCode } from "../../tree/wrapTreeForVSCode"; +import { localize } from "../../utils/localize"; + +interface RegisterActivityLogTreeOptions { + activityLogResourceBranchDataProviderManager: ActivityLogResourceBranchDataProviderManager, + activityLogResourceProviderManager: ActivityLogResourceProviderManager, + refreshEvent: Event<void | TreeDataItem | TreeDataItem[] | null | undefined>, +} + +export function registerActivityLogTree(context: ExtensionContext, options: RegisterActivityLogTreeOptions): ActivityLogTreeDataProvider { + const { activityLogResourceBranchDataProviderManager, activityLogResourceProviderManager, refreshEvent } = options; + + const branchItemCache = new BranchDataItemCache(); + const activityLogTreeDataProvider = + new ActivityLogTreeDataProvider(activityLogResourceBranchDataProviderManager, refreshEvent, activityLogResourceProviderManager, branchItemCache); + context.subscriptions.push(activityLogTreeDataProvider); + + const treeView = createTreeView('azureActivityLog', { + canSelectMany: true, + showCollapseAll: true, + itemCache: branchItemCache, + title: localize('activityLog', 'Activity Log'), + treeDataProvider: wrapTreeForVSCode(activityLogTreeDataProvider, branchItemCache), + findItemById: activityLogTreeDataProvider.findItemById.bind(activityLogTreeDataProvider) as typeof activityLogTreeDataProvider.findItemById, + }); + context.subscriptions.push(treeView); + ext.activityLogTreeView = treeView as unknown as TreeView<AzExtTreeItem>; + + return activityLogTreeDataProvider; +} diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 0b4203fd..f486ae2f 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -74,6 +74,10 @@ export function registerCommands(): void { ext.actions.refreshTenantTree(node); }); + registerCommand('azureActivityLogView.refresh', async (_context, node?: ResourceGroupsItem) => { + ext.actions.refreshActivityLogTree(node); + }); + registerCommand('azureTenantsView.signInToTenant', async (_context, node: TenantTreeItem) => { await (await ext.subscriptionProviderFactory()).signIn(node.tenantId, node.account); ext.actions.refreshTenantTree(node); diff --git a/src/commands/revealResource.ts b/src/commands/revealResource.ts index af179c4d..77809dac 100644 --- a/src/commands/revealResource.ts +++ b/src/commands/revealResource.ts @@ -7,14 +7,14 @@ import { ParsedAzureResourceId } from '@microsoft/vscode-azext-azureutils'; import { AzExtTreeItem, IActionContext, maskUserInfo, parseError } from '@microsoft/vscode-azext-utils'; import { VSCodeRevealOptions } from '../../api/src/index'; import { ext } from '../extensionVariables'; -import { ResourceGroupsItem } from '../tree/ResourceGroupsItem'; +import { TreeDataItem } from '../tree/ResourceGroupsItem'; import { ResourceTreeDataProviderBase } from '../tree/ResourceTreeDataProviderBase'; export async function revealResource(context: IActionContext, resourceId: string, options?: VSCodeRevealOptions): Promise<void> { setTelemetryPropertiesForId(context, resourceId); try { - const item: ResourceGroupsItem | undefined = await (ext.v2.api.resources.azureResourceTreeDataProvider as ResourceTreeDataProviderBase).findItemById(resourceId); + const item: TreeDataItem | undefined = await (ext.v2.api.resources.azureResourceTreeDataProvider as ResourceTreeDataProviderBase).findItemById(resourceId); if (item) { await ext.appResourceTreeView.reveal(item as unknown as AzExtTreeItem, options ?? { expand: false, focus: true, select: true }); } diff --git a/src/extension.ts b/src/extension.ts index c6092a49..50b29c6f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -11,11 +11,9 @@ import { AzureSubscription } from 'api/src'; import { GetApiOptions, apiUtils } from 'api/src/utils/apiUtils'; import * as vscode from 'vscode'; import { AzExtResourceType } from '../api/src/AzExtResourceType'; -import { ActivityLogTreeItem } from './activityLog/ActivityLogsTreeItem'; -import { registerActivity } from './activityLog/registerActivity'; import { DefaultAzureResourceProvider } from './api/DefaultAzureResourceProvider'; import { ResourceGroupsExtensionManager } from './api/ResourceGroupsExtensionManager'; -import { AzureResourceProviderManager, TenantResourceProviderManager, WorkspaceResourceProviderManager } from './api/ResourceProviderManagers'; +import { ActivityLogResourceProviderManager, AzureResourceProviderManager, TenantResourceProviderManager, WorkspaceResourceProviderManager } from './api/ResourceProviderManagers'; import { InternalAzureResourceGroupsExtensionApi } from './api/compatibility/AzureResourceGroupsExtensionApi'; import { CompatibleAzExtTreeDataProvider } from './api/compatibility/CompatibleAzExtTreeDataProvider'; import { createCompatibilityPickAppResource } from './api/compatibility/pickAppResource'; @@ -25,6 +23,8 @@ import { createAzureResourcesHostApi } from './api/createAzureResourcesHostApi'; import { createWrappedAzureResourcesExtensionApi } from './api/createWrappedAzureResourcesExtensionApi'; import { registerChatStandInParticipantIfNeeded } from './chat/chatStandIn'; import { createCloudConsole } from './cloudConsole/cloudConsole'; +import { registerActivity } from './commands/activities/registerActivity'; +import { registerActivityLogTree } from './commands/activities/registerActivityLogTree'; import { registerCommands } from './commands/registerCommands'; import { TagFileSystem } from './commands/tags/TagFileSystem'; import { registerTagDiagnostics } from './commands/tags/registerTagDiagnostics'; @@ -35,7 +35,9 @@ import { survey } from './nps'; import { getSubscriptionProviderFactory } from './services/getSubscriptionProviderFactory'; import { BranchDataItemCache } from './tree/BranchDataItemCache'; import { HelpTreeItem } from './tree/HelpTreeItem'; -import { ResourceGroupsItem } from './tree/ResourceGroupsItem'; +import { TreeDataItem } from './tree/ResourceGroupsItem'; +import { ActivityLogResourceBranchDataProviderManager } from './tree/activityLog/ActivityLogBranchDataProviderManager'; +import { ActivityLogDefaultBranchDataProvider } from './tree/activityLog/ActivityLogDefaultBranchDataProvider'; import { AzureResourceBranchDataProviderManager } from './tree/azure/AzureResourceBranchDataProviderManager'; import { DefaultAzureResourceBranchDataProvider } from './tree/azure/DefaultAzureResourceBranchDataProvider'; import { registerAzureTree } from './tree/azure/registerAzureTree'; @@ -61,19 +63,22 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo registerUIExtensionVariables(ext); registerAzureUtilsExtensionVariables(ext); - const refreshAzureTreeEmitter = new vscode.EventEmitter<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>(); + const refreshAzureTreeEmitter = new vscode.EventEmitter<void | TreeDataItem | TreeDataItem[] | null | undefined>(); context.subscriptions.push(refreshAzureTreeEmitter); - const refreshFocusTreeEmitter = new vscode.EventEmitter<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>(); + const refreshFocusTreeEmitter = new vscode.EventEmitter<void | TreeDataItem | TreeDataItem[] | null | undefined>(); context.subscriptions.push(refreshFocusTreeEmitter); - const refreshWorkspaceTreeEmitter = new vscode.EventEmitter<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>(); + const refreshWorkspaceTreeEmitter = new vscode.EventEmitter<void | TreeDataItem | TreeDataItem[] | null | undefined>(); context.subscriptions.push(refreshWorkspaceTreeEmitter); - const refreshTenantTreeEmitter = new vscode.EventEmitter<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>(); + const refreshTenantTreeEmitter = new vscode.EventEmitter<void | TreeDataItem | TreeDataItem[] | null | undefined>(); context.subscriptions.push(refreshTenantTreeEmitter); + const refreshActivityLogTreeEmitter = new vscode.EventEmitter<void | TreeDataItem | TreeDataItem[] | null | undefined>(); + context.subscriptions.push(refreshActivityLogTreeEmitter); ext.actions.refreshWorkspaceTree = (data) => refreshWorkspaceTreeEmitter.fire(data); ext.actions.refreshAzureTree = (data) => refreshAzureTreeEmitter.fire(data); ext.actions.refreshFocusTree = (data) => refreshFocusTreeEmitter.fire(data); ext.actions.refreshTenantTree = (data) => refreshTenantTreeEmitter.fire(data); + ext.actions.refreshActivityLogTree = (data) => refreshActivityLogTreeEmitter.fire(data); await callWithTelemetryAndErrorHandling('azureResourceGroups.activate', async (activateContext: IActionContext) => { activateContext.telemetry.properties.isActivationEvent = 'true'; @@ -92,10 +97,6 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo ext.helpTree = new AzExtTreeDataProvider(helpTreeItem, 'ms-azuretools.loadMore'); context.subscriptions.push(vscode.window.createTreeView('ms-azuretools.helpAndFeedback', { treeDataProvider: ext.helpTree })); - context.subscriptions.push(ext.activityLogTreeItem = new ActivityLogTreeItem()); - ext.activityLogTree = new AzExtTreeDataProvider(ext.activityLogTreeItem, 'azureActivityLog.loadMore'); - context.subscriptions.push(vscode.window.createTreeView('azureActivityLog', { treeDataProvider: ext.activityLogTree })); - context.subscriptions.push(vscode.window.registerTerminalProfileProvider('azureResourceGroups.cloudShellBash', { provideTerminalProfile: async (token: vscode.CancellationToken) => { return createCloudConsole(await ext.subscriptionProviderFactory(), 'Linux', token).terminalProfile; @@ -129,6 +130,8 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo new WorkspaceDefaultBranchDataProvider(), type => void extensionManager.activateWorkspaceResourceBranchDataProvider(type)); const workspaceResourceProviderManager = new WorkspaceResourceProviderManager(() => extensionManager.activateWorkspaceResourceProviders()); + const activityLogResourceBranchDataProviderManager = new ActivityLogResourceBranchDataProviderManager(new ActivityLogDefaultBranchDataProvider()); + const activityLogResourceProviderManager = new ActivityLogResourceProviderManager(async () => { return undefined }); const tenantResourceBranchDataProviderManager = new TenantResourceBranchDataProviderManager( new TenantDefaultBranchDataProvider()); @@ -161,7 +164,13 @@ export async function activate(context: vscode.ExtensionContext, perfStats: { lo tenantResourceBranchDataProviderManager, refreshEvent: refreshTenantTreeEmitter.event, itemCache: tenantResourcesBranchDataItemCache - }) + }); + + ext.activityLogTree = registerActivityLogTree(context, { + activityLogResourceProviderManager, + activityLogResourceBranchDataProviderManager, + refreshEvent: refreshActivityLogTreeEmitter.event + }); const v2ApiFactory: AzureExtensionApiFactory<AzureResourcesApiInternal> = { apiVersion: '2.0.0', diff --git a/src/extensionVariables.ts b/src/extensionVariables.ts index b5cef384..e1ef7ddd 100644 --- a/src/extensionVariables.ts +++ b/src/extensionVariables.ts @@ -7,20 +7,21 @@ import { AzureSubscriptionProvider } from "@microsoft/vscode-azext-azureauth"; import { AzExtTreeDataProvider, IAzExtLogOutputChannel, IExperimentationServiceAdapter } from "@microsoft/vscode-azext-utils"; import { AzExtResourceType } from "api/src/AzExtResourceType"; import { DiagnosticCollection, Disposable, ExtensionContext, TreeView } from "vscode"; -import { ActivityLogTreeItem } from "./activityLog/ActivityLogsTreeItem"; import { TagFileSystem } from "./commands/tags/TagFileSystem"; import { AzureResourcesApiInternal } from "./hostapi.v2.internal"; import { ManagedIdentityBranchDataProvider } from "./managedIdentity/ManagedIdentityBranchDataProvider"; import { AzureResourcesServiceFactory } from "./services/AzureResourcesService"; -import { ResourceGroupsItem } from "./tree/ResourceGroupsItem"; +import { TreeDataItem } from "./tree/ResourceGroupsItem"; import { TreeItemStateStore } from "./tree/TreeItemState"; +import { ActivityLogTreeDataProvider } from "./tree/activityLog/ActivityLogBranchDataProvider"; import { FocusViewTreeDataProvider } from "./tree/azure/FocusViewTreeDataProvider"; export namespace extActions { - export let refreshWorkspaceTree: (data?: ResourceGroupsItem | ResourceGroupsItem[] | null | undefined | void) => void; - export let refreshAzureTree: (data?: ResourceGroupsItem | ResourceGroupsItem[] | null | undefined | void) => void; - export let refreshFocusTree: (data?: ResourceGroupsItem | ResourceGroupsItem[] | null | undefined | void) => void; - export let refreshTenantTree: (data?: ResourceGroupsItem | ResourceGroupsItem[] | null | undefined | void) => void; + export let refreshWorkspaceTree: (data?: TreeDataItem | TreeDataItem[] | null | undefined | void) => void; + export let refreshAzureTree: (data?: TreeDataItem | TreeDataItem[] | null | undefined | void) => void; + export let refreshFocusTree: (data?: TreeDataItem | TreeDataItem[] | null | undefined | void) => void; + export let refreshTenantTree: (data?: TreeDataItem | TreeDataItem[] | null | undefined | void) => void; + export let refreshActivityLogTree: (data?: TreeDataItem | TreeDataItem[] | null | undefined | void) => void; } /** @@ -35,8 +36,8 @@ export namespace ext { export let workspaceTree: AzExtTreeDataProvider; export let workspaceTreeView: TreeView<unknown>; export let tenantTreeView: TreeView<unknown> - export let activityLogTree: AzExtTreeDataProvider; - export let activityLogTreeItem: ActivityLogTreeItem; + export let activityLogTree: ActivityLogTreeDataProvider; + export let activityLogTreeView: TreeView<unknown>; export let helpTree: AzExtTreeDataProvider; export let outputChannel: IAzExtLogOutputChannel; export let ignoreBundle: boolean | undefined; diff --git a/src/managedIdentity/ManagedIdentityBranchDataProvider.ts b/src/managedIdentity/ManagedIdentityBranchDataProvider.ts index 9cb6af95..3a7c5546 100644 --- a/src/managedIdentity/ManagedIdentityBranchDataProvider.ts +++ b/src/managedIdentity/ManagedIdentityBranchDataProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { callWithTelemetryAndErrorHandling, type IActionContext } from '@microsoft/vscode-azext-utils'; +import { callWithTelemetryAndErrorHandling, TreeElementBase, type IActionContext } from '@microsoft/vscode-azext-utils'; import { AzureResource, AzureResourceModel, BranchDataProvider } from '@microsoft/vscode-azureresources-api'; import * as vscode from 'vscode'; import { localize } from 'vscode-nls'; @@ -11,7 +11,7 @@ import { ext } from '../extensionVariables'; import { ResourceGroupsItem } from '../tree/ResourceGroupsItem'; import { ManagedIdentityItem } from './ManagedIdentityItem'; export class ManagedIdentityBranchDataProvider extends vscode.Disposable implements BranchDataProvider<AzureResource, AzureResourceModel> { - private readonly onDidChangeTreeDataEmitter = new vscode.EventEmitter<ResourceGroupsItem | undefined>(); + private readonly onDidChangeTreeDataEmitter = new vscode.EventEmitter<TreeElementBase | undefined>(); constructor() { super( @@ -20,11 +20,11 @@ export class ManagedIdentityBranchDataProvider extends vscode.Disposable impleme }); } - get onDidChangeTreeData(): vscode.Event<ResourceGroupsItem | undefined> { + get onDidChangeTreeData(): vscode.Event<TreeElementBase | undefined> { return this.onDidChangeTreeDataEmitter.event; } - async getChildren(element: ResourceGroupsItem): Promise<ResourceGroupsItem[] | null | undefined> { + async getChildren(element: ResourceGroupsItem): Promise<TreeElementBase[] | null | undefined> { return (await element.getChildren?.())?.map((child) => { return ext.azureTreeState.wrapItemInStateHandling(child, () => this.refresh(child)) }); @@ -42,14 +42,14 @@ export class ManagedIdentityBranchDataProvider extends vscode.Disposable impleme throw new Error(localize('failedToGetResourceItem', 'Failed to get resource item for "{0}"', element.id)); } - return ext.azureTreeState.wrapItemInStateHandling(resourceItem, () => this.refresh(resourceItem)); + return ext.azureTreeState.wrapItemInStateHandling(resourceItem, () => this.refresh(resourceItem)) as ResourceGroupsItem; } async getTreeItem(element: ResourceGroupsItem): Promise<vscode.TreeItem> { return await element.getTreeItem(); } - refresh(element?: ResourceGroupsItem): void { + refresh(element?: TreeElementBase): void { this.onDidChangeTreeDataEmitter.fire(element); } } diff --git a/src/tree/ResourceGroupsItem.ts b/src/tree/ResourceGroupsItem.ts index 0a6e1a47..87a252ce 100644 --- a/src/tree/ResourceGroupsItem.ts +++ b/src/tree/ResourceGroupsItem.ts @@ -3,8 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { TreeElementBase } from 'node_modules/@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; +export type TreeDataItem = ResourceGroupsItem | TreeElementBase; export interface ResourceGroupsItem { readonly id: string; diff --git a/src/tree/ResourceTreeDataProviderBase.ts b/src/tree/ResourceTreeDataProviderBase.ts index f2ab770f..2945f29f 100644 --- a/src/tree/ResourceTreeDataProviderBase.ts +++ b/src/tree/ResourceTreeDataProviderBase.ts @@ -4,27 +4,27 @@ *--------------------------------------------------------------------------------------------*/ import { AzureSubscriptionProvider } from '@microsoft/vscode-azext-azureauth'; -import { callWithTelemetryAndErrorHandling, parseError } from '@microsoft/vscode-azext-utils'; +import { callWithTelemetryAndErrorHandling, parseError, TreeElementBase } from '@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; import { ResourceBase, ResourceModelBase } from '../../api/src/index'; import { ext } from '../extensionVariables'; import { BranchDataItemCache } from './BranchDataItemCache'; import { BranchDataItemWrapper } from './BranchDataItemWrapper'; import { InvalidItem } from './InvalidItem'; -import { ResourceGroupsItem } from './ResourceGroupsItem'; +import { ResourceGroupsItem, TreeDataItem } from './ResourceGroupsItem'; import { TreeItemStateStore } from './TreeItemState'; -export abstract class ResourceTreeDataProviderBase extends vscode.Disposable implements vscode.TreeDataProvider<ResourceGroupsItem> { +export abstract class ResourceTreeDataProviderBase extends vscode.Disposable implements vscode.TreeDataProvider<TreeDataItem> { private readonly branchTreeDataChangeSubscription: vscode.Disposable; private readonly refreshSubscription: vscode.Disposable; private readonly resourceProviderManagerListener: vscode.Disposable; - private readonly onDidChangeTreeDataEmitter = new vscode.EventEmitter<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>(); + private readonly onDidChangeTreeDataEmitter = new vscode.EventEmitter<void | TreeElementBase | TreeElementBase[] | null | undefined>(); constructor( protected readonly itemCache: BranchDataItemCache, onDidChangeBranchTreeData: vscode.Event<void | ResourceModelBase | ResourceModelBase[] | null | undefined>, onDidChangeResource: vscode.Event<ResourceBase | undefined>, - onRefresh: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + onRefresh: vscode.Event<void | TreeDataItem | TreeDataItem[] | null | undefined>, private readonly state?: TreeItemStateStore, callOnDispose?: () => void) { super( @@ -73,10 +73,10 @@ export abstract class ResourceTreeDataProviderBase extends vscode.Disposable imp } } - onDidChangeTreeData: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined> = this.onDidChangeTreeDataEmitter.event; + onDidChangeTreeData: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined> = this.onDidChangeTreeDataEmitter.event; notifyTreeDataChanged(data: void | ResourceModelBase | ResourceModelBase[] | null | undefined): void { - const rgItems: ResourceGroupsItem[] = []; + const rgItems: TreeDataItem[] = []; // eslint-disable-next-line no-extra-boolean-cast if (!!data) { @@ -100,7 +100,7 @@ export abstract class ResourceTreeDataProviderBase extends vscode.Disposable imp } } - async getTreeItem(element: ResourceGroupsItem): Promise<vscode.TreeItem> { + async getTreeItem(element: TreeDataItem): Promise<vscode.TreeItem> { try { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return (await callWithTelemetryAndErrorHandling('getTreeItem', async (context) => { @@ -113,7 +113,7 @@ export abstract class ResourceTreeDataProviderBase extends vscode.Disposable imp } } - async getChildren(element?: ResourceGroupsItem | undefined): Promise<ResourceGroupsItem[] | null | undefined> { + async getChildren(element?: TreeDataItem | undefined): Promise<TreeDataItem[] | null | undefined> { const children = await this.onGetChildren(element); return children?.map(child => { if (this.state) { @@ -127,23 +127,23 @@ export abstract class ResourceTreeDataProviderBase extends vscode.Disposable imp }); } - getParent(element: ResourceGroupsItem): vscode.ProviderResult<ResourceGroupsItem> { + getParent(element: ResourceGroupsItem): vscode.ProviderResult<TreeDataItem> { return element.getParent?.(); } - async findItemById(id: string): Promise<ResourceGroupsItem | undefined> { - let element: ResourceGroupsItem | undefined = undefined; + async findItemById(id: string): Promise<TreeDataItem | undefined> { + let element: TreeDataItem | undefined = undefined; outerLoop: while (true) { - const children: ResourceGroupsItem[] | null | undefined = await this.getChildren(element); + const children: TreeDataItem[] | null | undefined = await this.getChildren(element); if (!children) { return; } for (const child of children) { - if (child.id.toLowerCase() === id.toLowerCase()) { + if (child.id?.toLowerCase() === id.toLowerCase()) { return child; - } else if (removePrefix(child.id.toLowerCase()) === id.toLowerCase()) { + } else if (removePrefix(child.id?.toLowerCase()) === id.toLowerCase()) { return child; } else if (this.isAncestorOf(child, id)) { element = child; @@ -155,15 +155,15 @@ export abstract class ResourceTreeDataProviderBase extends vscode.Disposable imp } } - protected isAncestorOf(element: ResourceGroupsItem, id: string): boolean { + protected isAncestorOf(element: TreeDataItem, id: string): boolean { // remove accounts / <accountId>/tenant/<tenantId> from the beginning of the id const elementId = removePrefix(element.id) + '/'; return id.toLowerCase().startsWith(elementId.toLowerCase()); } - protected abstract onGetChildren(element?: ResourceGroupsItem | undefined): Promise<ResourceGroupsItem[] | null | undefined>; + protected abstract onGetChildren(element?: TreeDataItem | undefined): Promise<TreeDataItem[] | null | undefined>; } -function removePrefix(id: string): string { - return id.replace(/\/accounts\/.+\/tenants\/[^/]+\//i, '/') +function removePrefix(id?: string): string { + return id?.replace(/\/accounts\/.+\/tenants\/[^/]+\//i, '/') || ''; } diff --git a/src/tree/TreeDataProviderBase.ts b/src/tree/TreeDataProviderBase.ts new file mode 100644 index 00000000..214f02f3 --- /dev/null +++ b/src/tree/TreeDataProviderBase.ts @@ -0,0 +1,162 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { callWithTelemetryAndErrorHandling, parseError, TreeElementBase } from '@microsoft/vscode-azext-utils'; +import * as vscode from 'vscode'; +import { ResourceBase, ResourceModelBase } from '../../api/src/index'; +import { BranchDataItemCache } from './BranchDataItemCache'; +import { InvalidItem } from './InvalidItem'; + +export abstract class TreeDataProviderBase extends vscode.Disposable implements vscode.TreeDataProvider<TreeElementBase> { + private readonly branchTreeDataChangeSubscription: vscode.Disposable; + private readonly refreshSubscription: vscode.Disposable; + private readonly resourceProviderManagerListener: vscode.Disposable; + private readonly onDidChangeTreeDataEmitter = new vscode.EventEmitter<void | TreeElementBase | TreeElementBase[] | null | undefined>(); + + constructor( + protected readonly itemCache: BranchDataItemCache, + onDidChangeBranchTreeData: vscode.Event<void | ResourceModelBase | ResourceModelBase[] | null | undefined>, + onDidChangeResource: vscode.Event<ResourceBase | undefined>, + onRefresh: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, + // private readonly state?: TreeItemStateStore, + callOnDispose?: () => void) { + super( + () => { + callOnDispose?.(); + + this.branchTreeDataChangeSubscription.dispose(); + this.refreshSubscription.dispose(); + this.resourceProviderManagerListener.dispose(); + }); + + this.branchTreeDataChangeSubscription = onDidChangeBranchTreeData(e => this.notifyTreeDataChanged(e)); + + this.refreshSubscription = onRefresh((e) => this.onDidChangeTreeDataEmitter.fire(e)); + + // TODO: If only individual resources change, just update the tree related to those resources. + this.resourceProviderManagerListener = onDidChangeResource(() => this.onDidChangeTreeDataEmitter.fire()); + } + + // protected statusSubscription: vscode.Disposable | undefined; + // private subscriptionProvider?: AzureSubscriptionProvider; + // private nextSessionChangeMessageMinimumTime = 0; + // private sessionChangeMessageInterval = 1 * 1000; // 1 second + + // protected async getAzureSubscriptionProvider(): Promise<AzureSubscriptionProvider> { + // // override for testing + // if (ext.testing.overrideAzureSubscriptionProvider) { + // return ext.testing.overrideAzureSubscriptionProvider(); + // } else { + // if (!this.subscriptionProvider) { + // this.subscriptionProvider = await ext.subscriptionProviderFactory(); + // } + + // this.statusSubscription = vscode.authentication.onDidChangeSessions((evt: vscode.AuthenticationSessionsChangeEvent) => { + // if (evt.provider.id === 'microsoft' || evt.provider.id === 'microsoft-sovereign-cloud') { + // if (Date.now() > this.nextSessionChangeMessageMinimumTime) { + // this.nextSessionChangeMessageMinimumTime = Date.now() + this.sessionChangeMessageInterval; + // // This event gets HEAVILY spammed and needs to be debounced + // // Suppress additional messages for 1 second after the first one + // this.notifyTreeDataChanged(); + // } + // } + // }); + + // return this.subscriptionProvider; + // } + // } + + public onDidChangeTreeData: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined> = this.onDidChangeTreeDataEmitter.event; + + public notifyTreeDataChanged(data: void | ResourceModelBase | ResourceModelBase[] | null | undefined): void { + const rgItems: TreeElementBase[] = []; + + // eslint-disable-next-line no-extra-boolean-cast + if (!!data) { + // e was defined, either a single item or array + // Make an array for consistency + const branchItems: ResourceModelBase[] = Array.isArray(data) ? data : [data]; + + for (const branchItem of branchItems) { + const rgItem = this.itemCache.getItemForBranchItem(branchItem); + + if (rgItem) { + rgItems.push(rgItem); + } + } + this.onDidChangeTreeDataEmitter.fire(rgItems); + } else { + // e was null/undefined/void + // Translate it to fire on all elements for this branch data provider + // TODO + this.onDidChangeTreeDataEmitter.fire(); + } + } + + async getTreeItem(element: TreeElementBase): Promise<vscode.TreeItem> { + try { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return (await callWithTelemetryAndErrorHandling('getTreeItem', async (context) => { + context.errorHandling.rethrow = true; + return await element.getTreeItem(); + }))!; + } catch (e) { + const invalidItem = new InvalidItem(parseError(e)); + return invalidItem.getTreeItem(); + } + } + + abstract getChildren(element?: TreeElementBase | undefined): Promise<TreeElementBase[] | null | undefined>; + // const children = await this.onGetChildren(element); + // return children?.map(child => { + // if (this.state) { + // // don't wrap items that belong to branch data providers + // if (child instanceof BranchDataItemWrapper) { + // return child; + // } + // return this.state.wrapItemInStateHandling(child, (item) => this.onDidChangeTreeDataEmitter.fire(item)); + // } + // return child; + // }); + + abstract getParent(element: TreeElementBase): vscode.ProviderResult<TreeElementBase> + // return element.getParent?.(); + + async findItemById(id: string): Promise<TreeElementBase | undefined> { + let element: TreeElementBase | undefined = undefined; + outerLoop: while (true) { + const children: TreeElementBase[] | null | undefined = await this.getChildren(element); + + if (!children) { + return; + } + + for (const child of children) { + if (child.id?.toLowerCase() === id.toLowerCase()) { + return child; + } else if (removePrefix(child.id?.toLowerCase()) === id.toLowerCase()) { + return child; + } else if (this.isAncestorOf(child, id)) { + element = child; + continue outerLoop; + } + } + + return undefined; + } + } + + protected isAncestorOf(element: TreeElementBase, id: string): boolean { + // remove accounts / <accountId>/tenant/<tenantId> from the beginning of the id + const elementId = removePrefix(element.id) + '/'; + return id.toLowerCase().startsWith(elementId.toLowerCase()); + } + + protected abstract onGetChildren(element?: TreeElementBase | undefined): Promise<TreeElementBase[] | null | undefined>; +} + +function removePrefix(id?: string): string { + return id ? id.replace(/\/accounts\/.+\/tenants\/[^/]+\//i, '/') : ''; +} diff --git a/src/tree/TreeItemState.ts b/src/tree/TreeItemState.ts index 888ca368..00017f08 100644 --- a/src/tree/TreeItemState.ts +++ b/src/tree/TreeItemState.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { TreeElementBase } from 'node_modules/@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; -import { ResourceGroupsItem } from './ResourceGroupsItem'; interface TreeItemState { /** @@ -32,7 +32,7 @@ export class TreeItemStateStore implements vscode.Disposable { this.onDidUpdateStateEmitter.fire(id); } - wrapItemInStateHandling(item: ResourceGroupsItem, refresh: (item: ResourceGroupsItem) => void): ResourceGroupsItem { + wrapItemInStateHandling(item: TreeElementBase, refresh: (item: TreeElementBase) => void): TreeElementBase { const getTreeItem = item.getTreeItem.bind(item) as typeof item.getTreeItem; item.getTreeItem = async () => { const treeItem = await getTreeItem(); @@ -79,7 +79,7 @@ export class TreeItemStateStore implements vscode.Disposable { return treeItem; } - private onDidRequestRefresh(id: string, callback: () => void): void { + private onDidRequestRefresh(id: string | undefined, callback: () => void): void { this.disposables.push(this.onDidUpdateStateEvent((eventId: string) => { if (eventId === id) { callback(); diff --git a/src/activityLog/ActivityTreeItem.ts b/src/tree/activityLog/ActivityItem.ts similarity index 77% rename from src/activityLog/ActivityTreeItem.ts rename to src/tree/activityLog/ActivityItem.ts index b11b2140..d859e72f 100644 --- a/src/activityLog/ActivityTreeItem.ts +++ b/src/tree/activityLog/ActivityItem.ts @@ -3,18 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AzExtParentTreeItem, AzExtTreeItem, callWithTelemetryAndErrorHandling, IActionContext, TreeItemIconPath } from "@microsoft/vscode-azext-utils"; +import { callWithTelemetryAndErrorHandling, TreeElementBase, TreeItemIconPath } from "@microsoft/vscode-azext-utils"; import { Activity, ActivityTreeItemOptions, OnErrorActivityData, OnProgressActivityData, OnStartActivityData, OnSuccessActivityData } from "@microsoft/vscode-azext-utils/hostapi"; -import { Disposable, ThemeColor, ThemeIcon, TreeItemCollapsibleState } from "vscode"; -import { localize } from "../utils/localize"; +import { Disposable, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; +import { ext } from "../../extensionVariables"; +import { localize } from "../../utils/localize"; +import { TreeDataItem } from "../ResourceGroupsItem"; export enum ActivityStatus { Running = 'running', Done = 'done' } -export class ActivityTreeItem extends AzExtParentTreeItem implements Disposable { - +export class ActivityItem implements TreeElementBase, Disposable { + public readonly id: string; public startedAtMs: number; public get contextValue(): string { @@ -53,14 +55,23 @@ export class ActivityTreeItem extends AzExtParentTreeItem implements Disposable label: localize('loading', 'Loading...') } - public initialCollapsibleState: TreeItemCollapsibleState = TreeItemCollapsibleState.None; + getTreeItem(): TreeItem | Thenable<TreeItem> { + return { + label: this.label, + description: this.description, + iconPath: this.iconPath, + contextValue: this.contextValue, + collapsibleState: this.initialCollapsibleState + } + } + + public initialCollapsibleState: TreeItemCollapsibleState = TreeItemCollapsibleState.Expanded; public status?: ActivityStatus; public error?: unknown; private latestProgress?: { message?: string }; - public constructor(parent: AzExtParentTreeItem, activity: Activity) { - super(parent); + public constructor(activity: Activity) { this.id = activity.id; this.setupListeners(activity); this.startedAtMs = Date.now(); @@ -72,53 +83,49 @@ export class ActivityTreeItem extends AzExtParentTreeItem implements Disposable private readonly disposables: Disposable[] = []; - public async loadMoreChildrenImpl(_clearCache: boolean, _context: IActionContext): Promise<AzExtTreeItem[]> { + public async getChildren(): Promise<TreeDataItem[] | null | undefined> { if (this.state.getChildren) { return await this.state.getChildren(this); } return []; } - public hasMoreChildrenImpl(): boolean { - return false; - } - private onProgress(data: OnProgressActivityData): void { void callWithTelemetryAndErrorHandling('activityOnProgress', async (context) => { context.telemetry.suppressIfSuccessful = true; this.latestProgress = data.message ? { message: data?.message } : this.latestProgress; this.state = data; - await this.refresh(context); + ext.actions.refreshActivityLogTree(this); }); } private onStart(data: OnStartActivityData): void { - void callWithTelemetryAndErrorHandling('activityOnStart', async (context) => { + void callWithTelemetryAndErrorHandling('activityOnStart', async (_context) => { this.startedAtMs = Date.now(); this.status = ActivityStatus.Running; this.state = data; - await this.refresh(context); + ext.actions.refreshActivityLogTree(this); }); } private onSuccess(data: OnSuccessActivityData): void { - void callWithTelemetryAndErrorHandling('activityOnSuccess', async (context) => { + void callWithTelemetryAndErrorHandling('activityOnSuccess', async (_context) => { this.state = data; this.status = ActivityStatus.Done; if (this.state.getChildren) { this.initialCollapsibleState = TreeItemCollapsibleState.Expanded; } - await this.refresh(context); + ext.actions.refreshActivityLogTree(this); }) } private onError(data: OnErrorActivityData): void { - void callWithTelemetryAndErrorHandling('activityOnError', async (context) => { + void callWithTelemetryAndErrorHandling('activityOnError', async (_context) => { this.state = data; this.status = ActivityStatus.Done; this.error = data.error; this.initialCollapsibleState = TreeItemCollapsibleState.Expanded; - await this.refresh(context); + ext.actions.refreshActivityLogTree(this); }); } diff --git a/src/tree/activityLog/ActivityLogBranchDataProvider.ts b/src/tree/activityLog/ActivityLogBranchDataProvider.ts new file mode 100644 index 00000000..7757e613 --- /dev/null +++ b/src/tree/activityLog/ActivityLogBranchDataProvider.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { callWithTelemetryAndErrorHandling, IActionContext, TreeElementBase } from '@microsoft/vscode-azext-utils'; +import { Activity } from '@microsoft/vscode-azext-utils/hostapi'; +import { commands, Event } from 'vscode'; +import { ActivityLogResourceProviderManager } from '../../api/ResourceProviderManagers'; +import { ext } from '../../extensionVariables'; +import { settingUtils } from '../../utils/settingUtils'; +import { BranchDataItemCache } from '../BranchDataItemCache'; +import { ResourceTreeDataProviderBase } from '../ResourceTreeDataProviderBase'; +import { WorkspaceResourceBranchDataProviderManager } from '../workspace/WorkspaceResourceBranchDataProviderManager'; +import { ActivityItem, ActivityStatus } from './ActivityItem'; + +export class ActivityLogTreeDataProvider extends ResourceTreeDataProviderBase { + private activityTreeItems: Record<string, ActivityItem> = {}; + constructor( + branchDataProviderManager: WorkspaceResourceBranchDataProviderManager, + onRefresh: Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, + resourceProviderManager: ActivityLogResourceProviderManager, + branchItemCache: BranchDataItemCache) { + super( + branchItemCache, + branchDataProviderManager.onDidChangeTreeData, + resourceProviderManager.onDidChangeResourceChange, + onRefresh); + } + + async onGetChildren(element?: TreeElementBase | undefined): Promise<TreeElementBase[] | null | undefined> { + if (element?.getChildren) { + return await element.getChildren(); + } else { + return Object.values(this.activityTreeItems).filter((activity) => !!activity.status); + } + } + + public async addActivity(activity: Activity): Promise<void> { + await callWithTelemetryAndErrorHandling('registerActivity', async (_context: IActionContext) => { + this.activityTreeItems[activity.id] = new ActivityItem(activity); + if ((await settingUtils.getWorkspaceSetting('autoOpenActivityPanel'))) { + await commands.executeCommand('azureActivityLog.focus'); + } + + ext.actions.refreshActivityLogTree(); + }); + } + + public async clearActivities(_context: IActionContext): Promise<void> { + Object.entries(this.activityTreeItems).forEach(([id, activity]: [string, ActivityItem]) => { + if (activity.status === ActivityStatus.Done) { + activity.dispose(); + delete this.activityTreeItems[id]; + } + }); + ext.actions.refreshActivityLogTree(); + } +} diff --git a/src/tree/activityLog/ActivityLogBranchDataProviderManager.ts b/src/tree/activityLog/ActivityLogBranchDataProviderManager.ts new file mode 100644 index 00000000..142e132f --- /dev/null +++ b/src/tree/activityLog/ActivityLogBranchDataProviderManager.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BranchDataProvider, ResourceBase, ResourceModelBase } from "api/src"; +import { ResourceBranchDataProviderManagerBase } from "../ResourceBranchDataProviderManagerBase"; + +export class ActivityLogResourceBranchDataProviderManager extends ResourceBranchDataProviderManagerBase<string, BranchDataProvider<ResourceBase, ResourceModelBase>> { + constructor( + defaultProvider: BranchDataProvider<ResourceBase, ResourceModelBase> + ) { + super( + defaultProvider, + () => { return 'activityLog' } + ); + } +} diff --git a/src/tree/activityLog/ActivityLogDefaultBranchDataProvider.ts b/src/tree/activityLog/ActivityLogDefaultBranchDataProvider.ts new file mode 100644 index 00000000..9430af3d --- /dev/null +++ b/src/tree/activityLog/ActivityLogDefaultBranchDataProvider.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.md in the project root for license information. +*--------------------------------------------------------------------------------------------*/ +import * as vscode from 'vscode'; +import { BranchDataProvider, ResourceBase, ResourceModelBase } from '../../../api/src/index'; +import { ActivityLogResource } from './activityLog'; + +interface ActivityLogResourceModel extends ResourceModelBase { + readonly name: string; +} + +class ActivityLogResourceItem implements ActivityLogResourceModel { + constructor(private readonly resource: ActivityLogResource) { + } + + get name(): string { + return this.resource.name; + } +} + +export class ActivityLogDefaultBranchDataProvider implements BranchDataProvider<ResourceBase, ActivityLogResourceModel> { + getChildren(_element: ActivityLogResourceModel): vscode.ProviderResult<ActivityLogResourceModel[]> { + return []; + } + + getResourceItem(element: ActivityLogResource): ActivityLogResourceModel | Thenable<ActivityLogResourceModel> { + return new ActivityLogResourceItem(element); + } + + getTreeItem(element: ActivityLogResourceModel): vscode.TreeItem | Thenable<vscode.TreeItem> { + return new vscode.TreeItem(element.name); + } +} diff --git a/src/tree/activityLog/ActivityLogResourceBranchDataProviderManager.ts b/src/tree/activityLog/ActivityLogResourceBranchDataProviderManager.ts new file mode 100644 index 00000000..5a3a3a8e --- /dev/null +++ b/src/tree/activityLog/ActivityLogResourceBranchDataProviderManager.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.md in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +import { BranchDataProvider, ResourceBase, ResourceModelBase } from '../../../api/src/index'; +import { ResourceBranchDataProviderManagerBase } from "../ResourceBranchDataProviderManagerBase"; + +export class ActivityLogResourceBranchDataProviderManager extends ResourceBranchDataProviderManagerBase<string, BranchDataProvider<ResourceBase, ResourceModelBase>> { + constructor( + defaultProvider: BranchDataProvider<ResourceBase, ResourceModelBase> + ) { + super(defaultProvider, () => { return 'activityLog' }); + } +} diff --git a/src/tree/activityLog/activityLog.ts b/src/tree/activityLog/activityLog.ts new file mode 100644 index 00000000..2fae5948 --- /dev/null +++ b/src/tree/activityLog/activityLog.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.md in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +import { BranchDataProvider, ResourceBase, ResourceModelBase, ResourceProvider } from "api/src"; + +/** + * Respresents a specific type of activity log resource. + * + * @remarks This value should be unique across all types of activity log resources. + */ +export type ActivityLogResourceType = string; + +/** + * An indivdual root resource for an activity log. + */ +export interface ActivityLogResource extends ResourceBase { + //account? + + /** + * The type of this resource. + * + * @remarks This value is used to map resources to their associated branch data provider. + */ + readonly resourceType: ActivityLogResourceType; +} + +/** + * A provider for supplying items for the activity log resource tree + */ +export type ActivityLogResourceProvider = ResourceProvider<void, ActivityLogResource>; +/** + * A provider for visualizing items in the activity log resource tree + */ +export type ActivityLogResourceBranchDataProvider<TModel extends ResourceModelBase> = BranchDataProvider<ActivityLogResource, TModel>; diff --git a/src/tree/azure/AzureResourceTreeDataProvider.ts b/src/tree/azure/AzureResourceTreeDataProvider.ts index e654af76..f718ee79 100644 --- a/src/tree/azure/AzureResourceTreeDataProvider.ts +++ b/src/tree/azure/AzureResourceTreeDataProvider.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { AzureSubscription, getUnauthenticatedTenants } from '@microsoft/vscode-azext-azureauth'; -import { IActionContext, callWithTelemetryAndErrorHandling, createSubscriptionContext, nonNullValueAndProp, registerEvent } from '@microsoft/vscode-azext-utils'; +import { IActionContext, TreeElementBase, callWithTelemetryAndErrorHandling, createSubscriptionContext, nonNullValueAndProp, registerEvent } from '@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; import { ResourceModelBase } from '../../../api/src/index'; import { AzureResourceProviderManager } from '../../api/ResourceProviderManagers'; @@ -28,7 +28,7 @@ export class AzureResourceTreeDataProvider extends AzureResourceTreeDataProvider onDidChangeBranchTreeData: vscode.Event<void | ResourceModelBase | ResourceModelBase[] | null | undefined>, itemCache: BranchDataItemCache, state: TreeItemStateStore, - onRefresh: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + onRefresh: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, protected readonly resourceGroupingManager: AzureResourceGroupingManager, protected readonly resourceProviderManager: AzureResourceProviderManager) { super( @@ -63,7 +63,7 @@ export class AzureResourceTreeDataProvider extends AzureResourceTreeDataProvider } async onGetChildren(element?: ResourceGroupsItem | undefined): Promise<ResourceGroupsItem[] | null | undefined> { - if (element) { + if (element?.getChildren) { return await element.getChildren(); } else { const subscriptionProvider = await this.getAzureSubscriptionProvider(); diff --git a/src/tree/azure/AzureResourceTreeDataProviderBase.ts b/src/tree/azure/AzureResourceTreeDataProviderBase.ts index 7a582e08..0dcabd1b 100644 --- a/src/tree/azure/AzureResourceTreeDataProviderBase.ts +++ b/src/tree/azure/AzureResourceTreeDataProviderBase.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { TreeElementBase } from 'node_modules/@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; import { ResourceModelBase } from '../../../api/src/index'; import { AzureResourceProviderManager } from '../../api/ResourceProviderManagers'; @@ -17,7 +18,7 @@ export abstract class AzureResourceTreeDataProviderBase extends ResourceTreeData constructor( itemCache: BranchDataItemCache, onDidChangeBranchTreeData: vscode.Event<void | ResourceModelBase | ResourceModelBase[] | null | undefined>, - onRefresh: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + onRefresh: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, state: TreeItemStateStore, protected readonly resourceGroupingManager: AzureResourceGroupingManager, protected readonly resourceProviderManager: AzureResourceProviderManager, diff --git a/src/tree/azure/FocusViewTreeDataProvider.ts b/src/tree/azure/FocusViewTreeDataProvider.ts index 16bf2958..1da1829a 100644 --- a/src/tree/azure/FocusViewTreeDataProvider.ts +++ b/src/tree/azure/FocusViewTreeDataProvider.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { AzureSubscription } from '@microsoft/vscode-azext-azureauth'; +import { TreeElementBase } from 'node_modules/@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; import { AzExtResourceType, AzureResource, ResourceModelBase } from '../../../api/src/index'; import { AzureResourceProviderManager } from '../../api/ResourceProviderManagers'; @@ -32,7 +33,7 @@ export class FocusViewTreeDataProvider extends AzureResourceTreeDataProviderBase onDidChangeBranchTreeData: vscode.Event<void | ResourceModelBase | ResourceModelBase[] | null | undefined>, itemCache: BranchDataItemCache, state: TreeItemStateStore, - onRefresh: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + onRefresh: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, protected readonly resourceGroupingManager: AzureResourceGroupingManager, protected readonly resourceProviderManager: AzureResourceProviderManager) { super( @@ -45,7 +46,7 @@ export class FocusViewTreeDataProvider extends AzureResourceTreeDataProviderBase } async onGetChildren(element?: ResourceGroupsItem | undefined): Promise<ResourceGroupsItem[] | null | undefined> { - if (element) { + if (element?.getChildren) { return await element.getChildren(); } else { const focusedGroup = ext.focusedGroup; diff --git a/src/tree/azure/registerAzureTree.ts b/src/tree/azure/registerAzureTree.ts index 787e28b5..471f1c7c 100644 --- a/src/tree/azure/registerAzureTree.ts +++ b/src/tree/azure/registerAzureTree.ts @@ -11,7 +11,7 @@ import { ext } from '../../extensionVariables'; import { localize } from '../../utils/localize'; import { listenForRecentlyUsedNodes } from '../../utils/usedAndSelectedResources'; import { BranchDataItemCache } from '../BranchDataItemCache'; -import { ResourceGroupsItem } from '../ResourceGroupsItem'; +import { TreeDataItem } from '../ResourceGroupsItem'; import { TreeItemStateStore } from '../TreeItemState'; import { createTreeView } from '../createTreeView'; import { wrapTreeForVSCode } from '../wrapTreeForVSCode'; @@ -24,7 +24,7 @@ import { GroupingItemFactory } from './grouping/GroupingItemFactory'; interface RegisterAzureTreeOptions { azureResourceBranchDataProviderManager: AzureResourceBranchDataProviderManager, azureResourceProviderManager: AzureResourceProviderManager, - refreshEvent: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + refreshEvent: vscode.Event<void | TreeDataItem | TreeDataItem[] | null | undefined>, itemCache: BranchDataItemCache, } diff --git a/src/tree/azure/registerFocusTree.ts b/src/tree/azure/registerFocusTree.ts index 6acadde3..99e3fa46 100644 --- a/src/tree/azure/registerFocusTree.ts +++ b/src/tree/azure/registerFocusTree.ts @@ -10,7 +10,7 @@ import { AzureResourceProviderManager } from '../../api/ResourceProviderManagers import { ext } from '../../extensionVariables'; import { localize } from '../../utils/localize'; import { BranchDataItemCache } from '../BranchDataItemCache'; -import { ResourceGroupsItem } from '../ResourceGroupsItem'; +import { TreeDataItem } from '../ResourceGroupsItem'; import { createTreeView } from '../createTreeView'; import { wrapTreeForVSCode } from '../wrapTreeForVSCode'; import { AzureResourceBranchDataProviderManager } from './AzureResourceBranchDataProviderManager'; @@ -22,7 +22,7 @@ import { GroupingItemFactory } from './grouping/GroupingItemFactory'; interface RegisterAzureTreeOptions { azureResourceBranchDataProviderManager: AzureResourceBranchDataProviderManager, azureResourceProviderManager: AzureResourceProviderManager, - refreshEvent: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + refreshEvent: vscode.Event<void | TreeDataItem | TreeDataItem[] | null | undefined>, itemCache: BranchDataItemCache, } diff --git a/src/tree/createTreeView.ts b/src/tree/createTreeView.ts index 8e27dd15..806561ca 100644 --- a/src/tree/createTreeView.ts +++ b/src/tree/createTreeView.ts @@ -6,15 +6,15 @@ import { isAzExtTreeItem } from "@microsoft/vscode-azext-utils"; import { TreeDataProvider, TreeView, TreeViewOptions, window } from "vscode"; import { BranchDataItemCache } from "./BranchDataItemCache"; -import { ResourceGroupsItem } from "./ResourceGroupsItem"; +import { TreeDataItem } from "./ResourceGroupsItem"; -export interface InternalTreeView extends TreeView<ResourceGroupsItem> { - _reveal: TreeView<ResourceGroupsItem>['reveal']; +export interface InternalTreeView extends TreeView<TreeDataItem> { + _reveal: TreeView<TreeDataItem>['reveal']; } -interface InternalTreeViewOptions extends TreeViewOptions<ResourceGroupsItem> { - treeDataProvider: TreeDataProvider<ResourceGroupsItem>; - findItemById: (id: string) => Promise<ResourceGroupsItem | undefined>; +interface InternalTreeViewOptions extends TreeViewOptions<TreeDataItem> { + treeDataProvider: TreeDataProvider<TreeDataItem>; + findItemById: (id: string) => Promise<TreeDataItem | undefined>; itemCache: BranchDataItemCache; /** * See {@link TreeView.description} @@ -31,7 +31,7 @@ interface InternalTreeViewOptions extends TreeViewOptions<ResourceGroupsItem> { * - sets the `description` if present in options * - modifies `TreeView.reveal` {@link ResourceTreeDataProviderBase.reveal} */ -export function createTreeView(viewId: string, options: InternalTreeViewOptions): TreeView<ResourceGroupsItem> { +export function createTreeView(viewId: string, options: InternalTreeViewOptions): TreeView<TreeDataItem> { const treeView = window.createTreeView(viewId, options); treeView.title = options.title; treeView.description = options.description; @@ -44,12 +44,12 @@ export function createTreeView(viewId: string, options: InternalTreeViewOptions) /** * v1.5 compatibility for TreeView.reveal */ -function modifyReveal(treeView: TreeView<ResourceGroupsItem>, findItemById: (id: string) => Promise<ResourceGroupsItem | undefined>, itemCache: BranchDataItemCache): void { +function modifyReveal(treeView: TreeView<TreeDataItem>, findItemById: (id: string) => Promise<TreeDataItem | undefined>, itemCache: BranchDataItemCache): void { (treeView as InternalTreeView)._reveal = treeView.reveal.bind(treeView) as typeof treeView.reveal; treeView.reveal = async (element, options) => { - // For compatibility: convert AzExtTreeItems into ResourceGroupsItems - const item: ResourceGroupsItem | undefined = isAzExtTreeItem(element) ? itemCache.getItemForBranchItem(element) ?? await findItemById(element.fullId) : element; + // For compatibility: convert AzExtTreeItems into TreeDataItems + const item: TreeDataItem | undefined = isAzExtTreeItem(element) ? itemCache.getItemForBranchItem(element) ?? await findItemById(element.fullId) : element; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion await (treeView as InternalTreeView)._reveal(item!, options); } diff --git a/src/tree/tenants/TenantResourceTreeDataProvider.ts b/src/tree/tenants/TenantResourceTreeDataProvider.ts index ed1c79bc..d4df989b 100644 --- a/src/tree/tenants/TenantResourceTreeDataProvider.ts +++ b/src/tree/tenants/TenantResourceTreeDataProvider.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { getConfiguredAuthProviderId } from '@microsoft/vscode-azext-azureauth'; -import { IActionContext, callWithTelemetryAndErrorHandling, nonNullProp, nonNullValueAndProp } from '@microsoft/vscode-azext-utils'; +import { IActionContext, TreeElementBase, callWithTelemetryAndErrorHandling, nonNullProp, nonNullValueAndProp } from '@microsoft/vscode-azext-utils'; import { ResourceModelBase } from 'api/src'; import * as vscode from 'vscode'; import { TenantResourceProviderManager } from '../../api/ResourceProviderManagers'; @@ -21,7 +21,7 @@ export class TenantResourceTreeDataProvider extends ResourceTreeDataProviderBase constructor( protected readonly branchDataProviderManager: TenantResourceBranchDataProviderManager, onDidChangeBranchTreeData: vscode.Event<void | ResourceModelBase | ResourceModelBase[] | null | undefined>, - onRefresh: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + onRefresh: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, protected readonly resourceProviderManager: TenantResourceProviderManager, branchItemCache: BranchDataItemCache, callOnDispose?: () => void) { diff --git a/src/tree/tenants/registerTenantTree.ts b/src/tree/tenants/registerTenantTree.ts index 25ad4e0d..93c717b7 100644 --- a/src/tree/tenants/registerTenantTree.ts +++ b/src/tree/tenants/registerTenantTree.ts @@ -9,7 +9,7 @@ import { TenantResourceProviderManager } from "../../api/ResourceProviderManager import { ext } from '../../extensionVariables'; import { localize } from '../../utils/localize'; import { BranchDataItemCache } from '../BranchDataItemCache'; -import { ResourceGroupsItem } from '../ResourceGroupsItem'; +import { TreeDataItem } from '../ResourceGroupsItem'; import { createTreeView } from '../createTreeView'; import { wrapTreeForVSCode } from '../wrapTreeForVSCode'; import { TenantResourceBranchDataProviderManager } from "./TenantResourceBranchDataProviderManager"; @@ -19,7 +19,7 @@ import { TenantTreeItem } from './TenantTreeItem'; interface RegisterTenantTreeOptions { tenantResourceBranchDataProviderManager: TenantResourceBranchDataProviderManager, tenantResourceProviderManager: TenantResourceProviderManager, - refreshEvent: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + refreshEvent: vscode.Event<void | TreeDataItem | TreeDataItem[] | null | undefined>, itemCache: BranchDataItemCache } diff --git a/src/tree/workspace/WorkspaceResourceTreeDataProvider.ts b/src/tree/workspace/WorkspaceResourceTreeDataProvider.ts index bb599e0d..4756db14 100644 --- a/src/tree/workspace/WorkspaceResourceTreeDataProvider.ts +++ b/src/tree/workspace/WorkspaceResourceTreeDataProvider.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { TreeElementBase } from 'node_modules/@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; import { WorkspaceResource } from '../../../api/src/index'; import { WorkspaceResourceProviderManager } from '../../api/ResourceProviderManagers'; @@ -17,7 +18,7 @@ import { WorkspaceResourceBranchDataProviderManager } from './WorkspaceResourceB export class WorkspaceResourceTreeDataProvider extends ResourceTreeDataProviderBase { constructor( private readonly branchDataProviderManager: WorkspaceResourceBranchDataProviderManager, - onRefresh: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + onRefresh: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, private readonly resourceProviderManager: WorkspaceResourceProviderManager, branchItemCache: BranchDataItemCache) { super( diff --git a/src/tree/workspace/registerWorkspaceTree.ts b/src/tree/workspace/registerWorkspaceTree.ts index 545afaa6..1f3ba473 100644 --- a/src/tree/workspace/registerWorkspaceTree.ts +++ b/src/tree/workspace/registerWorkspaceTree.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AzExtTreeItem } from '@microsoft/vscode-azext-utils'; +import { AzExtTreeItem, TreeElementBase } from '@microsoft/vscode-azext-utils'; import * as vscode from 'vscode'; import { WorkspaceResourceProviderManager } from '../../api/ResourceProviderManagers'; import { ext } from '../../extensionVariables'; import { localize } from '../../utils/localize'; import { BranchDataItemCache } from '../BranchDataItemCache'; import { createTreeView } from '../createTreeView'; -import { ResourceGroupsItem } from '../ResourceGroupsItem'; import { wrapTreeForVSCode } from '../wrapTreeForVSCode'; import { WorkspaceResourceBranchDataProviderManager } from './WorkspaceResourceBranchDataProviderManager'; import { WorkspaceResourceTreeDataProvider } from './WorkspaceResourceTreeDataProvider'; @@ -18,7 +17,7 @@ import { WorkspaceResourceTreeDataProvider } from './WorkspaceResourceTreeDataPr interface RegisterWorkspaceTreeOptions { workspaceResourceBranchDataProviderManager: WorkspaceResourceBranchDataProviderManager, workspaceResourceProviderManager: WorkspaceResourceProviderManager, - refreshEvent: vscode.Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | undefined>, + refreshEvent: vscode.Event<void | TreeElementBase | TreeElementBase[] | null | undefined>, } export function registerWorkspaceTree(context: vscode.ExtensionContext, options: RegisterWorkspaceTreeOptions): WorkspaceResourceTreeDataProvider { diff --git a/src/tree/wrapTreeForVSCode.ts b/src/tree/wrapTreeForVSCode.ts index 86415afc..121a4fc9 100644 --- a/src/tree/wrapTreeForVSCode.ts +++ b/src/tree/wrapTreeForVSCode.ts @@ -5,7 +5,7 @@ import type { Event, ProviderResult, TreeDataProvider, TreeItem } from "vscode"; import { BranchDataItemCache } from "./BranchDataItemCache"; -import { ResourceGroupsItem } from "./ResourceGroupsItem"; +import { TreeDataItem } from "./ResourceGroupsItem"; import { ResourceTreeDataProviderBase } from "./ResourceTreeDataProviderBase"; /** @@ -18,26 +18,26 @@ export function wrapTreeForVSCode(treeDataProvider: ResourceTreeDataProviderBase /** * Wraps a tree data provider and calls a callback function when the root of the tree is refreshed. */ -class OnRefreshTreeDataProvider implements TreeDataProvider<ResourceGroupsItem> { +class OnRefreshTreeDataProvider implements TreeDataProvider<TreeDataItem> { constructor( - private readonly treeDataProvider: TreeDataProvider<ResourceGroupsItem>, + private readonly treeDataProvider: TreeDataProvider<TreeDataItem>, private readonly onRefresh: () => void, ) { } - getTreeItem(element: ResourceGroupsItem): TreeItem | Thenable<TreeItem> { + getTreeItem(element: TreeDataItem): TreeItem | Thenable<TreeItem> { return this.treeDataProvider.getTreeItem(element); } - getParent(element: ResourceGroupsItem): ProviderResult<ResourceGroupsItem> { + getParent(element: TreeDataItem): ProviderResult<TreeDataItem> { return this.treeDataProvider.getParent?.(element); } - getChildren(element?: ResourceGroupsItem): ProviderResult<ResourceGroupsItem[]> { + getChildren(element?: TreeDataItem): ProviderResult<TreeDataItem[]> { if (!element) { this.onRefresh(); } return this.treeDataProvider.getChildren(element); } - onDidChangeTreeData?: Event<void | ResourceGroupsItem | ResourceGroupsItem[] | null | ResourceGroupsItem> = this.treeDataProvider.onDidChangeTreeData; + onDidChangeTreeData?: Event<void | TreeDataItem | TreeDataItem[] | null | TreeDataItem> = this.treeDataProvider.onDidChangeTreeData; } diff --git a/src/utils/activityUtils.ts b/src/utils/activityUtils.ts index aeabb936..6ce5361c 100644 --- a/src/utils/activityUtils.ts +++ b/src/utils/activityUtils.ts @@ -1,5 +1,5 @@ import { ExecuteActivityContext } from "@microsoft/vscode-azext-utils"; -import { registerActivity } from "../activityLog/registerActivity"; +import { registerActivity } from "../commands/activities/registerActivity"; import { settingUtils } from "./settingUtils"; export async function createActivityContext(): Promise<ExecuteActivityContext> {