Skip to content

Commit d5866e9

Browse files
authored
redhat-developer#342 add context menu and command to show logs (redhat-developer#620)
Signed-off-by: Yevhen Vydolob <[email protected]>
1 parent fb9c474 commit d5866e9

File tree

9 files changed

+93
-9
lines changed

9 files changed

+93
-9
lines changed

package-lock.json

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,7 @@
997997
"codecov": "^3.7.1",
998998
"css-loader": "^5.2.4",
999999
"cytoscape": "^3.14.0",
1000+
"cytoscape-cxtmenu": "^3.4.0",
10001001
"cytoscape-dagre": "^2.2.2",
10011002
"cytoscape-popper": "^2.0.0",
10021003
"decache": "^4.5.1",

src/pipeline/pipeline-graph.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function convertTasksToNode(tasks: PipelineRunTask[], includePositions = true):
120120
tasks.forEach((task: DeclaredTask) => tasksMap.set( task.id, task));
121121

122122
for (const task of tasks) {
123-
result.push({ data: { id: task.id, label: getLabel(task), type: task.kind, taskRef: task.taskRef, state: task.state, yamlPosition: includePositions ? task.position : undefined, final: task.final, steps: task.steps ?? undefined } as NodeData });
123+
result.push({ data: { id: task.id, label: getLabel(task), type: task.kind, taskRef: task.taskRef, state: task.state, yamlPosition: includePositions ? task.position : undefined, final: task.final, steps: task.steps ?? undefined, taskRunName: task.taskRunName } as NodeData });
124124
for (const after of task.runAfter ?? []) {
125125
if (tasksMap.has(after)) {
126126
result.push({ data: { source: after, target: task.id, id: `${after}-${ task.id}`, state: tasksMap.get(after).state } as EdgeData });
@@ -163,15 +163,17 @@ function updatePipelineRunTasks(pipelineRun: PipelineRunData, tasks: DeclaredTas
163163
const runTask = task as PipelineRunTask;
164164

165165
let taskRun: TaskRun | PipelineRunConditionCheckStatus;
166+
let taskRunName: string;
166167
if (task.kind === 'Condition') {
167-
taskRun = findConditionInTaskRun(task.name, taskRuns);
168+
[taskRun, taskRunName] = findConditionInTaskRun(task.name, taskRuns);
168169
} else {
169-
taskRun = findTaskInTaskRun(task.name, taskRuns);
170+
[taskRun, taskRunName] = findTaskInTaskRun(task.name, taskRuns);
170171
}
171172
if (taskRun) {
172173
runTask.completionTime = taskRun.status?.completionTime;
173174
runTask.startTime = taskRun.status?.startTime;
174175
runTask.state = getPipelineRunTaskState(taskRun.status);
176+
runTask.taskRunName = taskRunName;
175177
const steps = (taskRun as TaskRun).status?.steps;
176178
if (steps) {
177179
runTask.stepsCount = steps.length;
@@ -198,27 +200,29 @@ function updatePipelineRunTasks(pipelineRun: PipelineRunData, tasks: DeclaredTas
198200
return tasks as PipelineRunTask[];
199201
}
200202

201-
function findTaskInTaskRun(name: string, taskRuns: TaskRuns): TaskRun | undefined {
203+
function findTaskInTaskRun(name: string, taskRuns: TaskRuns): [TaskRun, string] {
202204
for (const taskRun in taskRuns) {
203205
const element = taskRuns[taskRun];
204206
if (element.pipelineTaskName === name) {
205-
return element;
207+
return [element, taskRun];
206208
}
207209
}
210+
return [undefined, undefined];
208211
}
209212

210-
function findConditionInTaskRun(name: string, taskRuns: TaskRuns): PipelineRunConditionCheckStatus | undefined {
213+
function findConditionInTaskRun(name: string, taskRuns: TaskRuns): [PipelineRunConditionCheckStatus, string] {
211214
for (const taskRun in taskRuns) {
212215
const element = taskRuns[taskRun];
213216
if (element.conditionChecks) {
214217
for (const conditionRunName in element.conditionChecks) {
215218
const condition = element.conditionChecks[conditionRunName];
216219
if (condition.conditionName === name) {
217-
return condition;
220+
return [condition, conditionRunName];
218221
}
219222
}
220223
}
221224
}
225+
return [undefined, undefined];
222226
}
223227

224228
async function getPipelineTaskSteps(document: vscode.TextDocument | VirtualDocument, task: NodeData): Promise<StepData[] | undefined> {

src/pipeline/preview.ts

+8
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { PipelineRunData } from '../tekton';
1414
import { NodeData } from '../webview/pipeline-preview/model';
1515
import { VirtualDocument } from '../yaml-support/yaml-locator';
1616
import { telemetryLogError } from '../telemetry';
17+
import { TaskRun } from '../tekton/taskrun';
1718

1819
export interface PipelinePreviewInput {
1920
readonly document: vscode.TextDocument | VirtualDocument;
@@ -77,6 +78,9 @@ export class PipelinePreview extends Disposable {
7778
case 'getSteps':
7879
this.handleGetSteps(e.body);
7980
break;
81+
case 'showTaskLog':
82+
this.handleShowTaskLog(e.body);
83+
break;
8084
default:
8185
console.error(`Cannot handle message: ${e.type}`);
8286
}
@@ -171,6 +175,10 @@ export class PipelinePreview extends Disposable {
171175

172176
}
173177

178+
private handleShowTaskLog(taskRunName: string): void {
179+
TaskRun.showLogs(taskRunName);
180+
}
181+
174182
private isPreviewOf(resource: vscode.Uri): boolean {
175183
return this.document.uri.fsPath === resource.fsPath;
176184
}

src/tekton/taskrun.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,14 @@ export class TaskRun extends TektonItem {
8080
if (!taskRun) {
8181
return;
8282
}
83+
return TaskRun.showLogs(taskRun.getName());
84+
}
85+
86+
static showLogs(taskRunName: string): void {
8387
if (workspace.getConfiguration('vs-tekton').get('showLogInEditor')) {
84-
showLogInEditor(Command.showTaskRunLogs(taskRun.getName()), `Log: ${taskRun.getName()}`);
88+
showLogInEditor(Command.showTaskRunLogs(taskRunName), `Log: ${taskRunName}`);
8589
} else {
86-
TaskRun.tkn.executeInTerminal(Command.showTaskRunLogs(taskRun.getName()));
90+
TaskRun.tkn.executeInTerminal(Command.showTaskRunLogs(taskRunName));
8791
}
8892
}
8993

src/webview/pipeline-preview/index.ts

+46
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import * as dagre from 'cytoscape-dagre';
99
import { debounce } from 'debounce';
1010
import * as popper from 'cytoscape-popper';
1111
import { TaskPopup } from './task-popup';
12+
import * as cxtmenu from 'cytoscape-cxtmenu';
1213

1314
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1415
declare let acquireVsCodeApi: any;
1516
const vscode = acquireVsCodeApi();
1617
cytoscape.use(dagre); // register extension
1718
cytoscape.use(popper);
19+
cytoscape.use(cxtmenu);
1820

1921
let cy: cytoscape.Core;
2022
const saveState = debounce(() => {
@@ -154,6 +156,48 @@ function startUpdatingState(): void {
154156
}
155157
hoveredId = undefined;
156158
});
159+
160+
const theme = getTheme();
161+
162+
// the default values of each option are outlined below:
163+
const defaults = {
164+
menuRadius: function(){ return 50; }, // the outer radius (node center to the end of the menu) in pixels. It is added to the rendered size of the node. Can either be a number or function as in the example.
165+
selector: 'node[taskRunName]', // elements matching this Cytoscape.js selector will trigger cxtmenus
166+
commands: [ // an array of commands to list in the menu or a function that returns the array
167+
168+
{ // example command
169+
// fillColor: 'rgba(200, 200, 200, 0.75)', // optional: custom background color for item
170+
content: 'Show logs', // html/text content to be displayed in the menu
171+
contentStyle: {}, // css key:value pairs to set the command's css in js if you want
172+
select: function(ele){ // a function to execute when the command is selected
173+
console.error(ele.data().taskRunName) // `ele` holds the reference to the active element
174+
vscode.postMessage({
175+
type: 'showTaskLog',
176+
body: ele.data().taskRunName
177+
});
178+
},
179+
enabled: true // whether the command is selectable
180+
}
181+
182+
], // function( ele ){ return [ /*...*/ ] }, // a function that returns commands or a promise of commands
183+
fillColor: theme.menuBackgroundColor,//'rgba(0, 0, 0, 0.75)', // the background colour of the menu
184+
activeFillColor: theme.menuSelectionColor,//'rgba(1, 105, 217, 0.75)', // the colour used to indicate the selected command
185+
activePadding: 0, // additional size in pixels for the active command
186+
indicatorSize: 24, // the size in pixels of the pointer to the active command, will default to the node size if the node size is smaller than the indicator size,
187+
separatorWidth: 3, // the empty spacing in pixels between successive commands
188+
spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight
189+
adaptativeNodeSpotlightRadius: true, // specify whether the spotlight radius should adapt to the node size
190+
minSpotlightRadius: 24, // the minimum radius in pixels of the spotlight (ignored for the node if adaptativeNodeSpotlightRadius is enabled but still used for the edge & background)
191+
maxSpotlightRadius: 38, // the maximum radius in pixels of the spotlight (ignored for the node if adaptativeNodeSpotlightRadius is enabled but still used for the edge & background)
192+
openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here
193+
itemColor: 'white', // the colour of text in the command's content
194+
itemTextShadowColor: 'transparent', // the text shadow colour of the command's content
195+
zIndex: 9999, // the z-index of the ui div
196+
atMouse: false, // draw menu at mouse position
197+
outsideMenuCancel: 2 // if set to a number, this will cancel the command if the pointer is released outside of the spotlight, padded by the number given
198+
};
199+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
200+
(cy as any).cxtmenu( defaults );
157201
}
158202

159203
function restore(state: object): void {
@@ -209,6 +253,8 @@ function getTheme(): CyTheme {
209253
result.arrowColor = getComputedStyle(document.documentElement).getPropertyValue('--vscode-editor-selectionBackground');
210254
result.targetEdgesColor = getComputedStyle(document.body).getPropertyValue('--vscode-charts-yellow');
211255
result.sourceEdgesColor = getComputedStyle(document.body).getPropertyValue('--vscode-charts-green');
256+
result.menuBackgroundColor = getComputedStyle(document.body).getPropertyValue('--vscode-menu-background');
257+
result.menuSelectionColor = getComputedStyle(document.body).getPropertyValue('--vscode-menu-selectionBackground');
212258
return result;
213259
}
214260

src/webview/pipeline-preview/model.ts

+2
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,6 @@ export interface CyTheme {
8686
fontFamily: string;
8787
targetEdgesColor: string;
8888
sourceEdgesColor: string;
89+
menuBackgroundColor: string;
90+
menuSelectionColor: string;
8991
}

src/yaml-support/tkn-yaml.ts

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface PipelineRunTask extends DeclaredTask {
5353
finishedSteps?: number;
5454
steps?: TaskRunSteps[] | TaskStep[];
5555
retryNumber?: number;
56+
taskRunName?: string;
5657
}
5758

5859

test/pipeline/pipeline-graph.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ suite('Tekton graph', () => {
162162
'state': 'Unknown',
163163
'steps': [],
164164
'taskRef': 'foo-ref',
165+
'taskRunName': 'foo',
165166
'type': 'Task',
166167
'yamlPosition': undefined
167168
}

0 commit comments

Comments
 (0)