Skip to content
Merged
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
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@
"title": "%containerApps.deployContainerApp%",
"category": "Azure Container Apps"
},
{
"command": "containerApps.deployContainerAppWithCopilot",
"title": "%containerApps.deployContainerAppWithCopilot%",
"category": "Azure Container Apps"
},
{
"command": "containerApps.deleteContainerApp",
"title": "%containerApps.deleteContainerApp%",
Expand Down Expand Up @@ -383,6 +388,11 @@
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /containerAppItem(.*)revisionMode:single/i",
"group": "2@1"
},
{
"command": "containerApps.deployContainerAppWithCopilot",
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /containerAppItem(.*)revisionMode:single/i",
"group": "2@2"
},
{
"command": "containerApps.deployRevisionDraft",
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /containerAppItem(.*)revisionMode:single(.*)unsavedChanges:true/i",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"containerApps.deployWorkspaceProject": "Deploy Project from Workspace...",
"containerApps.deployWorkspaceProjectApi": "Deploy Project from Workspace (API)...",
"containerApps.deployContainerApp": "Deploy to Container App...",
"containerApps.deployContainerAppWithCopilot": "Deploy to Container App with Copilot...",
"containerApps.deleteContainerApp": "Delete Container App...",
"containerApps.disableIngress": "Disable Ingress for Container App",
"containerApps.enableIngress": "Enable Ingress for Container App...",
Expand Down
15 changes: 15 additions & 0 deletions src/commands/copilot/deployWithCopilot.ts
Original file line number Diff line number Diff line change
@@ -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 { CopilotUserInput, type IActionContext } from "@microsoft/vscode-azext-utils";
import * as vscode from 'vscode';
import { type ContainerAppItem } from "../../tree/ContainerAppItem";
import { SharedState } from "../../webviews/OpenConfirmationViewStep";
import { deployContainerApp } from "../deployContainerApp/deployContainerApp";

export async function deployWithCopilot(context: IActionContext, node: ContainerAppItem): Promise<void> {
context.ui = new CopilotUserInput(vscode, JSON.stringify(node.viewProperties), () => SharedState.currentPanel);
await deployContainerApp(context, node);
}
31 changes: 21 additions & 10 deletions src/commands/deployContainerApp/deployContainerApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { KnownActiveRevisionsMode } from "@azure/arm-appcontainers";
import { AzureWizard, createSubscriptionContext, nonNullProp, type IActionContext, type ISubscriptionActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils";
import { AzureWizard, CopilotUserInput, createSubscriptionContext, nonNullProp, type AzureWizardPromptStep, type IActionContext, type ISubscriptionActionContext, type ISubscriptionContext } from "@microsoft/vscode-azext-utils";
import { ImageSource } from "../../constants";
import { type ContainerAppItem } from "../../tree/ContainerAppItem";
import { createActivityContext } from "../../utils/activityUtils";
Expand All @@ -14,6 +14,7 @@ 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 { CommandAttributes } from "../CommandAttributes";
import { ContainerAppOverwriteConfirmStep } from "../ContainerAppOverwriteConfirmStep";
import { deployWorkspaceProject } from "../deployWorkspaceProject/deployWorkspaceProject";
Expand Down Expand Up @@ -60,18 +61,28 @@ export async function deployContainerApp(context: IActionContext, node?: Contain
wizardContext.telemetry.properties.revisionMode = item.containerApp.revisionsMode;

const confirmationViewTitle: string = localize('summary', 'Summary');
const confirmationViewDescription: string = localize('viewDescription', 'Please select an input you would like to change. Note: Any input proceeding the changed input may need to change as well');
const confirmationViewTabTitle: string = localize('deployContainerAppTabTitle', 'Summary - Deploy Image to Container App');
const title: string = localize('deployContainerAppTitle', 'Deploy image to container app');
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 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());
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');
confirmationViewTabTitle = localize('deployContainerAppTabTitle', 'Summary - Deploy Image to Container App using Copilot');
title = localize('deployContainerAppWithCopilotTitle', 'Deploy image to container app using copilot');
}

promptSteps.push(
new ContainerAppDeployStartingResourcesLogStep(),
new ImageSourceListStep(),
new ContainerAppOverwriteConfirmStep(),
new OpenConfirmationViewStep(confirmationViewTitle, confirmationViewTabTitle, confirmationViewDescription, title, () => wizard.confirmationViewProperties)
);

const wizard: AzureWizard<ContainerAppDeployContext> = new AzureWizard(wizardContext, {
title: title,
promptSteps: [
new ContainerAppDeployStartingResourcesLogStep(),
new ImageSourceListStep(),
new ContainerAppOverwriteConfirmStep(),
new OpenConfirmationViewStep(confirmationViewTitle, confirmationViewTabTitle, confirmationViewDescription, title, () => wizard.confirmationViewProperties)
],
promptSteps: promptSteps,
executeSteps: [
getVerifyProvidersStep<ContainerAppDeployContext>(),
new ContainerAppUpdateStep(),
Expand Down
2 changes: 2 additions & 0 deletions src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { registerCommand, registerCommandWithTreeNodeUnwrapping, registerErrorHa
import { type EnvironmentVariableItem } from '../tree/containers/EnvironmentVariableItem';
import { deployImageApiCompat } from './api/deployImageApi';
import { browseContainerAppNode } from './browseContainerApp';
import { deployWithCopilot } from './copilot/deployWithCopilot';
import { createContainerApp } from './createContainerApp/createContainerApp';
import { createManagedEnvironment } from './createManagedEnvironment/createManagedEnvironment';
import { deleteContainerApp } from './deleteContainerApp/deleteContainerApp';
Expand Down Expand Up @@ -87,6 +88,7 @@ export function registerCommands(): void {
registerCommandWithTreeNodeUnwrapping('containerApps.deployRevisionDraft', deployRevisionDraft);
registerCommandWithTreeNodeUnwrapping('containerApps.deployWorkspaceProject', deployWorkspaceProject);
registerCommandWithTreeNodeUnwrapping('containerApps.deployContainerApp', deployContainerApp);
registerCommandWithTreeNodeUnwrapping('containerApps.deployContainerAppWithCopilot', deployWithCopilot);

// github
registerCommandWithTreeNodeUnwrapping('containerApps.connectToGitHub', connectToGitHub);
Expand Down
13 changes: 13 additions & 0 deletions src/webviews/LoadingView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Spinner } from "@fluentui/react-components";
import './loadingView.scss';

export const LoadingView = () =>
<div className='loadingView'>
<Spinner labelPosition="below" label="Generating Copilot responses..." />
</div>

18 changes: 18 additions & 0 deletions src/webviews/LoadingViewController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ViewColumn } from "vscode";
import { ext } from "../extensionVariables";
import { WebviewController } from "./extension-server/WebviewController";

export type LoadingViewControllerType = {
title: string;
}

export class LoadingViewController extends WebviewController<LoadingViewControllerType> {
constructor(viewConfiguration: LoadingViewControllerType) {
super(ext.context, viewConfiguration.title, 'loadingView', viewConfiguration, ViewColumn.Active);
}
}
12 changes: 11 additions & 1 deletion src/webviews/OpenConfirmationViewStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureWizardPromptStep, GoBackError, openUrl, UserCancelledError, type ConfirmationViewProperty, type IActionContext } from "@microsoft/vscode-azext-utils";
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 @@ -13,6 +14,7 @@ export const SharedState = {
cancelled: true,
copilotClicked: false,
editingPicks: false,
currentPanel: undefined as WebviewPanel | undefined,
};

export class OpenConfirmationViewStep<T extends IActionContext> extends AzureWizardPromptStep<T> {
Expand All @@ -32,6 +34,11 @@ export class OpenConfirmationViewStep<T extends IActionContext> extends AzureWiz
}

public async prompt(context: T): Promise<void> {
if (SharedState.currentPanel) {
SharedState.currentPanel.dispose();
SharedState.currentPanel = undefined;
}

const confirmationView = new ConfirmationViewController({
title: this.title,
tabTitle: this.tabTitle,
Expand All @@ -48,6 +55,9 @@ export class OpenConfirmationViewStep<T extends IActionContext> extends AzureWiz
if (SharedState.itemsToClear > 0) {
context.telemetry.properties.editingPicks = 'true';
SharedState.editingPicks = true;
if (context.ui instanceof CopilotUserInput) {
context.ui = new AzExtUserInput(context);
}
throw new GoBackError(SharedState.itemsToClear);
}

Expand Down
22 changes: 22 additions & 0 deletions src/webviews/OpenLoadingViewStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* 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 * as vscode from 'vscode';
import { localize } from "../utils/localize";
import { LoadingViewController } from "./LoadingViewController";
import { SharedState } from "./OpenConfirmationViewStep";

export class OpenLoadingViewStep<T extends IActionContext> extends AzureWizardPromptStep<T> {
public async prompt(): Promise<void> {
const loadingView = new LoadingViewController({ title: localize('loadingViewTitle', 'Loading...') });
loadingView.revealToForeground(vscode.ViewColumn.Active);
SharedState.currentPanel = loadingView.panel;
}

public shouldPrompt(): boolean {
return true;
}
}
4 changes: 3 additions & 1 deletion src/webviews/WebviewRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*--------------------------------------------------------------------------------------------*/

import { ConfirmationView } from "./ConfirmationView";
import { LoadingView } from "./LoadingView";

export const WebviewRegistry = {
confirmationView: ConfirmationView
confirmationView: ConfirmationView,
loadingView: LoadingView
} as const;
11 changes: 11 additions & 0 deletions src/webviews/loadingView.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

.loadingView {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}