diff --git a/package-lock.json b/package-lock.json index 56e66c496..9365ffc78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@microsoft/vscode-azext-azureappservice": "^3.6.4", "@microsoft/vscode-azext-azureappsettings": "^0.2.8", "@microsoft/vscode-azext-azureutils": "^3.4.0", - "@microsoft/vscode-azext-utils": "^3.1.1", + "@microsoft/vscode-azext-utils": "^3.2.0", "@microsoft/vscode-azureresources-api": "^2.0.4", "@microsoft/vscode-container-client": "^0.1.2", "cross-fetch": "^4.0.0", diff --git a/package.json b/package.json index 4c3b5cff2..a178a557d 100644 --- a/package.json +++ b/package.json @@ -1484,7 +1484,7 @@ "@microsoft/vscode-azext-azureappservice": "^3.6.4", "@microsoft/vscode-azext-azureappsettings": "^0.2.8", "@microsoft/vscode-azext-azureutils": "^3.4.0", - "@microsoft/vscode-azext-utils": "^3.1.1", + "@microsoft/vscode-azext-utils": "^3.2.0", "@microsoft/vscode-azureresources-api": "^2.0.4", "@microsoft/vscode-container-client": "^0.1.2", "cross-fetch": "^4.0.0", diff --git a/src/commands/appSettings/connectionSettings/durableTaskScheduler/DTSConnectionSetSettingStep.ts b/src/commands/appSettings/connectionSettings/durableTaskScheduler/DTSConnectionSetSettingStep.ts index feaa51ec7..1ce87fe1a 100644 --- a/src/commands/appSettings/connectionSettings/durableTaskScheduler/DTSConnectionSetSettingStep.ts +++ b/src/commands/appSettings/connectionSettings/durableTaskScheduler/DTSConnectionSetSettingStep.ts @@ -3,14 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { nonNullProp } from '@microsoft/vscode-azext-utils'; +import { ActivityChildItem, ActivityChildType, activityFailContext, activityFailIcon, activityProgressContext, activityProgressIcon, activitySuccessContext, activitySuccessIcon, createContextValue, nonNullProp, type ExecuteActivityOutput } from '@microsoft/vscode-azext-utils'; import { ConnectionKey } from '../../../../constants'; +import { localize } from '../../../../localize'; import { clientIdKey } from '../../../durableTaskScheduler/copySchedulerConnectionString'; import { SetConnectionSettingStepBase } from '../SetConnectionSettingStepBase'; import { type IDTSAzureConnectionWizardContext, type IDTSConnectionWizardContext } from './IDTSConnectionWizardContext'; export class DTSConnectionSetSettingStep extends SetConnectionSettingStepBase { public priority: number = 240; + public stepName: string = 'dtsConnectionSetSettingStep'; public debugDeploySetting: ConnectionKey = ConnectionKey.DTS; public async execute(context: T): Promise { @@ -24,4 +26,39 @@ export class DTSConnectionSetSettingStep extends SetConnectionSettingStepBase { public priority: number = 241; + public stepName: string = 'dtsHubNameSetSettingStep'; public debugDeploySetting: ConnectionKey = ConnectionKey.DTSHub; public async execute(context: T): Promise { @@ -19,4 +21,39 @@ export class DTSHubNameSetSettingStep ext public shouldExecute(context: T): boolean { return !!context.newDTSHubNameConnectionSetting; } + + public createSuccessOutput(context: T): ExecuteActivityOutput { + return { + item: new ActivityChildItem({ + label: localize('prepareDTSHubNameLabel', 'Prepare DTS hub connection: "{0}"', context.newDTSHubNameConnectionSetting), + contextValue: createContextValue([`${this.stepName}Item`, activitySuccessContext]), + activityType: ActivityChildType.Success, + iconPath: activitySuccessIcon, + }), + message: localize('prepareDTSHubNameSuccess', 'Successfully prepared DTS hub connection: "{0}".', context.newDTSConnectionSetting), + }; + } + + public createProgressOutput(): ExecuteActivityOutput { + return { + item: new ActivityChildItem({ + label: localize('prepareDTSHubNameProgressLabel', 'Prepare DTS hub connection: "..."'), + contextValue: createContextValue([`${this.stepName}Item`, activityProgressContext]), + activityType: ActivityChildType.Progress, + iconPath: activityProgressIcon, + }), + }; + } + + public createFailOutput(context: T): ExecuteActivityOutput { + return { + item: new ActivityChildItem({ + label: localize('prepareDTSHubNameLabel', 'Prepare DTS hub connection: "{0}"', context.newDTSHubNameConnectionSetting), + contextValue: createContextValue([`${this.stepName}Item`, activitySuccessContext]), + activityType: ActivityChildType.Fail, + iconPath: activityFailIcon, + }), + message: localize('prepareDTSHubNameFail', 'Failed to prepare DTS hub connection: "{0}".', context.newDTSConnectionSetting), + }; + } } diff --git a/src/commands/appSettings/connectionSettings/durableTaskScheduler/IDTSConnectionWizardContext.ts b/src/commands/appSettings/connectionSettings/durableTaskScheduler/IDTSConnectionWizardContext.ts index 43ceb26d8..01614577e 100644 --- a/src/commands/appSettings/connectionSettings/durableTaskScheduler/IDTSConnectionWizardContext.ts +++ b/src/commands/appSettings/connectionSettings/durableTaskScheduler/IDTSConnectionWizardContext.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { type IActionContext } from "@microsoft/vscode-azext-utils"; +import { type ExecuteActivityContext, type IActionContext } from "@microsoft/vscode-azext-utils"; import { type AzureSubscription } from "@microsoft/vscode-azureresources-api"; import { type ConnectionType } from "../../../../constants"; import { type DurableTaskHubResource, type DurableTaskSchedulerResource } from "../../../../tree/durableTaskScheduler/DurableTaskSchedulerClient"; @@ -20,7 +20,7 @@ export interface IDTSConnectionWizardContext extends IActionContext, ISetConnect newDTSHubNameConnectionSetting?: string; } -export interface IDTSAzureConnectionWizardContext extends IFunctionAppUserAssignedIdentitiesContext, IDTSConnectionWizardContext { +export interface IDTSAzureConnectionWizardContext extends IFunctionAppUserAssignedIdentitiesContext, IDTSConnectionWizardContext, Partial { subscription?: AzureSubscription; /** diff --git a/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DTSStartingResourcesLogStep.ts b/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DTSStartingResourcesLogStep.ts new file mode 100644 index 000000000..2f5f83525 --- /dev/null +++ b/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DTSStartingResourcesLogStep.ts @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ActivityChildItem, ActivityChildType, activityInfoContext, activityInfoIcon, AzureWizardPromptStep, createContextValue, prependOrInsertAfterLastInfoChild, type ActivityInfoChild } from "@microsoft/vscode-azext-utils"; +import { ext } from "../../../../../extensionVariables"; +import { localize } from "../../../../../localize"; +import { type IDTSAzureConnectionWizardContext } from "../IDTSConnectionWizardContext"; + +const startingResourcesContext: string = 'startingResourcesLogStepItem'; + +export class DTSStartingResourcesLogStep extends AzureWizardPromptStep { + public hideStepCount: boolean = true; + protected hasLogged: boolean = false; + + public async configureBeforePrompt(context: T): Promise { + if (this.hasLogged) { + return; + } + + if (context.resourceGroup) { + prependOrInsertAfterLastInfoChild(context, + new ActivityChildItem({ + contextValue: createContextValue([startingResourcesContext, activityInfoContext]), + label: localize('useResourceGroup', 'Use resource group "{0}"', context.resourceGroup.name), + activityType: ActivityChildType.Info, + iconPath: activityInfoIcon + }) as ActivityInfoChild + ); + ext.outputChannel.appendLog(localize('usingResourceGroup', 'Using resource group "{0}".', context.resourceGroup.name)); + } + + if (context.site) { + prependOrInsertAfterLastInfoChild(context, + new ActivityChildItem({ + label: localize('useFunctionApp', 'Use function app "{0}"', context.site.fullName), + contextValue: createContextValue([startingResourcesContext, activityInfoContext]), + activityType: ActivityChildType.Info, + iconPath: activityInfoIcon, + }) as ActivityInfoChild, + ); + ext.outputChannel.appendLog(localize('usingFunctionApp', 'Using function app "{0}".', context.site.fullName)); + } + + if (context.dts) { + prependOrInsertAfterLastInfoChild(context, + new ActivityChildItem({ + label: localize('useDTS', 'Use durable task scheduler "{0}"', context.dts.name), + contextValue: createContextValue([startingResourcesContext, activityInfoContext]), + activityType: ActivityChildType.Info, + iconPath: activityInfoIcon + }) as ActivityInfoChild, + ); + ext.outputChannel.appendLog(localize('usingDTS', 'Using durable task scheduler "{0}".', context.dts.name)); + } + + if (context.dtsHub) { + prependOrInsertAfterLastInfoChild(context, + new ActivityChildItem({ + label: localize('useDTSHub', 'Use durable task hub "{0}"', context.dtsHub.name), + contextValue: createContextValue([startingResourcesContext, activityInfoContext]), + activityType: ActivityChildType.Info, + iconPath: activityInfoIcon, + }) as ActivityInfoChild, + ); + ext.outputChannel.appendLog(localize('usingDTSHub', 'Using durable task hub "{0}".', context.dtsHub.name)); + } + + ext.outputChannel.appendLog(localize('prioritizingSiteLocation', 'Prioritizing site location: "{0}".', context.site?.location)); + this.hasLogged = true; + } + + public async prompt(): Promise { + // Don't prompt, just use to log starting resources + } + + public shouldPrompt(): boolean { + return false; + } +} diff --git a/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskHubCreateStep.ts b/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskHubCreateStep.ts index d9699c6bc..3d265e0d9 100644 --- a/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskHubCreateStep.ts +++ b/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskHubCreateStep.ts @@ -3,25 +3,31 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; +import { AzureWizardExecuteStepWithActivityOutput, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; import { type Progress } from "vscode"; import { localize } from "../../../../../localize"; import { HttpDurableTaskSchedulerClient, type DurableTaskSchedulerClient } from "../../../../../tree/durableTaskScheduler/DurableTaskSchedulerClient"; import { type IDTSAzureConnectionWizardContext } from "../IDTSConnectionWizardContext"; -export class DurableTaskHubCreateStep extends AzureWizardExecuteStep { - priority: number = 160; - private readonly schedulerClient: DurableTaskSchedulerClient; +export class DurableTaskHubCreateStep extends AzureWizardExecuteStepWithActivityOutput { + public priority: number = 160; + public stepName: string = 'durableTaskHubCreateStep'; + + protected getOutputLogSuccess = (context: T) => localize('createTaskHubSuccess', 'Created durable task hub "{0}"', context.dtsHub?.name); + protected getOutputLogFail = (context: T) => localize('createTaskHubFail', 'Failed to create durable task hub "{0}"', context.newDTSHubName); + protected getTreeItemLabel = (context: T) => localize('createTaskHubLabel', 'Create durable task hub "{0}"', context.newDTSHubName); + + private readonly _schedulerClient: DurableTaskSchedulerClient; constructor(schedulerClient?: DurableTaskSchedulerClient) { super(); - this.schedulerClient = schedulerClient ?? new HttpDurableTaskSchedulerClient(); + this._schedulerClient = schedulerClient ?? new HttpDurableTaskSchedulerClient(); } public async execute(context: T, progress: Progress<{ message?: string; increment?: number; }>): Promise { progress.report({ message: localize('createTaskHub', 'Creating durable task hub...') }); - context.dtsHub = await this.schedulerClient.createTaskHub( + context.dtsHub = await this._schedulerClient.createTaskHub( nonNullProp(context, 'subscription'), nonNullValueAndProp(context.resourceGroup, 'name'), nonNullValueAndProp(context.dts, 'name'), diff --git a/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskSchedulerCreateStep.ts b/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskSchedulerCreateStep.ts index 8bd4aac27..8ae17d708 100644 --- a/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskSchedulerCreateStep.ts +++ b/src/commands/appSettings/connectionSettings/durableTaskScheduler/azure/DurableTaskSchedulerCreateStep.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { LocationListStep } from "@microsoft/vscode-azext-azureutils"; -import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; +import { ActivityChildItem, ActivityChildType, activityProgressContext, activityProgressIcon, AzureWizardExecuteStepWithActivityOutput, createContextValue, nonNullProp, nonNullValueAndProp, type ExecuteActivityOutput } from "@microsoft/vscode-azext-utils"; import { type Progress } from "vscode"; import { localize } from "../../../../../localize"; import { HttpDurableTaskSchedulerClient, type DurableTaskSchedulerClient } from "../../../../../tree/durableTaskScheduler/DurableTaskSchedulerClient"; @@ -12,19 +12,25 @@ import { withCancellation } from "../../../../../utils/cancellation"; import { getSchedulerConnectionString, SchedulerAuthenticationType } from "../../../../durableTaskScheduler/copySchedulerConnectionString"; import { type IDTSAzureConnectionWizardContext } from "../IDTSConnectionWizardContext"; -export class DurableTaskSchedulerCreateStep extends AzureWizardExecuteStep { - priority: number = 150; - private readonly schedulerClient: DurableTaskSchedulerClient; +export class DurableTaskSchedulerCreateStep extends AzureWizardExecuteStepWithActivityOutput { + public priority: number = 150; + public stepName: string = 'durableTaskSchedulerCreateStep'; + + protected getOutputLogSuccess = (context: T) => localize('createTaskSchedulerSuccess', 'Created durable task scheduler "{0}"', context.dts?.name); + protected getOutputLogFail = (context: T) => localize('createTaskSchedulerFail', 'Failed to create durable task scheduler "{0}"', context.newDTSName); + protected getTreeItemLabel = (context: T) => localize('createTaskSchedulerLabel', 'Create durable task scheduler "{0}"', context.newDTSName); + + private readonly _schedulerClient: DurableTaskSchedulerClient; public constructor(schedulerClient?: DurableTaskSchedulerClient) { super(); - this.schedulerClient = schedulerClient ?? new HttpDurableTaskSchedulerClient(); + this._schedulerClient = schedulerClient ?? new HttpDurableTaskSchedulerClient(); } public async execute(context: T, progress: Progress<{ message?: string; increment?: number; }>): Promise { progress.report({ message: localize('createTaskScheduler', 'Creating durable task scheduler...') }); - const response = (await this.schedulerClient.createScheduler( + const response = (await this._schedulerClient.createScheduler( nonNullProp(context, 'subscription'), nonNullValueAndProp(context.resourceGroup, 'name'), (await LocationListStep.getLocation(context)).name, @@ -44,4 +50,16 @@ export class DurableTaskSchedulerCreateStep = new AzureWizard(wizardContext, { - title: localize('prepareDTSConnection', 'Prepare durable task scheduler connection'), + title: localize('prepareDTSConnection', 'Prepare durable task scheduler connections'), promptSteps: [ new ResourceGroupListStep(), new DTSConnectionListStep(availableDeployConnectionTypes), + new DTSStartingResourcesLogStep(), ], showLoadingPrompt: true, }); diff --git a/src/commands/identity/listUserAssignedIdentities/FunctionAppUserAssignedIdentitiesListStep.ts b/src/commands/identity/listUserAssignedIdentities/FunctionAppUserAssignedIdentitiesListStep.ts index 2a6b182b7..50946ced4 100644 --- a/src/commands/identity/listUserAssignedIdentities/FunctionAppUserAssignedIdentitiesListStep.ts +++ b/src/commands/identity/listUserAssignedIdentities/FunctionAppUserAssignedIdentitiesListStep.ts @@ -6,7 +6,7 @@ import { type ManagedServiceIdentityClient } from '@azure/arm-msi'; import { type ParsedSite } from '@microsoft/vscode-azext-azureappservice'; import { createAuthorizationManagementClient, createManagedServiceIdentityClient, parseAzureResourceId, uiUtils, type ParsedAzureResourceId, type Role } from '@microsoft/vscode-azext-azureutils'; -import { AzureWizardPromptStep, nonNullProp, type IAzureQuickPickItem } from '@microsoft/vscode-azext-utils'; +import { ActivityChildItem, ActivityChildType, activityInfoContext, activityInfoIcon, AzureWizardPromptStep, createContextValue, nonNullProp, prependOrInsertAfterLastInfoChild, type ActivityInfoChild, type IAzureQuickPickItem } from '@microsoft/vscode-azext-utils'; import { ext } from '../../../extensionVariables'; import { localize } from '../../../localize'; import { type IFunctionAppUserAssignedIdentitiesContext } from './IFunctionAppUserAssignedIdentitiesContext'; @@ -72,9 +72,19 @@ export class FunctionAppUserAssignedIdentitiesListStep { diff --git a/src/commands/identity/listUserAssignedIdentities/IFunctionAppUserAssignedIdentitiesContext.ts b/src/commands/identity/listUserAssignedIdentities/IFunctionAppUserAssignedIdentitiesContext.ts index 752cdf625..6de24f97f 100644 --- a/src/commands/identity/listUserAssignedIdentities/IFunctionAppUserAssignedIdentitiesContext.ts +++ b/src/commands/identity/listUserAssignedIdentities/IFunctionAppUserAssignedIdentitiesContext.ts @@ -5,7 +5,8 @@ import { type ParsedSite } from "@microsoft/vscode-azext-azureappservice"; import { type IResourceGroupWizardContext } from "@microsoft/vscode-azext-azureutils"; +import { type ExecuteActivityContext } from "@microsoft/vscode-azext-utils"; -export interface IFunctionAppUserAssignedIdentitiesContext extends IResourceGroupWizardContext { +export interface IFunctionAppUserAssignedIdentitiesContext extends IResourceGroupWizardContext, Partial { site?: ParsedSite; } diff --git a/src/utils/activityUtils.ts b/src/utils/activityUtils.ts index 419702ee4..d22e4ca37 100644 --- a/src/utils/activityUtils.ts +++ b/src/utils/activityUtils.ts @@ -7,9 +7,10 @@ import { type ExecuteActivityContext } from "@microsoft/vscode-azext-utils"; import { ext } from "../extensionVariables"; import { getWorkspaceSetting } from "../vsCodeConfig/settings"; -export async function createActivityContext(): Promise { +export async function createActivityContext(options?: { withChildren?: boolean }): Promise { return { registerActivity: async (activity) => ext.rgApi.registerActivity(activity), suppressNotification: await getWorkspaceSetting('suppressActivityNotifications', undefined, 'azureResourceGroups'), + activityChildren: options?.withChildren ? [] : undefined, }; }