Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
380 changes: 345 additions & 35 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@
"@fluentui/react-icons": "^2.0.265",
"@microsoft/vscode-azext-azureutils": "^3.5.2",
"@microsoft/vscode-azext-github": "^1.0.7",
"@microsoft/vscode-azext-utils": "^3.5.1",
"@microsoft/vscode-azext-utils": "file:../vscode-azuretools/utils/microsoft-vscode-azext-utils-4.0.2.tgz",
"@microsoft/vscode-azureresources-api": "^2.6.3",
"@vscode/codicons": "0.0.38",
"buffer": "^6.0.3",
Expand Down
12 changes: 10 additions & 2 deletions src/commands/createContainerApp/ContainerAppListStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { type ContainerApp, type ContainerAppsAPIClient } from "@azure/arm-appcontainers";
import { LocationListStep, parseAzureResourceId, ResourceGroupListStep, uiUtils } from "@microsoft/vscode-azext-azureutils";
import { AzureWizardPromptStep, nonNullProp, type AzureWizardExecuteStep, type IAzureQuickPickItem, type IWizardOptions } from "@microsoft/vscode-azext-utils";
import { AzureWizardPromptStep, nonNullProp, nonNullValueAndProp, type AzureWizardExecuteStep, type ConfirmationViewProperty, type IAzureQuickPickItem, type IWizardOptions } from "@microsoft/vscode-azext-utils";
import { containerAppProvider, containerAppResourceType } from "../../constants";
import { ContainerAppItem } from "../../tree/ContainerAppItem";
import { createContainerAppsAPIClient } from "../../utils/azureClients";
Expand Down Expand Up @@ -59,6 +59,14 @@ export class ContainerAppListStep<T extends ContainerAppCreateContext> extends A
return !context.containerApp && !context.newContainerAppName;
}

public confirmationViewProperty(context: T): ConfirmationViewProperty {
return {
name: localize('containerApp', 'Container App'),
value: nonNullValueAndProp(context.containerApp, 'name'),
contextPropertyName: 'containerApp',
}
}

private async getPicks(context: T): Promise<IAzureQuickPickItem<ContainerApp>[]> {
const client: ContainerAppsAPIClient = await createContainerAppsAPIClient(context);

Expand All @@ -72,7 +80,7 @@ export class ContainerAppListStep<T extends ContainerAppCreateContext> extends A
}

if (context.managedEnvironment) {
containerApps = containerApps.filter(ca => ca.managedEnvironmentId === context.managedEnvironment.id);
containerApps = containerApps.filter(ca => ca.managedEnvironmentId === context.managedEnvironment?.id);
}

return containerApps.map(ca => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { type ContainerAppsAPIClient, type ManagedEnvironment } from "@azure/arm
import { type Workspace } from "@azure/arm-operationalinsights";
import { type ResourceGroup } from "@azure/arm-resources";
import { getResourceGroupFromId, LocationListStep, ResourceGroupListStep, uiUtils } from "@microsoft/vscode-azext-azureutils";
import { AzureWizardPromptStep, nonNullProp, type AzureWizardExecuteStep, type IAzureQuickPickItem, type ISubscriptionActionContext, type IWizardOptions } from "@microsoft/vscode-azext-utils";
import { AzureWizardPromptStep, nonNullProp, nonNullValueAndProp, type AzureWizardExecuteStep, type ConfirmationViewProperty, type IAzureQuickPickItem, type ISubscriptionActionContext, type IWizardOptions } from "@microsoft/vscode-azext-utils";
import { logAnalyticsProvider, logAnalyticsResourceType, managedEnvironmentProvider, managedEnvironmentResourceType } from "../../constants";
import { createContainerAppsAPIClient } from "../../utils/azureClients";
import { localize } from "../../utils/localize";
Expand Down Expand Up @@ -57,6 +57,14 @@ export class ManagedEnvironmentListStep<T extends ManagedEnvironmentCreateContex
return !context.managedEnvironment && !context.newManagedEnvironmentName;
}

public confirmationViewProperty(context: T): ConfirmationViewProperty {
return {
name: "Container Apps Environment",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Missed localization

value: nonNullValueAndProp(context.managedEnvironment, 'name'),
contextPropertyName: 'managedEnvironment',
}
}

private async getPicks(context: T): Promise<ManagedEnvironmentPick[]> {
const client: ContainerAppsAPIClient = await createContainerAppsAPIClient(context);

Expand Down
72 changes: 54 additions & 18 deletions src/commands/deployContainerApp/deployContainerApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/

import { KnownActiveRevisionsMode } from "@azure/arm-appcontainers";
import { AzureWizard, CopilotUserInput, createSubscriptionContext, nonNullProp, type AzureWizardPromptStep, type IActionContext, type ISubscriptionActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils";
import { AzureWizard, createSubscriptionContext, nonNullProp, type AzureWizardPromptStep, type IActionContext, type ISubscriptionActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils";
import { type AzureSubscription } from "@microsoft/vscode-azureresources-api";
import { ImageSource } from "../../constants";
import { type ContainerAppItem } from "../../tree/ContainerAppItem";
import { createActivityContext } from "../../utils/activityUtils";
Expand All @@ -14,9 +15,11 @@ import { getVerifyProvidersStep } from "../../utils/getVerifyProvidersStep";
import { localize } from "../../utils/localize";
import { pickContainerApp } from "../../utils/pickItem/pickContainerApp";
import { OpenConfirmationViewStep } from "../../webviews/OpenConfirmationViewStep";
import { OpenLoadingViewStep } from "../../webviews/OpenLoadingViewStep";
import { openLoadingViewPanel } from "../../webviews/OpenLoadingViewStep";
import { CommandAttributes } from "../CommandAttributes";
import { ContainerAppOverwriteConfirmStep } from "../ContainerAppOverwriteConfirmStep";
import { ContainerAppListStep } from "../createContainerApp/ContainerAppListStep";
import { ManagedEnvironmentListStep } from "../createManagedEnvironment/ManagedEnvironmentListStep";
import { deployWorkspaceProject } from "../deployWorkspaceProject/deployWorkspaceProject";
import { type DeployWorkspaceProjectResults } from "../deployWorkspaceProject/getDeployWorkspaceProjectResults";
import { editContainerCommandName } from "../editContainer/editContainer";
Expand Down Expand Up @@ -45,29 +48,58 @@ export async function deployContainerApp(context: IActionContext, node?: Contain
return await deployWorkspaceProject(context, item);
}

const wizardContext: ContainerAppDeployContext = {
...subscriptionActionContext,
...await createActivityContext({ withChildren: true }),
subscription: item.subscription,
containerApp: item.containerApp,
managedEnvironment: await getManagedEnvironmentFromContainerApp(subscriptionActionContext, item.containerApp),
imageSource,
activityAttributes: CommandAttributes.DeployContainerAppContainerRegistry,
};

if (isAzdExtensionInstalled()) {
wizardContext.telemetry.properties.isAzdExtensionInstalled = 'true';
return await deployContainerAppInternal(subscriptionActionContext, item, imageSource);
}

export async function deployContainerAppInternal(context: ISubscriptionActionContext, node?: ContainerAppItem, imageSource?: ImageSource, subscription?: AzureSubscription): Promise<void> {
if (isCopilotUserInput(context)) {
await openLoadingViewPanel(context);
}

const promptSteps: AzureWizardPromptStep<ContainerAppDeployContext>[] = [];

if (!node) {
promptSteps.push(new ManagedEnvironmentListStep(), new ContainerAppListStep());
}

let wizardContext: ContainerAppDeployContext = {} as ContainerAppDeployContext;

if (context.subscriptionId && node && imageSource) {
// If this command gets re run we only want the internal portion of the command to run, so we set the callbackid
context.callbackId = 'containerApps.deployContainerAppInternal';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what this means?

wizardContext = {
...context,
...await createActivityContext({ withChildren: true }),
subscription: node.subscription,
containerApp: node.containerApp,
managedEnvironment: await getManagedEnvironmentFromContainerApp(context, node.containerApp),
imageSource,
activityAttributes: {
...CommandAttributes.DeployContainerAppContainerRegistry,
subscription: node.subscription,
},
};

if (isAzdExtensionInstalled()) {
wizardContext.telemetry.properties.isAzdExtensionInstalled = 'true';
}
wizardContext.telemetry.properties.revisionMode = node.containerApp.revisionsMode;
} else if (context.subscriptionId && subscription) {
wizardContext = {
...context,
...await createActivityContext({ withChildren: true }),
subscription: subscription,
//at the moment we are only supporting re run with container registry image source
imageSource: ImageSource.ContainerRegistry
}
}
wizardContext.telemetry.properties.revisionMode = item.containerApp.revisionsMode;

const confirmationViewTitle: string = localize('summary', 'Summary');
let confirmationViewDescription: string = localize('viewDescription', 'Please select an input you would like to change. Note: Any input proceeding the changed input will need to change as well');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let confirmationViewDescription: string = localize('viewDescription', 'Please select an input you would like to change. Note: Any input proceeding the changed input will need to change as well');
let confirmationViewDescription: string = localize('viewDescription', 'Please select an input you would like to change. Note: Any input preceding the changed input will need to change as well');

let confirmationViewTabTitle: string = localize('deployContainerAppTabTitle', 'Summary - Deploy Image to Container App');
let title: string = localize('deployContainerAppTitle', 'Deploy image to container app');

const promptSteps: AzureWizardPromptStep<ContainerAppDeployContext>[] = []
if (wizardContext.ui instanceof CopilotUserInput) {
promptSteps.push(new OpenLoadingViewStep());
if (isCopilotUserInput(wizardContext)) {
confirmationViewDescription = localize('viewDescription', 'Please review AI generated inputs and select any you would like to modify. Note: Any input proceeding the modified input will need to change as well');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
confirmationViewDescription = localize('viewDescription', 'Please review AI generated inputs and select any you would like to modify. Note: Any input proceeding the modified input will need to change as well');
confirmationViewDescription = localize('viewDescription', 'Please review AI generated inputs and select any you would like to modify. Note: Any input preceding the modified input will need to change as well');

confirmationViewTabTitle = localize('deployContainerAppTabTitle', 'Summary - Deploy Image to Container App using Copilot');
title = localize('deployContainerAppWithCopilotTitle', 'Deploy image to container app using copilot');
Expand Down Expand Up @@ -105,3 +137,7 @@ async function promptImageSource(context: ISubscriptionActionContext): Promise<I

return nonNullProp(promptContext, 'imageSource');
}

function isCopilotUserInput(context: IActionContext): boolean {
return context.ui.constructor.name === 'CopilotUserInput';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do context.ui instanceof CopilotUserInput? I think it's a more robust detection method.

}
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class ContainerAppStartVerificationStep<T extends ContainerAppStartVerifi
throw new Error(invalidName);
}

const workspaceId = context.managedEnvironment.appLogsConfiguration?.logAnalyticsConfiguration?.customerId;
const workspaceId = context.managedEnvironment?.appLogsConfiguration?.logAnalyticsConfiguration?.customerId;
if (!workspaceId) {
return;
}
Expand Down
3 changes: 2 additions & 1 deletion src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { createContainerApp } from './createContainerApp/createContainerApp';
import { createManagedEnvironment } from './createManagedEnvironment/createManagedEnvironment';
import { deleteContainerApp } from './deleteContainerApp/deleteContainerApp';
import { deleteManagedEnvironment } from './deleteManagedEnvironment/deleteManagedEnvironment';
import { deployContainerApp } from './deployContainerApp/deployContainerApp';
import { deployContainerApp, deployContainerAppInternal } from './deployContainerApp/deployContainerApp';
import { deployWorkspaceProject } from './deployWorkspaceProject/deployWorkspaceProject';
import { editContainer } from './editContainer/editContainer';
import { editContainerImage } from './editContainer/editContainerImage/editContainerImage';
Expand Down Expand Up @@ -89,6 +89,7 @@ export function registerCommands(): void {
registerCommandWithTreeNodeUnwrapping('containerApps.deployWorkspaceProject', deployWorkspaceProject);
registerCommandWithTreeNodeUnwrapping('containerApps.deployContainerApp', deployContainerApp);
registerCommandWithTreeNodeUnwrapping('containerApps.deployContainerAppWithCopilot', deployWithCopilot);
registerCommand('containerApps.deployContainerAppInternal', deployContainerAppInternal);

// github
registerCommandWithTreeNodeUnwrapping('containerApps.connectToGitHub', connectToGitHub);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { type RegistryCredentials } from "@azure/arm-appcontainers";
import { type SupportedRegistries } from "../../../constants";
import { type IContainerAppContext } from "../../IContainerAppContext";
import { type CreateAcrContext } from "../../image/imageSource/containerRegistry/acr/createAcr/CreateAcrContext";
import { type ManagedEnvironmentRequiredContext } from "../../ManagedEnvironmentContext";
import { type ManagedEnvironmentContext } from "../../ManagedEnvironmentContext";

export interface ManagedIdentityRegistryCredentialsContext extends CreateAcrContext, ManagedEnvironmentRequiredContext, IContainerAppContext {
export interface ManagedIdentityRegistryCredentialsContext extends CreateAcrContext, ManagedEnvironmentContext, IContainerAppContext {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Context loosened from ManagedEnvironmentRequiredContext → ManagedEnvironmentContext.
This is fine only if all consumers tolerate managedEnvironment being undefined. Worth a quick scan of downstream usage.

registryDomain?: SupportedRegistries;
newRegistryCredential?: RegistryCredentials;
}
3 changes: 1 addition & 2 deletions src/webviews/OpenConfirmationViewStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import { AzExtUserInput, AzureWizardPromptStep, CopilotUserInput, GoBackError, openUrl, UserCancelledError, type ConfirmationViewProperty, type IActionContext } from "@microsoft/vscode-azext-utils";
import * as vscode from 'vscode';
import { type WebviewPanel } from 'vscode';
import { localize } from "../utils/localize";
import { ConfirmationViewController } from "./ConfirmationViewController";

Expand All @@ -14,7 +13,7 @@ export const SharedState = {
cancelled: true,
copilotClicked: false,
editingPicks: false,
currentPanel: undefined as WebviewPanel | undefined,
currentPanel: undefined as vscode.WebviewPanel | undefined,
};

export class OpenConfirmationViewStep<T extends IActionContext> extends AzureWizardPromptStep<T> {
Expand Down
10 changes: 9 additions & 1 deletion src/webviews/OpenLoadingViewStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureWizardPromptStep, type IActionContext } from "@microsoft/vscode-azext-utils";
import { AzureWizardPromptStep, runGenericPromptStep, type IActionContext } from "@microsoft/vscode-azext-utils";
import * as vscode from 'vscode';
import { localize } from "../utils/localize";
import { LoadingViewController } from "./LoadingViewController";
Expand All @@ -20,3 +20,11 @@ export class OpenLoadingViewStep<T extends IActionContext> extends AzureWizardPr
return true;
}
}

export async function openLoadingViewPanel(context: IActionContext): Promise<void> {
const promptSteps: AzureWizardPromptStep<IActionContext>[] = [new OpenLoadingViewStep<IActionContext>()];

return await runGenericPromptStep(context, {
promptSteps
});
}
Loading