Skip to content

Commit

Permalink
Group containers by compose project name (#1876)
Browse files Browse the repository at this point in the history
* Group containers by compose project name

* localize description

* Update src/tree/containers/ContainerProperties.ts

Co-Authored-By: Brandon Waterloo [MSFT] <[email protected]>

Co-authored-by: Brandon Waterloo [MSFT] <[email protected]>
  • Loading branch information
ravipal and bwateratmsft authored Apr 20, 2020
1 parent d0b342d commit 7085854
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 7 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,7 @@
"default": "None",
"description": "%vscode-docker.config.docker.containers.groupBy%",
"enum": [
"Compose Project Name",
"ContainerId",
"ContainerName",
"CreatedTime",
Expand Down Expand Up @@ -1599,6 +1600,7 @@
"items": {
"type": "string",
"enum": [
"Compose Project Name",
"ContainerId",
"ContainerName",
"CreatedTime",
Expand All @@ -1621,6 +1623,7 @@
"default": "FullTag",
"description": "%vscode-docker.config.docker.containers.label%",
"enum": [
"Compose Project Name",
"ContainerId",
"ContainerName",
"CreatedTime",
Expand Down
8 changes: 4 additions & 4 deletions src/tree/LocalRootTreeItemBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ export abstract class LocalRootTreeItemBase<TItem extends ILocalItem, TProperty
public sortBySetting: CommonSortBy;
public labelSetting: TProperty;
public descriptionSetting: TProperty[];
protected failedToConnect: boolean = false;

private _currentItems: TItem[] | undefined;
private _itemsFromPolling: TItem[] | undefined;
private _failedToConnect: boolean = false;

public get contextValue(): string {
return this.treePrefix;
Expand Down Expand Up @@ -103,10 +103,10 @@ export abstract class LocalRootTreeItemBase<TItem extends ILocalItem, TProperty
try {
this._currentItems = this._itemsFromPolling || await this.getSortedItems();
this._itemsFromPolling = undefined;
this._failedToConnect = false;
this.failedToConnect = false;
} catch (error) {
this._currentItems = undefined;
this._failedToConnect = true;
this.failedToConnect = true;
context.telemetry.properties.failedToConnect = 'true';
return this.getDockerErrorTreeItems(context, error);
}
Expand Down Expand Up @@ -137,7 +137,7 @@ export abstract class LocalRootTreeItemBase<TItem extends ILocalItem, TProperty
}

public compareChildrenImpl(ti1: AzExtTreeItem, ti2: AzExtTreeItem): number {
if (this._failedToConnect) {
if (this.failedToConnect) {
return 0; // children are already sorted
} else {
if (ti1 instanceof this.childGroupType && ti2 instanceof this.childGroupType) {
Expand Down
1 change: 1 addition & 0 deletions src/tree/containers/ContainerGroupTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class ContainerGroupTreeItem extends LocalGroupTreeItemBase<ILocalContain
break;
case 'Ports':
case 'Status':
case 'Compose Project Name':
icon = 'applicationGroup';
break;
case 'State':
Expand Down
6 changes: 4 additions & 2 deletions src/tree/containers/ContainerProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { localize } from "../../localize";
import { getThemedIconPath, IconPath } from "../IconPath";
import { imageProperties, ImageProperty } from "../images/ImageProperties";
import { ITreePropertyInfo } from "../settings/ITreeSettingInfo";

export type ContainerProperty = ImageProperty | 'ContainerId' | 'ContainerName' | 'Networks' | 'Ports' | 'State' | 'Status';
export type ContainerProperty = ImageProperty | 'Compose Project Name' | 'ContainerId' | 'ContainerName' | 'Networks' | 'Ports' | 'State' | 'Status';

export const containerProperties: ITreePropertyInfo<ContainerProperty>[] = [
...imageProperties,
Expand All @@ -16,7 +17,8 @@ export const containerProperties: ITreePropertyInfo<ContainerProperty>[] = [
{ property: 'Networks', exampleValue: 'mybridge_network' },
{ property: 'Ports', exampleValue: '8080' },
{ property: 'State', exampleValue: 'exited' },
{ property: 'Status', exampleValue: 'Exited (0) 2 hours ago' }
{ property: 'Status', exampleValue: 'Exited (0) 2 hours ago' },
{ property: 'Compose Project Name', description: localize('vscode-docker.tree.containers.properties.composeProjectName', 'Value used to associate containers launched by a \'docker-compose up\' command') },
];

export function getContainerStateIcon(state: string): IconPath {
Expand Down
22 changes: 21 additions & 1 deletion src/tree/containers/ContainersTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ITreeArraySettingInfo, ITreeSettingInfo } from "../settings/ITreeSettin
import { ContainerGroupTreeItem } from "./ContainerGroupTreeItem";
import { containerProperties, ContainerProperty } from "./ContainerProperties";
import { ContainerTreeItem } from "./ContainerTreeItem";
import { ILocalContainerInfo, LocalContainerInfo } from "./LocalContainerInfo";
import { ILocalContainerInfo, LocalContainerInfo, NonComposeGroupName } from "./LocalContainerInfo";

export class ContainersTreeItem extends LocalRootTreeItemBase<ILocalContainerInfo, ContainerProperty> {
public treePrefix: string = 'containers';
Expand Down Expand Up @@ -67,8 +67,28 @@ export class ContainersTreeItem extends LocalRootTreeItemBase<ILocalContainerInf
return item.state;
case 'Status':
return item.status;
case 'Compose Project Name':
return item.composeProjectName;
default:
return getImagePropertyValue(item, property);
}
}

public compareChildrenImpl(ti1: ContainerTreeItem, ti2: ContainerTreeItem): number {
// Override the sorting behavior to keep the non compose group at the bottom when
// grouped by compose project name.
if (this.failedToConnect) {
return 0; // children are already sorted
}
if (this.groupBySetting === 'Compose Project Name'
&& ti1 instanceof this.childGroupType && ti2 instanceof this.childGroupType
&& (ti1.label === NonComposeGroupName || ti2.label === NonComposeGroupName)) {
if (ti1.label === ti2.label) {
return 0;
} else {
return ti1.label === NonComposeGroupName ? 1 : -1;
}
}
return super.compareChildrenImpl(ti1, ti2);
}
}
15 changes: 15 additions & 0 deletions src/tree/containers/LocalContainerInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { ContainerInfo } from "dockerode";
import { localize } from "../../localize";
import { ILocalItem } from "../LocalRootTreeItemBase";

/**
Expand All @@ -18,8 +19,10 @@ export interface ILocalContainerInfo extends ILocalItem {
ports: number[];
state: string;
status: string;
composeProjectName: string;
}

export const NonComposeGroupName = localize('vscode-docker.tree.containers.otherContainers', 'Other Containers');
/**
* Wrapper class for Dockerode item, which has inconsistent names/types
*/
Expand Down Expand Up @@ -75,6 +78,18 @@ export class LocalContainerInfo implements ILocalContainerInfo {
return this.data.Status;
}

public get composeProjectName(): string {
const labels = Object.keys(this.data.Labels)
.map(label => ({ label: label, value: this.data.Labels[label] }));

const composeProject = labels.find(l => l.label === 'com.docker.compose.project');
if (composeProject) {
return composeProject.value;
} else {
return NonComposeGroupName;
}
}

public get treeId(): string {
// include state in treeId so that auto-refresh will detect and show a new icon when state changes
return this.containerId + this.state;
Expand Down

0 comments on commit 7085854

Please sign in to comment.