Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

CHE-11443 Implement the containers plugin #13

Merged
merged 3 commits into from
Jan 11, 2019
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
7 changes: 7 additions & 0 deletions extensions/eclipse-che-theia-plugin/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@eclipse-che/api@^6.16.1":
version "6.16.1"
resolved "https://registry.yarnpkg.com/@eclipse-che/api/-/api-6.16.1.tgz#5b5e70285cf27d525df3752c938388e36f7925d6"
3 changes: 3 additions & 0 deletions plugins/containers-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lib/
node_modules/
*.theia
11 changes: 11 additions & 0 deletions plugins/containers-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# containers-plugin

Containers-tree plugin for Theia.

This plugin provides:

- List of containers with their status, where each container provides:

- List of servers (resource locator) if there is any;

- Ability to open a terminal within a selected container;
54 changes: 54 additions & 0 deletions plugins/containers-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "containers-plugin",
"publisher": "theia",
"keywords": [
"theia-plugin"
],
"version": "0.0.1",
"license": "EPL-2.0",
"files": [
"src"
],
"contributes": {
"viewsContainers": {
"right": [
{
"id": "containers",
"title": "Containers"
}
]
},
"views": {
"containers": [
{
"id": "containers",
"name": "Workspace"
}
]
}
},
"devDependencies": {
"@theia/plugin": "next",
"@theia/plugin-packager": "latest",
"@eclipse-che/plugin": "latest",
"rimraf": "2.6.2",
"typescript-formatter": "7.2.2",
"typescript": "2.9.2"
},
"dependencies": {
},
"scripts": {
"prepare": "yarn run clean && yarn run build",
"clean": "rimraf lib",
"format-code": "tsfmt -r",
"watch": "tsc -watch",
"compile": "tsc",
"build": "yarn run format-code && yarn run compile && theia:plugin pack"
},
"engines": {
"theiaPlugin": "next"
},
"theiaPlugin": {
"backend": "lib/containers-plugin.js"
}
}
25 changes: 25 additions & 0 deletions plugins/containers-plugin/src/containers-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { ContainersTreeDataProvider } from './containers-tree-data-provider';
import * as theia from '@theia/plugin';

export function start(context: theia.PluginContext) {
const treeDataProvider = new ContainersTreeDataProvider();
const treeDataDisposableFn = theia.Disposable.create(() => {
treeDataProvider.dispose();
});
context.subscriptions.push(treeDataDisposableFn);

theia.window.createTreeView('containers', { treeDataProvider });
}

export function stop() {
}
69 changes: 69 additions & 0 deletions plugins/containers-plugin/src/containers-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import * as che from '@eclipse-che/plugin';

export interface IContainer {
name: string;
status?: 'STARTING' | 'RUNNING' | 'STOPPED' | 'FAILED';
servers?: {
[serverRef: string]: {
url?: string;
}
};
}

export class ContainersService {
private _containers: Array<IContainer>;

constructor() {
this._containers = [];
}

async updateMachines(): Promise<void> {
const workspace = await che.workspace.getCurrentWorkspace();
if (!workspace) {
return Promise.reject('Failed to get workspace configuration');
}

const workspaceMachines = workspace!.runtime
&& workspace!.runtime!.machines
|| workspace!.config!.environments![workspace.config!.defaultEnv!].machines
|| {};

this._containers.length = 0;
Object.keys(workspaceMachines).forEach((machineName: string) => {
const machine = <{
servers?: {
[serverRef: string]: { url?: string; }
},
status?: 'STARTING' | 'RUNNING' | 'STOPPED' | 'FAILED';
}>workspaceMachines[machineName];
const container: IContainer = {
name: machineName,
status: machine.status
};
if (machine && machine.servers) {
container.servers = {};
Object.keys(machine.servers).forEach((serverName: string) => {
const server = machine!.servers![serverName]!;
if (server && server.url) {
container!.servers![serverName] = { url: server!.url };
}
});
}
this._containers.push(container);
});
}

get containers(): Array<IContainer> {
return this._containers;
}
}
158 changes: 158 additions & 0 deletions plugins/containers-plugin/src/containers-tree-data-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import * as theia from '@theia/plugin';
import { ContainersService, IContainer } from './containers-service';

interface ITreeNodeItem {
id: string;
name: string;
tooltip: string;
iconPath?: string;
parentId?: string;
commandId?: string;
isExpanded?: boolean;
}

export class ContainersTreeDataProvider implements theia.TreeDataProvider<ITreeNodeItem> {
private ids: string[];
private treeNodeItems: ITreeNodeItem[];
private onDidChangeTreeDataEmitter: theia.EventEmitter<undefined>;

readonly onDidChangeTreeData: theia.Event<undefined>;

constructor() {
this.ids = [];
this.treeNodeItems = [];

this.onDidChangeTreeDataEmitter = new theia.EventEmitter<undefined>();
this.onDidChangeTreeData = this.onDidChangeTreeDataEmitter.event;

const containersService = new ContainersService();

this.updateContainersTreeData(containersService).then(() => {
this.onDidChangeTreeDataEmitter.fire();
});
}

private async updateContainersTreeData(containersService: ContainersService): Promise<void> {
this.ids.length = 0;
this.treeNodeItems.length = 0;
await containersService.updateMachines();
containersService.containers.forEach((container: IContainer) => {
const treeItem: ITreeNodeItem = {
id: this.getRandId(),
name: container.name,
tooltip: 'container name',
isExpanded: true
};
switch (container.status) {
case 'STARTING':
treeItem.iconPath = 'fa-circle medium-yellow';
treeItem.tooltip = 'container is STARTING';
break;
case 'RUNNING':
treeItem.iconPath = 'fa-circle medium-green';
treeItem.tooltip = 'container is RUNNING';
break;
case 'FAILED':
treeItem.iconPath = 'fa-circle medium-red';
treeItem.tooltip = 'container is FAILED';
break;
default:
treeItem.iconPath = 'fa-circle-o';
}
this.treeNodeItems.push(treeItem);
this.treeNodeItems.push({
id: this.getRandId(),
parentId: treeItem.id,
name: 'New terminal',
iconPath: 'fa-terminal medium-yellow',
tooltip: `open a new terminal for ${container.name}`,
commandId: `terminal-for-${container.name}-container:new`
});
const servers = container.servers;
if (!servers) {
return;
}
const serverKeys = Object.keys(servers);
if (!serverKeys.length) {
return;
}
const serversId = this.getRandId();
this.treeNodeItems.push({
id: serversId,
parentId: treeItem.id,
name: 'servers',
tooltip: 'servers',
isExpanded: true
});
serverKeys.forEach((serverName: string) => {
const server = servers[serverName];
if (!server) {
return;
}
const treeNodeItem: ITreeNodeItem = {
id: this.getRandId(),
parentId: serversId,
name: serverName,
iconPath: 'fa-info-circle medium-blue',
tooltip: server.url ? server.url : 'server'
};
if (server.url && server.url.startsWith('http')) {
treeNodeItem.name = ` [${serverName}](${server.url})`;
treeNodeItem.iconPath = 'fa-share medium-blue';
}
this.treeNodeItems.push(treeNodeItem);
});
});
}

private getRandId(): string {
let uniqueId = '';
for (let counter = 0; counter < 1000; counter++) {
uniqueId = `${('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)}`;
if (this.ids.findIndex(id => id === uniqueId) === -1) {
break;
}
}
this.ids.push(uniqueId);
return uniqueId;
}

dispose(): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

You could return Disposible here and simplify code upper.

Copy link
Contributor Author

@olexii4 olexii4 Jan 10, 2019

Choose a reason for hiding this comment

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

I don't think so

this.onDidChangeTreeDataEmitter.dispose();
}

getTreeItem(element: ITreeNodeItem): theia.TreeItem {
const treeItem: theia.TreeItem = {
label: element.name,
tooltip: element.tooltip
};
if (element.isExpanded) {
treeItem.collapsibleState = theia.TreeItemCollapsibleState.Expanded;
}
if (element.iconPath) {
treeItem.iconPath = element.iconPath;
}
if (element.commandId) {
treeItem.command = { id: element.commandId };
}
return treeItem;
}

getChildren(element?: ITreeNodeItem): ITreeNodeItem[] {
if (element) {
return this.treeNodeItems.filter(item => item.parentId === element.id);
} else {
return this.treeNodeItems.filter(item => item.parentId === undefined);
}
}
}
23 changes: 23 additions & 0 deletions plugins/containers-plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"noUnusedLocals": true,
"emitDecoratorMetadata": true,
"downlevelIteration": true,
"module": "commonjs",
"moduleResolution": "node",
"target": "es5",
"lib": [
"es6",
"webworker"
],
"sourceMap": true,
"rootDir": "src",
"outDir": "lib"
},
"include": [
"src"
]
}
19 changes: 19 additions & 0 deletions plugins/containers-plugin/tsfmt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"baseIndentSize": 0,
"newLineCharacter": "\n",
"indentSize": 4,
"tabSize": 4,
"indentStyle": 4,
"convertTabsToSpaces": true,
"insertSpaceAfterCommaDelimiter": true,
"insertSpaceAfterSemicolonInForStatements": true,
"insertSpaceBeforeAndAfterBinaryOperators": true,
"insertSpaceAfterKeywordsInControlFlowStatements": true,
"insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
"placeOpenBraceOnNewLineForFunctions": false,
"placeOpenBraceOnNewLineForControlBlocks": false
}

Loading