From b79710d5ddda7e2edac3fb0126ac5a4ec7ef8694 Mon Sep 17 00:00:00 2001 From: MicroFish91 <40250218+MicroFish91@users.noreply.github.com> Date: Mon, 8 Dec 2025 17:28:42 -0800 Subject: [PATCH 1/4] First pass --- .../FunctionAppHostingPlanStep.ts | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts b/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts index f443a9289..bfcf63e5b 100644 --- a/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts +++ b/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts @@ -8,20 +8,18 @@ import { createHttpHeaders, createPipelineRequest } from '@azure/core-rest-pipel import { setLocationsTask, WebsiteOS, type IAppServiceWizardContext } from '@microsoft/vscode-azext-azureappservice'; import { createGenericClient, LocationListStep, type AzExtPipelineResponse, type AzExtRequestPrepareOptions } from '@microsoft/vscode-azext-azureutils'; import { AzureWizardPromptStep, type IAzureQuickPickItem } from '@microsoft/vscode-azext-utils'; -import { DurableBackend } from '../../constants'; import { localize } from '../../localize'; import { getRandomHexString } from '../../utils/fs'; import { nonNullProp } from '../../utils/nonNull'; import { type IFunctionAppWizardContext } from './IFunctionAppWizardContext'; -const premiumSkuFilter = /^EP$/i; export class FunctionAppHostingPlanStep extends AzureWizardPromptStep { public async prompt(context: IFunctionAppWizardContext): Promise { const placeHolder: string = localize('selectHostingPlan', 'Select a hosting plan.'); const picks: IAzureQuickPickItem<[boolean, boolean, RegExp | undefined]>[] = [ { label: localize('flexConsumption', 'Flex Consumption'), data: [false, true, undefined] }, { label: localize('consumption', 'Consumption'), description: localize('legacy', 'Legacy'), data: [true, false, undefined] }, - { label: localize('premium', 'Premium'), data: [false, false, premiumSkuFilter] }, + { label: localize('premium', 'Premium'), data: [false, false, /^EP$/i] }, { label: localize('dedicated', 'App Service Plan'), data: [false, false, /^((?!EP|Y|FC).)*$/i] } ]; @@ -35,19 +33,11 @@ export class FunctionAppHostingPlanStep extends AzureWizardPromptStep { - if (context.durableStorageType === DurableBackend.DTS) { - // premium is required for DTS - if (context.advancedCreation) { - // allows users to select/create a Elastic Premium plan - context.planSkuFamilyFilter = premiumSkuFilter; - } else { - setPremiumPlanProperties(context); - } - } else if (context.useFlexConsumptionPlan) { + if (context.useFlexConsumptionPlan) { setFlexConsumptionPlanProperties(context); } } @@ -66,16 +56,6 @@ function setFlexConsumptionPlanProperties(context: IAppServiceWizardContext): vo LocationListStep.setLocationSubset(context, getFlexLocations(context), 'Microsoft.WebFlex'); } -function setPremiumPlanProperties(context: IAppServiceWizardContext): void { - context.newPlanName = `PREMIUM-${nonNullProp(context, 'newSiteName')}-${getRandomHexString(4)}`; - context.newPlanSku = { - name: 'P1v2', - tier: 'Premium V2', - size: 'P1v2', - family: 'Pv2' - }; -} - async function getFlexLocations(context: IAppServiceWizardContext): Promise { const headers = createHttpHeaders({ 'Content-Type': 'application/json', From 9e2d2502248f52b3472b62472c247edd9a16dc27 Mon Sep 17 00:00:00 2001 From: MicroFish91 <40250218+MicroFish91@users.noreply.github.com> Date: Mon, 8 Dec 2025 18:22:51 -0800 Subject: [PATCH 2/4] WIP --- .../FunctionAppHostingPlanStep.ts | 36 ++++++++++++++----- .../createCreateFunctionAppComponents.ts | 23 ++++++++++-- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts b/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts index bfcf63e5b..542e25923 100644 --- a/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts +++ b/src/commands/createFunctionApp/FunctionAppHostingPlanStep.ts @@ -13,16 +13,36 @@ import { getRandomHexString } from '../../utils/fs'; import { nonNullProp } from '../../utils/nonNull'; import { type IFunctionAppWizardContext } from './IFunctionAppWizardContext'; +export enum FunctionAppHostingPlans { + Flex, + Consumption, + Premium, + AppService, +} + +export const allAvailableFunctionAppHostingPlans = new Set([FunctionAppHostingPlans.Flex, FunctionAppHostingPlans.Consumption, FunctionAppHostingPlans.Premium, FunctionAppHostingPlans.AppService]); + export class FunctionAppHostingPlanStep extends AzureWizardPromptStep { + constructor(private readonly availablePlans: Set) { + super(); + } + public async prompt(context: IFunctionAppWizardContext): Promise { - const placeHolder: string = localize('selectHostingPlan', 'Select a hosting plan.'); - const picks: IAzureQuickPickItem<[boolean, boolean, RegExp | undefined]>[] = [ - { label: localize('flexConsumption', 'Flex Consumption'), data: [false, true, undefined] }, - { label: localize('consumption', 'Consumption'), description: localize('legacy', 'Legacy'), data: [true, false, undefined] }, - { label: localize('premium', 'Premium'), data: [false, false, /^EP$/i] }, - { label: localize('dedicated', 'App Service Plan'), data: [false, false, /^((?!EP|Y|FC).)*$/i] } - ]; + const picks: IAzureQuickPickItem<[boolean, boolean, RegExp | undefined]>[] = []; + if (this.availablePlans.has(FunctionAppHostingPlans.Flex)) { + picks.push({ label: localize('flexConsumption', 'Flex Consumption'), data: [false, true, undefined] }); + } + if (this.availablePlans.has(FunctionAppHostingPlans.Consumption)) { + picks.push({ label: localize('consumption', 'Consumption'), description: localize('legacy', 'Legacy'), data: [true, false, undefined] }); + } + if (this.availablePlans.has(FunctionAppHostingPlans.Premium)) { + picks.push({ label: localize('premium', 'Premium'), data: [false, false, /^EP$/i] }); + } + if (this.availablePlans.has(FunctionAppHostingPlans.AppService)) { + picks.push({ label: localize('dedicated', 'App Service Plan'), data: [false, false, /^((?!EP|Y|FC).)*$/i] }); + } + const placeHolder: string = localize('selectHostingPlan', 'Select a hosting plan.'); [context.useConsumptionPlan, context.useFlexConsumptionPlan, context.planSkuFamilyFilter] = (await context.ui.showQuickPick(picks, { placeHolder, learnMoreLink: 'aka.ms/flexconsumption' })).data; await setLocationsTask(context); if (context.useConsumptionPlan) { @@ -33,7 +53,7 @@ export class FunctionAppHostingPlanStep extends AzureWizardPromptStep { diff --git a/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts b/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts index d11c637a3..b8663831d 100644 --- a/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts +++ b/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts @@ -7,7 +7,7 @@ import { AppInsightsCreateStep, AppInsightsListStep, AppKind, AppServicePlanCrea import { CommonRoleDefinitions, createRoleId, LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep, RoleAssignmentExecuteStep, StorageAccountCreateStep, StorageAccountKind, StorageAccountListStep, StorageAccountPerformance, StorageAccountReplication, type INewStorageAccountDefaults, type Role } from "@microsoft/vscode-azext-azureutils"; import { type AzureWizardExecuteStep, type AzureWizardPromptStep, type ISubscriptionContext } from "@microsoft/vscode-azext-utils"; import { FuncVersion, latestGAVersion, tryParseFuncVersion } from "../../FuncVersion"; -import { funcVersionSetting } from "../../constants"; +import { DurableBackend, funcVersionSetting } from "../../constants"; import { tryGetLocalFuncVersion } from "../../funcCoreTools/tryGetLocalFuncVersion"; import { type ICreateFunctionAppContext } from "../../tree/SubscriptionTreeItem"; import { createActivityContext } from "../../utils/activityUtils"; @@ -15,7 +15,7 @@ import { durableUtils } from "../../utils/durableUtils"; import { getRootFunctionsWorkerRuntime, getWorkspaceSetting, getWorkspaceSettingFromAnyFolder } from "../../vsCodeConfig/settings"; import { AuthenticationPromptStep } from "./AuthenticationPromptStep"; import { FunctionAppCreateStep } from "./FunctionAppCreateStep"; -import { FunctionAppHostingPlanStep } from "./FunctionAppHostingPlanStep"; +import { allAvailableFunctionAppHostingPlans, FunctionAppHostingPlans, FunctionAppHostingPlanStep } from "./FunctionAppHostingPlanStep"; import { type IFunctionAppWizardContext } from "./IFunctionAppWizardContext"; import { ConfigureCommonNamesStep } from "./UniqueNamePromptStep"; import { ContainerizedFunctionAppCreateStep } from "./containerImage/ContainerizedFunctionAppCreateStep"; @@ -150,7 +150,9 @@ async function createFunctionAppWizard(wizardContext: IFunctionAppWizardContext) const promptSteps: AzureWizardPromptStep[] = []; const executeSteps: AzureWizardExecuteStep[] = []; - promptSteps.push(new FunctionAppHostingPlanStep()); + promptSteps.push(new FunctionAppHostingPlanStep( + getAvailableFunctionAppHostingPlans(wizardContext) /** availablePlans */, + )); CustomLocationListStep.addStep(wizardContext, promptSteps); promptSteps.push(new FunctionAppStackStep()); @@ -177,3 +179,18 @@ async function createContainerizedFunctionAppWizard(): Promise<{ promptSteps: Az return { promptSteps, executeSteps }; } + +function getAvailableFunctionAppHostingPlans(context: IFunctionAppWizardContext): Set { + const availablePlans: Set = new Set(); + + if (context.useFlexConsumptionPlan) { + availablePlans.add(FunctionAppHostingPlans.Flex); + } if (context.durableStorageType === DurableBackend.DTS) { + if (context.advancedCreation) { + availablePlans.add(FunctionAppHostingPlans.Premium); + } + availablePlans.add(FunctionAppHostingPlans.Flex); + } + + return availablePlans.size ? availablePlans : allAvailableFunctionAppHostingPlans; +} From 0dd990c172f2a56dbcad1794a03809cbc95b6ce2 Mon Sep 17 00:00:00 2001 From: MicroFish91 <40250218+MicroFish91@users.noreply.github.com> Date: Mon, 8 Dec 2025 18:47:58 -0800 Subject: [PATCH 3/4] Inject available plans --- .../createFunctionApp/createCreateFunctionAppComponents.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts b/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts index b8663831d..269d5868c 100644 --- a/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts +++ b/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts @@ -185,7 +185,7 @@ function getAvailableFunctionAppHostingPlans(context: IFunctionAppWizardContext) if (context.useFlexConsumptionPlan) { availablePlans.add(FunctionAppHostingPlans.Flex); - } if (context.durableStorageType === DurableBackend.DTS) { + } else if (context.durableStorageType === DurableBackend.DTS) { if (context.advancedCreation) { availablePlans.add(FunctionAppHostingPlans.Premium); } From 8738f30cf0415b80cc3caf7533906b63246e5875 Mon Sep 17 00:00:00 2001 From: MicroFish91 <40250218+MicroFish91@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:01:09 -0800 Subject: [PATCH 4/4] Update available plans --- .../createCreateFunctionAppComponents.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts b/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts index 269d5868c..66c3fd425 100644 --- a/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts +++ b/src/commands/createFunctionApp/createCreateFunctionAppComponents.ts @@ -183,14 +183,21 @@ async function createContainerizedFunctionAppWizard(): Promise<{ promptSteps: Az function getAvailableFunctionAppHostingPlans(context: IFunctionAppWizardContext): Set { const availablePlans: Set = new Set(); - if (context.useFlexConsumptionPlan) { - availablePlans.add(FunctionAppHostingPlans.Flex); - } else if (context.durableStorageType === DurableBackend.DTS) { - if (context.advancedCreation) { - availablePlans.add(FunctionAppHostingPlans.Premium); - } - availablePlans.add(FunctionAppHostingPlans.Flex); + switch (true) { + case context.useFlexConsumptionPlan: + availablePlans.add(FunctionAppHostingPlans.Flex); + break; + + case context.durableStorageType === DurableBackend.DTS: + if (context.advancedCreation) { + availablePlans.add(FunctionAppHostingPlans.Premium); + } + availablePlans.add(FunctionAppHostingPlans.Flex); + break; + + default: + return allAvailableFunctionAppHostingPlans; } - return availablePlans.size ? availablePlans : allAvailableFunctionAppHostingPlans; + return availablePlans; }