diff --git a/src/commands/AzureWizardActivityOutputExecuteStep.ts b/src/commands/AzureWizardActivityOutputExecuteStep.ts new file mode 100644 index 000000000..3c199e775 --- /dev/null +++ b/src/commands/AzureWizardActivityOutputExecuteStep.ts @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { activityFailContext, activityFailIcon, activityProgressContext, activityProgressIcon, activitySuccessContext, activitySuccessIcon, AzureWizardExecuteStep, createUniversallyUniqueContextValue, GenericParentTreeItem, GenericTreeItem, nonNullValue, type ExecuteActivityOutput, type IActionContext } from "@microsoft/vscode-azext-utils"; + +interface ActivityOutputCreateOptions { + stepName: string; + treeItemLabel: string; + outputLogMessage?: string; + activityStatus: 'Success' | 'Fail' | 'Progress'; +} + +export abstract class AzureWizardActivityOutputExecuteStep extends AzureWizardExecuteStep { + abstract stepName: string; + protected abstract getSuccessString(context: T): string; + protected abstract getFailString(context: T): string; + + protected getProgressString?(context: T): string; + /** + * Optional; define this if you want a special, custom label to be assigned to each tree item + * that is different than the required success or fail strings + */ + protected getTreeItemLabel?(context: T): string; + + public createSuccessOutput(context: T): ExecuteActivityOutput { + const success: string = this.getSuccessString(context); + + return createExecuteActivityOutput(context, { + activityStatus: 'Success', + stepName: this.stepName, + treeItemLabel: this.getTreeItemLabel ? this.getTreeItemLabel(context) : success, + outputLogMessage: success, + }); + } + + public createProgressOutput(context: T): ExecuteActivityOutput { + const progress: string | undefined = this.getProgressString?.(context); + + return createExecuteActivityOutput(context, { + activityStatus: 'Progress', + stepName: this.stepName, + treeItemLabel: this.getTreeItemLabel ? this.getTreeItemLabel(context) : nonNullValue(progress), + outputLogMessage: progress, + }); + } + + public createFailOutput(context: T): ExecuteActivityOutput { + const fail: string = this.getFailString(context); + + return createExecuteActivityOutput(context, { + activityStatus: 'Fail', + stepName: this.stepName, + treeItemLabel: this.getTreeItemLabel ? this.getTreeItemLabel(context) : fail, + outputLogMessage: fail, + }); + } +} + +function createExecuteActivityOutput(_: IActionContext, options: ActivityOutputCreateOptions): ExecuteActivityOutput { + const activityContext = options.activityStatus === 'Success' ? activitySuccessContext : options.activityStatus === 'Fail' ? activityFailContext : activityProgressContext; + const contextValue = createUniversallyUniqueContextValue([`${options.stepName}${options.activityStatus}Item`, activityContext]); + const label = options.treeItemLabel; + const iconPath = options.activityStatus === 'Success' ? activitySuccessIcon : options.activityStatus === 'Fail' ? activityFailIcon : activityProgressIcon; + + const item = options.activityStatus === 'Fail' ? + // Logic is in place to automatically attach an error item as child if thrown during a registered execute step -- therefore, return fails with a parent tree item + new GenericParentTreeItem(undefined, { + contextValue, + label, + iconPath + }) : + new GenericTreeItem(undefined, { + contextValue, + label, + iconPath + }); + + return { + item, + message: options.outputLogMessage, + } +} diff --git a/src/commands/EXECUTE_PRIORITY.md b/src/commands/EXECUTE_PRIORITY.md index d750c8a30..36f189686 100644 --- a/src/commands/EXECUTE_PRIORITY.md +++ b/src/commands/EXECUTE_PRIORITY.md @@ -68,6 +68,7 @@ When creating or updating resources, execute steps should occupy certain priorit #### Steps +- QuickStartImageConfigureStep: 610 - ContainerAppCreateStep: 620 - ContainerAppUpdateStep: 650 diff --git a/src/commands/createContainerApp/ContainerAppCreateStep.ts b/src/commands/createContainerApp/ContainerAppCreateStep.ts index 78df494ed..71879d1a6 100644 --- a/src/commands/createContainerApp/ContainerAppCreateStep.ts +++ b/src/commands/createContainerApp/ContainerAppCreateStep.ts @@ -5,19 +5,24 @@ import { KnownActiveRevisionsMode, type ContainerAppsAPIClient, type Ingress } from "@azure/arm-appcontainers"; import { LocationListStep } from "@microsoft/vscode-azext-azureutils"; -import { AzureWizardExecuteStep, GenericParentTreeItem, GenericTreeItem, activityFailContext, activityFailIcon, activitySuccessContext, activitySuccessIcon, createUniversallyUniqueContextValue, nonNullProp, nonNullValueAndProp, type ExecuteActivityOutput } from "@microsoft/vscode-azext-utils"; +import { nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils"; import { type Progress } from "vscode"; import { containerAppsWebProvider } from "../../constants"; import { ContainerAppItem } from "../../tree/ContainerAppItem"; import { createContainerAppsAPIClient } from "../../utils/azureClients"; import { localize } from "../../utils/localize"; +import { AzureWizardActivityOutputExecuteStep } from "../AzureWizardActivityOutputExecuteStep"; import { getContainerNameForImage } from "../image/imageSource/containerRegistry/getContainerNameForImage"; import { type ContainerAppCreateContext } from "./ContainerAppCreateContext"; -export class ContainerAppCreateStep extends AzureWizardExecuteStep { +export class ContainerAppCreateStep extends AzureWizardActivityOutputExecuteStep { public priority: number = 620; + public stepName: string = 'containerAppCreateStep'; + protected getSuccessString = (context: T) => localize('createContainerAppSuccess', 'Created container app "{0}"', context.newContainerAppName); + protected getFailString = (context: T) => localize('createContainerAppFail', 'Failed to create container app "{0}"', context.newContainerAppName); + protected getTreeItemLabel = (context: T) => localize('createContainerAppLabel', 'Create container app "{0}"', context.newContainerAppName); - public async execute(context: ContainerAppCreateContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { + public async execute(context: T, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise { const appClient: ContainerAppsAPIClient = await createContainerAppsAPIClient(context); const resourceGroupName: string = nonNullValueAndProp(context.resourceGroup, 'name'); @@ -60,29 +65,7 @@ export class ContainerAppCreateStep extends AzureWizardExecuteStep extends AzureWizardActivityOutputExecuteStep { + public priority: number = 610; + public stepName: string = 'quickStartImageConfigureStep'; + protected getSuccessString = () => localize('quickStartImageSuccess', 'Successfully configured quick start image.'); + protected getFailString = () => localize('quickStartImageFail', 'Failed to configure quick start image.'); + protected getTreeItemLabel = () => localize('quickStartImageLabel', 'Configure quick start image'); + + public async execute(context: T): Promise { + context.image = quickStartImageName; + context.enableIngress = true; + context.enableExternal = true; + context.targetPort = 80; + } + + public shouldExecute(context: T): boolean { + return !context.image && context.imageSource === ImageSource.QuickstartImage; + } +} diff --git a/src/commands/createContainerApp/createContainerApp.ts b/src/commands/createContainerApp/createContainerApp.ts index c39baa655..ac4be1393 100644 --- a/src/commands/createContainerApp/createContainerApp.ts +++ b/src/commands/createContainerApp/createContainerApp.ts @@ -16,7 +16,6 @@ import { getVerifyProvidersStep } from "../../utils/getVerifyProvidersStep"; import { localize } from "../../utils/localize"; import { pickEnvironment } from "../../utils/pickItem/pickEnvironment"; import { ImageSourceListStep } from "../image/imageSource/ImageSourceListStep"; -import { IngressPromptStep } from "../ingress/IngressPromptStep"; import { type ContainerAppCreateContext } from "./ContainerAppCreateContext"; import { ContainerAppCreateStep } from "./ContainerAppCreateStep"; import { ContainerAppNameStep } from "./ContainerAppNameStep"; @@ -33,7 +32,7 @@ export async function createContainerApp(context: IActionContext, node?: Managed const wizardContext: ContainerAppCreateContext = { ...context, ...createSubscriptionContext(node.subscription), - ...await createActivityContext(), + ...await createActivityContext(true), subscription: node.subscription, managedEnvironment: node.managedEnvironment, imageSource: ImageSource.QuickstartImage, @@ -55,7 +54,6 @@ export async function createContainerApp(context: IActionContext, node?: Managed promptSteps: [ new ContainerAppNameStep(), new ImageSourceListStep(), - new IngressPromptStep(), ], executeSteps: [ getVerifyProvidersStep(), diff --git a/src/commands/createContainerApp/setQuickStartImage.ts b/src/commands/createContainerApp/setQuickStartImage.ts deleted file mode 100644 index c64755643..000000000 --- a/src/commands/createContainerApp/setQuickStartImage.ts +++ /dev/null @@ -1,14 +0,0 @@ -/*--------------------------------------------------------------------------------------------- -* Copyright (c) Microsoft Corporation. All rights reserved. -* Licensed under the MIT License. See License.md in the project root for license information. -*--------------------------------------------------------------------------------------------*/ - -import { quickStartImageName } from "../../constants"; -import { type ContainerAppCreateContext } from "./ContainerAppCreateContext"; - -export function setQuickStartImage(context: Partial): void { - context.image = quickStartImageName; - context.enableIngress = true; - context.enableExternal = true; - context.targetPort = 80; -} diff --git a/src/commands/image/imageSource/ImageSourceListStep.ts b/src/commands/image/imageSource/ImageSourceListStep.ts index 64832d5cc..b064f6aea 100644 --- a/src/commands/image/imageSource/ImageSourceListStep.ts +++ b/src/commands/image/imageSource/ImageSourceListStep.ts @@ -7,7 +7,7 @@ import { AzureWizardPromptStep, type AzureWizardExecuteStep, type IAzureQuickPic import { UIKind, env, workspace } from "vscode"; import { ImageSource } from "../../../constants"; import { localize } from "../../../utils/localize"; -import { setQuickStartImage } from "../../createContainerApp/setQuickStartImage"; +import { QuickStartImageConfigureStep } from "../../createContainerApp/QuickStartImageConfigureStep"; import { RegistryCredentialsAddConfigurationListStep } from "../../registryCredentials/RegistryCredentialsAddConfigurationListStep"; import { EnvironmentVariablesListStep } from "./EnvironmentVariablesListStep"; import { type ImageSourceContext } from "./ImageSourceContext"; @@ -65,7 +65,7 @@ export class ImageSourceListStep extends AzureWizardPromptStep { +export async function createActivityContext(withChildren?: boolean): Promise { return { registerActivity: async (activity) => (ext.rgApiV2 as AzureResourcesExtensionApiWithActivity).activity.registerActivity(activity), suppressNotification: await settingUtils.getSetting('suppressActivityNotifications', undefined, 'azureResourceGroups'), + activityChildren: withChildren ? [] : undefined, }; }