Skip to content

Commit 9172624

Browse files
farodin91timja
andauthored
Add job view (#48)
Co-authored-by: Tim Jacomb <[email protected]>
1 parent edbf23d commit 9172624

File tree

26 files changed

+451
-88
lines changed

26 files changed

+451
-88
lines changed

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[*.java]
2+
indent_size = 2
3+
indent_style = space

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>org.jenkins-ci.plugins</groupId>
66
<artifactId>plugin</artifactId>
7-
<version>4.18</version>
7+
<version>4.31</version>
88
<relativePath />
99
</parent>
1010
<groupId>io.jenkins.plugins</groupId>

src/main/frontend/multi-pipeline-graph-view/app.scss

Whitespace-only changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from "react";
2+
import {
3+
FunctionComponent,
4+
} from "react";
5+
6+
import { MultiPipelineGraph } from "./multi-pipeline-graph/main";
7+
8+
import "./app.scss";
9+
import "./multi-pipeline-graph/styles/main.scss";
10+
11+
12+
const App: FunctionComponent = () => {
13+
return (
14+
<div>
15+
<MultiPipelineGraph />
16+
</div>
17+
);
18+
};
19+
20+
export default App;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as React from "react";
2+
import * as ReactDOM from "react-dom";
3+
4+
import App from "./app";
5+
import { resetEnvironment } from "../common/reset-environment";
6+
7+
resetEnvironment();
8+
const root = document.getElementById("multiple-pipeline-root");
9+
ReactDOM.render(<App />, root);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, { useEffect, useState } from "react";
2+
import { RunInfo } from "./MultiPipelineGraphModel";
3+
import startPollingRunsStatus from "./support/startPollingRunsStatus";
4+
import { SingleRun } from "./SingleRun";
5+
6+
export const MultiPipelineGraph = () => {
7+
const [runs, setRuns] = useState<Array<RunInfo>>([]);
8+
const [poll, setPoll] = useState(false);
9+
10+
useEffect(() => {
11+
if (!poll) {
12+
setPoll(true);
13+
startPollingRunsStatus(setRuns, (err) => {
14+
console.log(err);
15+
});
16+
}
17+
}, [runs, poll]);
18+
return (
19+
<table className="jenkins-table sortable">
20+
<thead>
21+
<tr>
22+
<th className="jenkins-table__cell--tight">id</th>
23+
<th data-sort-disable="true">pipeline</th>
24+
</tr>
25+
</thead>
26+
<tbody>
27+
{runs.map((run) => (
28+
<SingleRun key={run.id} run={run} />
29+
))}
30+
</tbody>
31+
</table>
32+
);
33+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface RunInfo {
2+
id: string;
3+
displayName: string;
4+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React, { useState } from "react";
2+
import { RunInfo } from "./MultiPipelineGraphModel";
3+
import {
4+
PipelineGraph,
5+
StageInfo,
6+
} from "../../../pipeline-graph-view/pipeline-graph/main";
7+
8+
interface Props {
9+
run: RunInfo;
10+
}
11+
12+
export const SingleRun: (data: Props) => JSX.Element = ({ run }) => {
13+
const [stages, setStages] = useState<Array<StageInfo>>([]);
14+
const path = `graph?runId=${run.id}`;
15+
const singleRunPage = `../${run.id}`;
16+
17+
const handleNodeClick = (nodeName: string, id: number) => {
18+
console.log(nodeName, id);
19+
window.location.href = `../${
20+
run.id
21+
}/pipeline-console?selected-node=${id}`;
22+
};
23+
return (
24+
<tr>
25+
<td>
26+
<a href={singleRunPage} className="jenkins-table__link">
27+
{run.id}
28+
</a>
29+
</td>
30+
<td>
31+
<PipelineGraph
32+
stages={stages}
33+
setStages={setStages}
34+
onNodeClick={handleNodeClick}
35+
path={path}
36+
collapsed={true}
37+
/>
38+
</td>
39+
</tr>
40+
);
41+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { MultiPipelineGraph } from "./MultiPipelineGraph";
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { RunInfo } from "../MultiPipelineGraphModel";
2+
3+
/**
4+
* Starts polling the server to retrieve pipeline status.
5+
* Will only stop once the run is finished.
6+
*/
7+
export default function startPollingRunsStatus(
8+
onFetchSuccess: (data: Array<RunInfo>) => void,
9+
onFetchError: (err: Error) => void,
10+
interval = 10000
11+
) {
12+
const path = "runs";
13+
async function fetchPipelineData() {
14+
try {
15+
const res = await fetch(path);
16+
const result = await res.json();
17+
onFetchSuccess(result.data);
18+
} catch (err) {
19+
// TODO: implement exponential backoff of the timeout interval
20+
onFetchError(err);
21+
} finally {
22+
setTimeout(() => fetchPipelineData(), interval);
23+
}
24+
}
25+
fetchPipelineData();
26+
}

0 commit comments

Comments
 (0)