Skip to content

Commit 98f212e

Browse files
janfaraciktimja
andauthored
Update node symbols (#578)
Co-authored-by: Tim Jacomb <[email protected]> Co-authored-by: Tim Jacomb <[email protected]>
1 parent 2dbb349 commit 98f212e

File tree

23 files changed

+223
-418
lines changed

23 files changed

+223
-418
lines changed

src/main/frontend/multi-pipeline-graph-view/multi-pipeline-graph/main/SingleRun.tsx

-9
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ export const SingleRun: (data: Props) => JSX.Element = ({ run }) => {
2525
singleRunPage = `${run.id}/pipeline-graph/`;
2626
}
2727

28-
const handleNodeClick = (nodeName: string, id: number) => {
29-
console.log(nodeName, id);
30-
let redirect = `../${run.id}/pipeline-console?selected-node=${id}`;
31-
if (onJobView) {
32-
redirect = `${run.id}/pipeline-console?selected-node=${id}`;
33-
}
34-
window.location.href = redirect;
35-
};
3628
return (
3729
<tr>
3830
<td>
@@ -47,7 +39,6 @@ export const SingleRun: (data: Props) => JSX.Element = ({ run }) => {
4739
<PipelineGraph
4840
stages={stages}
4941
setStages={setStages}
50-
onNodeClick={handleNodeClick}
5142
path={path}
5243
collapsed={true}
5344
/>

src/main/frontend/pipeline-console-view/pipeline-console/main/PipelineConsoleModel.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export type {
1212
} from "../../../pipeline-graph-view/pipeline-graph/main/PipelineGraphModel";
1313
export { default as startPollingPipelineStatus } from "../../../pipeline-graph-view/pipeline-graph/main/support/startPollingPipelineStatus";
1414
export { pollUntilComplete } from "../../../common/Poller";
15-
export { getGroupForResult } from "../../../pipeline-graph-view/pipeline-graph/main/support/StatusIcons";
15+
export { getSymbolForResult } from "../../../pipeline-graph-view/pipeline-graph/main/support/StatusIcons";
1616
export * from "../../../common/RestClient";
1717

1818
export const LOG_FETCH_SIZE = 150 * 1024;

src/main/frontend/pipeline-console-view/pipeline-console/main/TestData.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const defaultStagesList: StageInfo[] = [
1212
startTimeMillis: "",
1313
totalDurationMillis: "",
1414
agent: "built-in",
15+
url: "?selected-node=0",
1516
},
1617
{
1718
name: "Stage B",
@@ -25,6 +26,7 @@ export const defaultStagesList: StageInfo[] = [
2526
startTimeMillis: "",
2627
totalDurationMillis: "",
2728
agent: "not-built-in",
29+
url: "?selected-node=1",
2830
},
2931
{
3032
name: "Parent C",
@@ -46,12 +48,14 @@ export const defaultStagesList: StageInfo[] = [
4648
startTimeMillis: "",
4749
totalDurationMillis: "",
4850
agent: "not-built-in",
51+
url: "?selected-node=3",
4952
},
5053
],
5154
pauseDurationMillis: "",
5255
startTimeMillis: "",
5356
totalDurationMillis: "",
5457
agent: "built-in",
58+
url: "?selected-node=2",
5559
},
5660
];
5761

src/main/frontend/pipeline-console-view/pipeline-console/main/pipeline-console.scss

-6
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,6 @@ g.build-status-icon__outer {
220220
padding: unset;
221221
}
222222

223-
.jenkins-button svg {
224-
width: 20px !important;
225-
height: 20px !important;
226-
color: currentColor !important;
227-
}
228-
229223
.svg-icon {
230224
// Force rotating icons to rotate about their center.
231225
transform-origin: center;

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

-6
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@
4040
}
4141
}
4242

43-
.jenkins-button svg {
44-
width: 20px !important;
45-
height: 20px !important;
46-
color: currentColor !important;
47-
}
48-
4943
.app-details__prev_next {
5044
color: inherit !important;
5145
text-decoration: none !important;

src/main/frontend/pipeline-graph-view/app.tsx

+1-15
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,10 @@ import { PipelineGraph } from "./pipeline-graph/main";
66
import "./app.scss";
77
import "./pipeline-graph/styles/main.scss";
88

9-
function handleNodeClick(nodeName: string, id: number) {
10-
let location = `../pipeline-console?selected-node=${id}`;
11-
const url = new URL(window.location.href);
12-
if (!url.pathname.endsWith("pipeline-graph/")) {
13-
location = `pipeline-console?selected-node=${id}`;
14-
}
15-
16-
window.location.href = location;
17-
}
18-
199
const App: FunctionComponent = () => {
2010
return (
2111
<div>
22-
<PipelineGraph
23-
stages={[]}
24-
onNodeClick={handleNodeClick}
25-
collapsed={false}
26-
/>
12+
<PipelineGraph stages={[]} collapsed={false} />
2713
</div>
2814
);
2915
};

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraph.tsx

+3-25
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
NodeLabelInfo,
88
LayoutInfo,
99
NodeColumn,
10-
NodeInfo,
1110
StageInfo,
1211
} from "./PipelineGraphModel";
1312
import { layoutGraph } from "./PipelineGraphLayout";
@@ -24,7 +23,6 @@ interface Props {
2423
stages: Array<StageInfo>;
2524
layout?: Partial<LayoutInfo>;
2625
setStages?: (stages: Array<StageInfo>) => void;
27-
onNodeClick?: (nodeName: string, id: number) => void;
2826
selectedStage?: StageInfo;
2927
path?: string;
3028
collapsed?: boolean;
@@ -145,20 +143,6 @@ export class PipelineGraph extends React.Component {
145143
return (selectedStage && stage && selectedStage.id === stage.id) || false;
146144
};
147145

148-
private handleNodeClick = (node: NodeInfo) => {
149-
if (node.isPlaceholder === false && node.stage.state !== "skipped") {
150-
const stage = node.stage;
151-
const listener = this.props.onNodeClick;
152-
153-
if (listener) {
154-
listener(stage.name, stage.id);
155-
}
156-
157-
// Update selection
158-
this.setState({ selectedStage: stage });
159-
}
160-
};
161-
162146
render() {
163147
const {
164148
nodeColumns,
@@ -194,22 +178,16 @@ export class PipelineGraph extends React.Component {
194178
layout={this.state.layout}
195179
/>
196180

197-
{nodes.map((node) => (
198-
<Node
199-
key={node.id}
200-
node={node}
201-
layout={this.state.layout}
202-
onClick={this.handleNodeClick}
203-
isStageSelected={this.stageIsSelected}
204-
/>
205-
))}
206181
<SelectionHighlight
207182
layout={this.state.layout}
208183
nodeColumns={this.state.nodeColumns}
209184
isStageSelected={this.stageIsSelected}
210185
/>
211186
</svg>
212187

188+
{nodes.map((node) => (
189+
<Node key={node.id} node={node} />
190+
))}
213191
{bigLabels.map((label) => (
214192
<BigLabel
215193
key={label.key}

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraphLayout.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe("PipelineGraphLayout", () => {
1515
startTimeMillis: "",
1616
totalDurationMillis: "",
1717
agent: "built-in",
18+
url: "?selected-node=0",
1819
};
1920

2021
const makeStage = (

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraphModel.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export interface StageInfo {
6363
startTimeMillis: string;
6464
totalDurationMillis: string;
6565
agent: string;
66+
url: string;
6667
}
6768

6869
interface BaseNodeInfo {
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,114 @@
11
import * as React from "react";
22
import { Result } from "../PipelineGraphModel";
3-
import { SvgStatus } from "./SvgStatus";
43

54
export const nodeStrokeWidth = 3.5; // px.
65

7-
// Returns the correct <g> element for the result / progress percent.
8-
export function getGroupForResult(
9-
result: Result,
10-
percentage: number,
11-
radius: number,
12-
centerX: number,
13-
centerY: number,
14-
outerStyle: React.CSSProperties,
15-
): React.ReactElement<SvgStatus> {
6+
function mapResultToCore(result: Result): string {
167
switch (result) {
17-
case Result.running:
18-
case Result.queued:
19-
case Result.not_built:
20-
case Result.skipped:
218
case Result.success:
9+
return "blue";
10+
case Result.running:
11+
return "nobuilt-anime";
2212
case Result.failure:
23-
case Result.paused:
13+
return "red";
2414
case Result.unstable:
15+
return "yellow";
2516
case Result.aborted:
26-
case Result.unknown:
27-
return (
28-
<SvgStatus
29-
radius={radius}
30-
result={result}
31-
outerStyle={outerStyle}
32-
centerX={centerX}
33-
centerY={centerY}
34-
/>
35-
);
17+
return "aborted";
18+
case Result.not_built:
19+
return "nobuilt";
3620
default:
37-
badResult(result);
38-
return (
39-
<SvgStatus
40-
radius={radius}
41-
result={Result.unknown}
42-
outerStyle={outerStyle}
43-
centerX={centerX}
44-
centerY={centerY}
45-
/>
46-
);
21+
throw new Error(`Unhandled result: ${result}`);
4722
}
4823
}
4924

50-
function badResult(x: never) {
51-
console.error("Unexpected Result value", x);
52-
}
25+
export function getSymbolForResult(result: Result): React.ReactElement {
26+
// Handle non-core symbols
27+
if (result === Result.paused) {
28+
return (
29+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
30+
<ellipse
31+
cx="256"
32+
cy="256"
33+
rx="210"
34+
ry="210"
35+
fill="none"
36+
stroke="var(--text-color-secondary)"
37+
strokeLinecap="round"
38+
strokeMiterlimit="10"
39+
strokeWidth="36"
40+
/>
41+
<path
42+
fill="none"
43+
stroke="var(--text-color-secondary)"
44+
strokeLinecap="round"
45+
strokeMiterlimit="10"
46+
strokeWidth="32"
47+
d="M208 192v128M304 192v128"
48+
/>
49+
</svg>
50+
);
51+
}
5352

54-
export const getClassForResult = (result: Result) => {
55-
// These come from the themes icons.less
56-
switch (result) {
57-
case Result.aborted:
58-
return "icon-aborted";
59-
case Result.unstable:
60-
return "icon-yellow";
61-
case Result.failure:
62-
return "icon-red";
63-
case Result.success:
64-
return "icon-blue";
65-
case Result.running:
66-
case Result.queued:
67-
return "icon-grey";
68-
case Result.skipped:
69-
return "icon-skipped";
70-
case Result.not_built:
71-
case Result.paused:
72-
case Result.unknown:
73-
default:
74-
return "icon-nobuilt";
53+
if (result === Result.unknown) {
54+
return (
55+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
56+
<ellipse
57+
cx="256"
58+
cy="256"
59+
rx="210"
60+
ry="210"
61+
fill="none"
62+
stroke="var(--text-color-secondary)"
63+
strokeLinecap="round"
64+
strokeMiterlimit="10"
65+
strokeWidth="36"
66+
/>
67+
<path
68+
d="M200 202.29s.84-17.5 19.57-32.57C230.68 160.77 244 158.18 256 158c10.93-.14 20.69 1.67 26.53 4.45 10 4.76 29.47 16.38 29.47 41.09 0 26-17 37.81-36.37 50.8S251 281.43 251 296"
69+
fill="none"
70+
stroke="var(--text-color-secondary)"
71+
strokeLinecap="round"
72+
strokeMiterlimit="10"
73+
strokeWidth="28"
74+
/>
75+
<circle cx="250" cy="348" r="20" fill="var(--text-color-secondary)" />
76+
</svg>
77+
);
7578
}
76-
};
79+
80+
if (result === Result.skipped) {
81+
return (
82+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
83+
<ellipse
84+
cx="256"
85+
cy="256"
86+
rx="210"
87+
ry="210"
88+
fill="none"
89+
stroke="var(--text-color-secondary)"
90+
strokeLinecap="round"
91+
strokeMiterlimit="10"
92+
strokeWidth="36"
93+
/>
94+
</svg>
95+
);
96+
}
97+
98+
// Map the result to retrieve the appropriate symbol from core
99+
const symbols = document.querySelector<HTMLTemplateElement>(
100+
"#pgv-build-status-icons",
101+
);
102+
const mappedResult = mapResultToCore(result);
103+
104+
return (
105+
<div
106+
dangerouslySetInnerHTML={{
107+
// This fails in React tests without the Jelly context
108+
__html:
109+
symbols?.content?.querySelector("#" + mappedResult)?.outerHTML ||
110+
`<div></div>`,
111+
}}
112+
/>
113+
);
114+
}

0 commit comments

Comments
 (0)