Skip to content

Commit 0c05a41

Browse files
authored
Add container view to container apps (#673)
* Add Container tree item * Add containers tree items * Add containers items * Add env var and update * Changes * more small changes * requested changes * id changes * change to fix image * fix env var
1 parent 0ade22c commit 0c05a41

File tree

10 files changed

+354
-1
lines changed

10 files changed

+354
-1
lines changed

package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@
277277
"command": "containerApps.walkthrough.cleanUpResources",
278278
"title": "%containerApps.walkthrough.cleanUpResources%",
279279
"category": "Azure Container Apps"
280+
},
281+
{
282+
"command": "containerapps.toggleEnvironmentVariableVisibility",
283+
"title": "%containerapps.toggleEnvironmentVariableVisibility%",
284+
"category": "Azure Container Apps",
285+
"icon": "$(eye)"
280286
}
281287
],
282288
"submenus": [
@@ -526,6 +532,11 @@
526532
"command": "containerApps.disconnectRepo",
527533
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /actionsConnected:true(.*)containerAppsActionsItem/i",
528534
"group": "1@2"
535+
},
536+
{
537+
"command": "containerapps.toggleEnvironmentVariableVisibility",
538+
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /environmentVariableItem/i",
539+
"group": "inline"
529540
}
530541
],
531542
"commandPalette": [

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"containerApps.deploymentConfiguration.containerApp": "The name of the target container app.",
6262
"containerApps.deploymentConfiguration.containerRegistry": "The name of the container registry to use for storing and building images.",
6363
"containerApps.deploymentConfigurations": "A list of saved deployment configurations used for quickly redeploying a workspace project to a container app.",
64+
"containerApp.toggleEnvironmentVariableVisibility": "Toggle Environment Variable Visibility.",
6465
"containerApps.walkthrough.gettingStarted.internal": "Open Walkthrough",
6566
"containerApps.walkthrough.gettingStarted.title": "Getting Started with Azure Container Apps",
6667
"containerApps.walkthrough.gettingStarted.description": "Learn to deploy a containerized application to Azure Container Apps using a sample GitHub repository.",

resources/containers.svg

Lines changed: 33 additions & 0 deletions
Loading

src/commands/registerCommands.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { registerCommand, registerCommandWithTreeNodeUnwrapping, registerErrorHandler, registerReportIssueCommand } from '@microsoft/vscode-azext-utils';
6+
import { registerCommand, registerCommandWithTreeNodeUnwrapping, registerErrorHandler, registerReportIssueCommand, type IActionContext } from '@microsoft/vscode-azext-utils';
7+
import { type EnvironmentVariableItem } from '../tree/containers/EnvironmentVariableItem';
78
import { browseContainerAppNode } from './browseContainerApp';
89
import { createContainerApp } from './createContainerApp/createContainerApp';
910
import { createManagedEnvironment } from './createManagedEnvironment/createManagedEnvironment';
@@ -58,6 +59,10 @@ export function registerCommands(): void {
5859
registerCommandWithTreeNodeUnwrapping('containerApps.editContainerApp', editContainerApp);
5960
registerCommandWithTreeNodeUnwrapping('containerApps.openConsoleInPortal', openConsoleInPortal);
6061
registerCommandWithTreeNodeUnwrapping('containerApps.updateImage', updateImage);
62+
registerCommandWithTreeNodeUnwrapping('containerapps.toggleEnvironmentVariableVisibility',
63+
async (context: IActionContext, item: EnvironmentVariableItem) => {
64+
await item.toggleValueVisibility(context);
65+
});
6166

6267
// deploy
6368
registerCommandWithTreeNodeUnwrapping('containerApps.deployImageApi', deployImageApi);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.md in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type Container, type Revision } from "@azure/arm-appcontainers";
7+
import { nonNullProp, nonNullValue, type TreeElementBase } from "@microsoft/vscode-azext-utils";
8+
import { type AzureSubscription, type ViewPropertiesModel } from "@microsoft/vscode-azureresources-api";
9+
import { TreeItemCollapsibleState, type TreeItem } from "vscode";
10+
import { getParentResource } from "../../utils/revisionDraftUtils";
11+
import { type ContainerAppModel } from "../ContainerAppItem";
12+
import { type RevisionsItemModel } from "../revisionManagement/RevisionItem";
13+
import { EnvironmentVariablesItem } from "./EnvironmentVariablesItem";
14+
import { ImageItem } from "./ImageItem";
15+
16+
export class ContainerItem implements RevisionsItemModel {
17+
id: string;
18+
label: string;
19+
static readonly contextValue: string = 'containerItem';
20+
static readonly contextValueRegExp: RegExp = new RegExp(ContainerItem.contextValue);
21+
22+
constructor(readonly subscription: AzureSubscription, readonly containerApp: ContainerAppModel, readonly revision: Revision, readonly container: Container) {
23+
this.id = `${this.parentResource.id}/${container.name}`;
24+
this.label = nonNullValue(this.container.name);
25+
}
26+
27+
getTreeItem(): TreeItem {
28+
return {
29+
id: this.id,
30+
label: `${this.container.name}`,
31+
contextValue: ContainerItem.contextValue,
32+
collapsibleState: TreeItemCollapsibleState.Collapsed,
33+
}
34+
}
35+
36+
getChildren(): TreeElementBase[] {
37+
return [
38+
new ImageItem(this.subscription, this.containerApp, this.revision, this.id, this.container),
39+
new EnvironmentVariablesItem(this.subscription, this.containerApp, this.revision, this.id, this.container)
40+
];
41+
}
42+
43+
private get parentResource(): ContainerAppModel | Revision {
44+
return getParentResource(this.containerApp, this.revision);
45+
}
46+
47+
viewProperties: ViewPropertiesModel = {
48+
data: this.container,
49+
label: nonNullProp(this.container, 'name'),
50+
}
51+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.md in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { KnownActiveRevisionsMode, type Container, type Revision } from "@azure/arm-appcontainers";
7+
import { nonNullValue, nonNullValueAndProp, type TreeElementBase } from "@microsoft/vscode-azext-utils";
8+
import { type AzureSubscription, type ViewPropertiesModel } from "@microsoft/vscode-azureresources-api";
9+
import * as deepEqual from 'deep-eql';
10+
import { TreeItemCollapsibleState, type TreeItem } from "vscode";
11+
import { ext } from "../../extensionVariables";
12+
import { localize } from "../../utils/localize";
13+
import { getParentResource } from "../../utils/revisionDraftUtils";
14+
import { treeUtils } from "../../utils/treeUtils";
15+
import { type ContainerAppModel } from "../ContainerAppItem";
16+
import { RevisionDraftDescendantBase } from "../revisionManagement/RevisionDraftDescendantBase";
17+
import { RevisionDraftItem } from "../revisionManagement/RevisionDraftItem";
18+
import { ContainerItem } from "./ContainerItem";
19+
import { EnvironmentVariablesItem } from "./EnvironmentVariablesItem";
20+
import { ImageItem } from "./ImageItem";
21+
22+
export class ContainersItem extends RevisionDraftDescendantBase {
23+
id: string;
24+
label: string;
25+
private containers: Container[] = [];
26+
27+
constructor(public readonly subscription: AzureSubscription,
28+
public readonly containerApp: ContainerAppModel,
29+
public readonly revision: Revision,) {
30+
super(subscription, containerApp, revision);
31+
this.id = `${this.parentResource.id}/containers`;
32+
this.containers = nonNullValue(revision.template?.containers);
33+
this.label = this.containers.length === 1 ? localize('container', 'Container') : localize('containers', 'Containers');
34+
}
35+
36+
getChildren(): TreeElementBase[] {
37+
if (this.containers.length === 1) {
38+
return [new ImageItem(this.subscription, this.containerApp, this.revision, this.id, this.containers[0]),
39+
new EnvironmentVariablesItem(this.subscription, this.containerApp, this.revision, this.id, this.containers[0])];
40+
}
41+
return nonNullValue(this.containers?.map(container => new ContainerItem(this.subscription, this.containerApp, this.revision, container)));
42+
}
43+
44+
getTreeItem(): TreeItem {
45+
return {
46+
id: this.id,
47+
label: this.label,
48+
iconPath: treeUtils.getIconPath('containers'),
49+
collapsibleState: TreeItemCollapsibleState.Collapsed
50+
}
51+
}
52+
53+
private get parentResource(): ContainerAppModel | Revision {
54+
return getParentResource(this.containerApp, this.revision);
55+
}
56+
57+
protected setProperties(): void {
58+
this.label = this.containers.length === 1 ? localize('container', 'Container') : localize('containers', 'Containers');
59+
this.containers = nonNullValueAndProp(this.parentResource.template, 'containers');
60+
}
61+
62+
protected setDraftProperties(): void {
63+
this.label = this.containers.length === 1 ? localize('container*', 'Container*') : localize('containers*', 'Containers*');
64+
this.containers = nonNullValueAndProp(ext.revisionDraftFileSystem.parseRevisionDraft(this), 'containers');
65+
}
66+
67+
viewProperties: ViewPropertiesModel = {
68+
label: 'Containers',
69+
getData: async () => {
70+
return this.containers.length === 1 ? this.containers[0] : JSON.stringify(this.containers)
71+
}
72+
}
73+
74+
hasUnsavedChanges(): boolean {
75+
// We only care about showing changes to descendants of the revision draft item when in multiple revisions mode
76+
if (this.containerApp.revisionsMode === KnownActiveRevisionsMode.Multiple && !RevisionDraftItem.hasDescendant(this)) {
77+
return false;
78+
}
79+
80+
const draftTemplate = ext.revisionDraftFileSystem.parseRevisionDraft(this)?.containers;
81+
const currentTemplate = this.parentResource.template?.containers;
82+
83+
if (!draftTemplate) {
84+
return false;
85+
}
86+
87+
return !deepEqual(currentTemplate, draftTemplate);
88+
}
89+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.md in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type Container, type EnvironmentVar, type Revision } from "@azure/arm-appcontainers";
7+
import { type IActionContext } from "@microsoft/vscode-azext-utils";
8+
import { type AzureSubscription } from "@microsoft/vscode-azureresources-api";
9+
import { ThemeIcon, type TreeItem } from "vscode";
10+
import { ext } from "../../extensionVariables";
11+
import { localize } from "../../utils/localize";
12+
import { getParentResource } from "../../utils/revisionDraftUtils";
13+
import { type ContainerAppModel } from "../ContainerAppItem";
14+
import { type RevisionsItemModel } from "../revisionManagement/RevisionItem";
15+
16+
export class EnvironmentVariableItem implements RevisionsItemModel {
17+
_hideValue: boolean;
18+
constructor(public readonly subscription: AzureSubscription,
19+
public readonly containerApp: ContainerAppModel,
20+
public readonly revision: Revision,
21+
readonly containerId: string,
22+
readonly container: Container,
23+
readonly envVariable: EnvironmentVar) {
24+
this._hideValue = true;
25+
}
26+
id: string = `${this.parentResource.id}/${this.container.image}/${this.envVariable.name}`
27+
28+
getTreeItem(): TreeItem {
29+
return {
30+
label: this._hideValue ? `${this.envVariable.name}=Hidden value. Click to view.` : `${this.envVariable.name}=${this.envVariable.value}`,
31+
contextValue: 'environmentVariableItem',
32+
iconPath: new ThemeIcon('symbol-constant'),
33+
command: {
34+
command: 'containerapps.toggleEnvironmentVariableVisibility',
35+
title: localize('commandtitle', 'Toggle Environment Variable Visibility'),
36+
arguments: [this, this._hideValue,]
37+
}
38+
}
39+
}
40+
41+
public async toggleValueVisibility(_: IActionContext): Promise<void> {
42+
this._hideValue = !this._hideValue;
43+
ext.branchDataProvider.refresh(this);
44+
}
45+
46+
private get parentResource(): ContainerAppModel | Revision {
47+
return getParentResource(this.containerApp, this.revision);
48+
}
49+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.md in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type Container, type Revision } from "@azure/arm-appcontainers";
7+
import { type TreeElementBase } from "@microsoft/vscode-azext-utils";
8+
import { type AzureSubscription } from "@microsoft/vscode-azureresources-api";
9+
import { ThemeIcon, TreeItemCollapsibleState, type TreeItem } from "vscode";
10+
import { localize } from "../../utils/localize";
11+
import { getParentResource } from "../../utils/revisionDraftUtils";
12+
import { type ContainerAppModel } from "../ContainerAppItem";
13+
import { type RevisionsItemModel } from "../revisionManagement/RevisionItem";
14+
import { EnvironmentVariableItem } from "./EnvironmentVariableItem";
15+
16+
export class EnvironmentVariablesItem implements RevisionsItemModel {
17+
static readonly contextValue: string = 'environmentVariablesItem';
18+
static readonly contextValueRegExp: RegExp = new RegExp(EnvironmentVariablesItem.contextValue);
19+
20+
constructor(public readonly subscription: AzureSubscription,
21+
public readonly containerApp: ContainerAppModel,
22+
public readonly revision: Revision,
23+
readonly containerId: string,
24+
readonly container: Container) {
25+
}
26+
id: string = `${this.parentResource.id}/environmentVariables/${this.container.image}`;
27+
28+
getTreeItem(): TreeItem {
29+
return {
30+
id: this.id,
31+
label: localize('environmentVariables', 'Environment Variables'),
32+
iconPath: new ThemeIcon('settings'),
33+
contextValue: EnvironmentVariablesItem.contextValue,
34+
collapsibleState: TreeItemCollapsibleState.Collapsed
35+
}
36+
}
37+
38+
getChildren(): TreeElementBase[] | undefined {
39+
if (!this.container.env) {
40+
return;
41+
}
42+
return this.container.env?.map(env => new EnvironmentVariableItem(this.subscription, this.containerApp, this.revision, this.id, this.container, env));
43+
}
44+
45+
private get parentResource(): ContainerAppModel | Revision {
46+
return getParentResource(this.containerApp, this.revision);
47+
}
48+
}

0 commit comments

Comments
 (0)