Skip to content

Commit 12f6c54

Browse files
committed
Add tree elements including the devfile commands in component views #2811
Fixes: #2811 Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com>
1 parent c7c5c3f commit 12f6c54

File tree

6 files changed

+191
-22
lines changed

6 files changed

+191
-22
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,12 @@
495495
"title": "Open in Browser",
496496
"category": "OpenShift"
497497
},
498+
{
499+
"command": "openshift.component.commands.command.run",
500+
"title": "Run Command",
501+
"category": "OpenShift",
502+
"icon": "$(notebook-execute)"
503+
},
498504
{
499505
"command": "openshift.open.developerConsole",
500506
"title": "Open Console Dashboard",
@@ -940,6 +946,10 @@
940946
"command": "openshift.component.followLog",
941947
"when": "view == openshiftProjectExplorer"
942948
},
949+
{
950+
"command": "openshift.component.commands.command.run",
951+
"when": "view == openshiftComponentsView"
952+
},
943953
{
944954
"command": "openshift.open.developerConsole",
945955
"when": "view == openshiftProjectExplorer"
@@ -1486,6 +1496,11 @@
14861496
{
14871497
"command": "openshift.Serverless.stopRun",
14881498
"when": "view == openshiftServerlessFunctionsView && viewItem =~ /^(running)$/"
1499+
},
1500+
{
1501+
"command": "openshift.component.commands.command.run",
1502+
"when": "view == openshiftComponentsView && viewItem =~ /openshift\\-component-command.*\\.dev-run.*/",
1503+
"group": "inline"
14891504
}
14901505
]
14911506
},

src/componentsView.ts

Lines changed: 140 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,140 @@ import * as path from 'path';
77
import * as vsc from 'vscode';
88
import { BaseTreeDataProvider } from './base/baseTreeDataProvider';
99
import { ComponentWorkspaceFolder, OdoWorkspace } from './odo/workspace';
10+
import { Command, CommandProvider } from './odo/componentTypeDescription';
1011
import { Component } from './openshift/component';
1112
import { vsCommand } from './vscommand';
1213

14+
interface ComponentInfo extends ComponentWorkspaceFolder {
15+
getParent(): ComponentInfo;
16+
17+
getChildren() : ComponentInfo[];
18+
19+
toTreeItem() : ComponentWorkspaceFolderTreeItem;
20+
}
21+
22+
abstract class ComponentInfo implements ComponentInfo {
23+
parent : ComponentInfo | null;
24+
25+
constructor(parent : ComponentInfo, folder : ComponentWorkspaceFolder) {
26+
this.parent = parent;
27+
this.component = folder.component;
28+
this.contextPath = folder.contextPath;
29+
}
30+
31+
getParent(): ComponentInfo {
32+
return this.parent;
33+
}
34+
35+
getChildren(): ComponentInfo[] {
36+
return [];
37+
}
38+
}
39+
40+
class ComponentInfoCommand extends ComponentInfo implements CommandProvider {
41+
command :Command;
42+
43+
constructor(parent : ComponentInfo, command : Command) {
44+
super(parent, parent);
45+
this.command = command;
46+
}
47+
48+
getCommand(): Command {
49+
return this.command;
50+
}
51+
52+
toTreeItem() : ComponentWorkspaceFolderTreeItem {
53+
return {
54+
label: this.command.id,
55+
workspaceFolder: this,
56+
tooltip: `Command: ${this.command.id}`,
57+
contextValue: `openshift-component-command${Component.generateContextStateSuffixValue(this)}`,
58+
iconPath: vsc.Uri.file(path.join(__dirname, '../../images/component', 'workspace.png')),
59+
collapsibleState: vsc.TreeItemCollapsibleState.None
60+
};
61+
}
62+
}
63+
64+
class ComponentInfoCommands extends ComponentInfo {
65+
private children : ComponentInfo[];
66+
67+
constructor (parent : ComponentInfo) {
68+
super(parent, parent);
69+
}
70+
71+
getChildren(): ComponentInfo[] {
72+
if (!this.children) {
73+
const thisCommands = this.component.devfileData.devfile.commands;
74+
if (thisCommands === undefined) {
75+
this.children = [];
76+
} else {
77+
this.children = thisCommands.flatMap(c => new ComponentInfoCommand(this, c) );
78+
}
79+
}
80+
return this.children;
81+
}
82+
83+
toTreeItem() : ComponentWorkspaceFolderTreeItem {
84+
return {
85+
label: 'Commands',
86+
workspaceFolder: this,
87+
tooltip: 'Commands',
88+
contextValue: 'openshift-component-commands',
89+
iconPath: vsc.Uri.file(path.join(__dirname, '../../images/component', 'workspace.png')),
90+
collapsibleState: vsc.TreeItemCollapsibleState.Collapsed
91+
};
92+
}
93+
}
94+
95+
class ComponentInfoRoot extends ComponentInfo {
96+
private children : ComponentInfo[];
97+
98+
constructor (folder : ComponentWorkspaceFolder) {
99+
super(null, folder);
100+
}
101+
102+
getParent(): ComponentInfo {
103+
return this;
104+
}
105+
106+
getChildren(): ComponentInfo[] {
107+
if (!this.children) {
108+
const thisCommands = this.component.devfileData.devfile.commands;
109+
if (thisCommands === undefined) {
110+
this.children = [];
111+
} else {
112+
this.children = [ new ComponentInfoCommands(this) ];
113+
}
114+
}
115+
return this.children;
116+
}
117+
118+
toTreeItem() : ComponentWorkspaceFolderTreeItem {
119+
const tooltip = ['Component',
120+
`Name: ${this.component.devfileData.devfile.metadata.name}`,
121+
`Context: ${this.contextPath}`,
122+
].join('\n');
123+
124+
return {
125+
label: Component.renderLabel(this),
126+
workspaceFolder: this,
127+
tooltip,
128+
contextValue: Component.generateContextValue(this),
129+
iconPath: vsc.Uri.file(path.join(__dirname, '../../images/component', 'workspace.png')),
130+
collapsibleState: vsc.TreeItemCollapsibleState.Collapsed
131+
};
132+
}
133+
}
134+
13135
export interface ComponentWorkspaceFolderTreeItem extends vsc.TreeItem {
14136
workspaceFolder: ComponentWorkspaceFolder;
15137
}
16138

17-
export class ComponentsTreeDataProvider extends BaseTreeDataProvider<ComponentWorkspaceFolder> {
139+
export class ComponentsTreeDataProvider extends BaseTreeDataProvider<ComponentInfo> {
18140

19141
static dataProviderInstance: ComponentsTreeDataProvider;
20142
public odoWorkspace = new OdoWorkspace();
143+
private children : ComponentInfo[];
21144

22145
private constructor() {
23146
super();
@@ -30,7 +153,7 @@ export class ComponentsTreeDataProvider extends BaseTreeDataProvider<ComponentWo
30153
private refresh(contextPath?: string): void {
31154
if (contextPath) {
32155
const folder = this.odoWorkspace.findComponent(vsc.workspace.getWorkspaceFolder(vsc.Uri.parse(contextPath)));
33-
this.onDidChangeTreeDataEmitter.fire(folder)
156+
this.onDidChangeTreeDataEmitter.fire(new ComponentInfoRoot(folder));
34157
} else {
35158
this.odoWorkspace.reset();
36159
this.onDidChangeTreeDataEmitter.fire(undefined);
@@ -48,7 +171,7 @@ export class ComponentsTreeDataProvider extends BaseTreeDataProvider<ComponentWo
48171
await vsc.commands.executeCommand('revealInExplorer', vsc.Uri.parse(context.contextPath));
49172
}
50173

51-
createTreeView(id: string): vsc.TreeView<ComponentWorkspaceFolder> {
174+
createTreeView(id: string): vsc.TreeView<ComponentInfo> {
52175
if (!this.treeView) {
53176
this.treeView = vsc.window.createTreeView(id, {
54177
treeDataProvider: this,
@@ -64,25 +187,24 @@ export class ComponentsTreeDataProvider extends BaseTreeDataProvider<ComponentWo
64187
return ComponentsTreeDataProvider.dataProviderInstance;
65188
}
66189

67-
getTreeItem(element: ComponentWorkspaceFolder): ComponentWorkspaceFolderTreeItem {
68-
const tooltip = ['Component',
69-
`Name: ${element.component.devfileData.devfile.metadata.name}`,
70-
`Context: ${element.contextPath}`,
71-
].join('\n');
72-
return {
73-
label: Component.renderLabel(element),
74-
workspaceFolder: element,
75-
tooltip,
76-
contextValue: Component.generateContextValue(element),
77-
iconPath: vsc.Uri.file(path.join(__dirname, '../../images/component', 'workspace.png'))
78-
};
190+
getTreeItem(element: ComponentInfo): ComponentWorkspaceFolderTreeItem {
191+
return element.toTreeItem();
79192
}
80193

81-
getChildren(element?: ComponentWorkspaceFolder): vsc.ProviderResult<ComponentWorkspaceFolder[]> {
82-
const result = element ? [] : this.odoWorkspace.getComponents();
194+
getChildren(element?: ComponentInfo): vsc.ProviderResult<ComponentInfo[]> {
195+
if (element) {
196+
return Promise.resolve(element.getChildren());
197+
}
198+
199+
if (this.children) {
200+
return Promise.resolve(this.children);
201+
}
202+
203+
const result = this.odoWorkspace.getComponents();
83204
return Promise.resolve(result).then(async result1 => {
84205
await vsc.commands.executeCommand('setContext', 'openshift.component.explorer.init', !result1?.length && result1.length === 0);
85-
return result;
206+
this.children = result1.flatMap(f => new ComponentInfoRoot(f));
207+
return this.children;
86208
})
87209
}
88210
}

src/odo/command.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,8 @@ export class Command {
315315
undefined,
316316
[new CommandOption('-o json')]);
317317
}
318+
319+
static runComponentCommand(commandId : string): CommandText {
320+
return new CommandText('odo run', commandId);
321+
}
318322
}

src/odo/componentTypeDescription.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ export interface Command {
125125
id: string;
126126
}
127127

128+
export interface CommandProvider {
129+
getCommand() : Command | undefined
130+
}
131+
128132
export interface Exec {
129133
commandLine: string;
130134
component: string;

src/openshift/component.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import * as YAML from 'yaml';
1313
import { CliChannel } from '../cli';
1414
import { Command } from '../odo/command';
1515
import { ascDevfileFirst, ComponentTypeAdapter, ComponentTypeDescription } from '../odo/componentType';
16-
import { StarterProject } from '../odo/componentTypeDescription';
16+
import { StarterProject, CommandProvider } from '../odo/componentTypeDescription';
1717
import { ComponentWorkspaceFolder } from '../odo/workspace';
1818
import * as odo3 from '../odo3';
1919
import sendTelemetry, { NewComponentCommandProps } from '../telemetry';
@@ -121,7 +121,7 @@ export class Component extends OpenShiftItem {
121121
return state;
122122
}
123123

124-
public static generateContextValue(folder: ComponentWorkspaceFolder): string {
124+
public static generateContextStateSuffixValue(folder: ComponentWorkspaceFolder): string {
125125
const state = Component.componentStates.get(folder.contextPath);
126126
let contextSuffix = '';
127127
if (state.devStatus) {
@@ -133,7 +133,11 @@ export class Component extends OpenShiftItem {
133133
if (state.deployStatus) {
134134
contextSuffix = contextSuffix.concat('.').concat(state.deployStatus);
135135
}
136-
return `openshift.component${contextSuffix}`;
136+
return contextSuffix;
137+
}
138+
139+
public static generateContextValue(folder: ComponentWorkspaceFolder): string {
140+
return `openshift.component${this.generateContextStateSuffixValue(folder)}`;
137141
}
138142

139143
public static renderLabel(folder: ComponentWorkspaceFolder) {
@@ -864,4 +868,24 @@ export class Component extends OpenShiftItem {
864868
}
865869
}
866870
}
871+
872+
@vsCommand('openshift.component.commands.command.run', true)
873+
static runComponentCommand(componentFolder: ComponentWorkspaceFolder): Promise<void> {
874+
const componentName = componentFolder.component.devfileData.devfile.metadata.name;
875+
if ('getCommand' in componentFolder) {
876+
const componentCommand = (<CommandProvider>componentFolder).getCommand();
877+
const command = Command.runComponentCommand(componentCommand.id);
878+
if (Component.isUsingWebviewEditor()) {
879+
DescribeViewLoader.loadView(`Component ${componentName}: Run '${componentCommand.id}' Command`, command, componentFolder);
880+
} else {
881+
void Component.odo.executeInTerminal(
882+
command,
883+
componentFolder.contextPath,
884+
`OpenShift: Component ${componentName}: Run '${componentCommand.id}' Command`);
885+
}
886+
} else {
887+
void window.showErrorMessage(`No Command found in Component '${componentName}`);
888+
}
889+
return;
890+
}
867891
}

0 commit comments

Comments
 (0)