Skip to content

Commit e40bedc

Browse files
timbrown5timja
andauthored
Update react to 18 and MUI to 5 (#161)
Co-authored-by: Tim Jacomb <timjacomb1@gmail.com>
1 parent a6429f4 commit e40bedc

File tree

12 files changed

+4120
-4174
lines changed

12 files changed

+4120
-4174
lines changed

package-lock.json

Lines changed: 3934 additions & 4041 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
"private": true,
66
"scripts": {
77
"mvnbuild": "npm run build",
8-
"mvntest": "npm run test",
8+
"mvntest": "npm test",
99
"build": "webpack --mode production",
1010
"build:dev": "webpack --mode development --watch",
11-
"test": "npm run prettier-check && jest",
12-
"prettier-check": "prettier --check src/main/frontend/",
11+
"test": "jest && prettier --check src/main/frontend/",
1312
"prettier": "prettier --write src/main/frontend/"
1413
},
1514
"repository": {
@@ -23,36 +22,41 @@
2322
},
2423
"homepage": "https://github.com/jenkinsci/pipeline-graph-view-plugin/#readme",
2524
"dependencies": {
26-
"@material-ui/core": "4.11.4",
27-
"@material-ui/icons": "4.11.2",
28-
"@material-ui/lab": "4.0.0-alpha.58",
25+
"@mui/icons-material": "5.10.9",
26+
"@mui/lab": "5.0.0-alpha.104",
27+
"@mui/material": "5.10.10",
2928
"@react-spring/web": "9.5.4",
3029
"@reacticons/ionicons": "6.0.4",
3130
"html-react-parser": "1.4.14",
32-
"react": "16.14.0",
33-
"react-dom": "16.14.0",
34-
"react-split-pane": "0.1.92"
31+
"react": "18.2.0",
32+
"react-dom": "18.2.0"
3533
},
3634
"devDependencies": {
3735
"@babel/preset-env": "7.19.4",
3836
"@babel/preset-react": "7.18.6",
37+
"@emotion/react": "^11.10.4",
38+
"@emotion/styled": "^11.10.4",
39+
"@testing-library/jest-dom": "^5.16.5",
40+
"@testing-library/react": "^13.4.0",
3941
"@types/enzyme": "3.10.12",
4042
"@types/jest": "26.0.24",
4143
"@types/node": "16.18.0",
42-
"@types/react": "16.14.32",
43-
"@types/react-dom": "16.9.16",
44+
"@types/react": "18.0.21",
45+
"@types/react-dom": "18.0.6",
4446
"css-loader": "3.6.0",
45-
"enzyme": "3.11.0",
46-
"enzyme-adapter-react-16": "1.15.6",
47-
"jest": "27.5.1",
47+
"import": "^0.0.6",
48+
"jest": "^27.5.1",
49+
"jest-cli": "^27.5.1",
4850
"prettier": "2.7.1",
51+
"react-collapse-pane": "^3.0.1",
4952
"sass": "1.55.0",
5053
"sass-loader": "13.1.0",
5154
"source-map-loader": "0.2.4",
52-
"style-loader": "1.3.0",
55+
"style-loader": "^1.3.0",
56+
"styled-components": "^5.3.6",
5357
"ts-jest": "27.0.4",
54-
"ts-loader": "7.0.5",
55-
"typescript": "3.9.10",
58+
"ts-loader": "^7.0.5",
59+
"typescript": "4.1.5",
5660
"webpack": "5.74.0",
5761
"webpack-cli": "4.10.0"
5862
},
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import * as React from "react";
2-
import * as ReactDOM from "react-dom";
3-
1+
import React from "react";
2+
import ReactDOMClient from "react-dom/client";
43
import App from "./app";
4+
55
import { resetEnvironment } from "../common/reset-environment";
66

77
resetEnvironment();
8-
const root = document.getElementById("multiple-pipeline-root");
9-
ReactDOM.render(<App />, root);
8+
const rootElement = document.getElementById("multiple-pipeline-root");
9+
if (!rootElement)
10+
throw new Error("Failed to find the 'multiple-pipeline-root' element");
11+
const root = ReactDOMClient.createRoot(rootElement);
12+
13+
// Render App
14+
root.render(<App />);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { FunctionComponent } from "react";
33

44
import { PipelineConsole } from "./pipeline-console/main/";
55

6+
import { createTheme } from "@mui/material/styles";
7+
8+
export const theme = createTheme();
9+
610
const App: FunctionComponent = () => {
711
return (
812
<React.Fragment>
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import React from "react";
2-
import ReactDOM from "react-dom";
2+
import ReactDOMClient from "react-dom/client";
33
import App from "./app";
44

55
import { resetEnvironment } from "../common/reset-environment";
66

77
resetEnvironment();
8-
const root = document.getElementById("root");
9-
ReactDOM.render(<App />, root);
8+
const rootElement = document.getElementById("root");
9+
if (!rootElement) throw new Error("Failed to find the root element");
10+
const root = ReactDOMClient.createRoot(rootElement);
11+
12+
// Render App
13+
root.render(<App />);

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,28 @@ export function tokenizeANSIString(input?: string): string[] | Result[] {
148148
* Takes an array of string snippets and parsed escape codes produced bv tokenizeANSIString, and creates
149149
* an array of strings and spans with classNames for attributes.
150150
*/
151-
export function makeReactChildren(tokenizedInput: string[] | Result[]) {
151+
export function makeReactChildren(
152+
tokenizedInput: string[] | Result[],
153+
key: string
154+
) {
152155
const result = [];
153156
let currentState: Result = {
154157
setFG: false,
155158
setBG: false,
156159
};
157160

158-
for (const codeOrString of tokenizedInput) {
161+
for (let i = 0; i < tokenizedInput.length; i++) {
162+
let codeOrString = tokenizedInput[i];
159163
if (typeof codeOrString === "string") {
160164
// Need to output a <span> or plain text if there's no interesting current state
161165

162166
if (!currentState.setFG && !currentState.setBG) {
163-
result.push(<div dangerouslySetInnerHTML={{ __html: codeOrString }} />);
167+
result.push(
168+
<div
169+
dangerouslySetInnerHTML={{ __html: codeOrString }}
170+
key={`${key}-${i}`}
171+
/>
172+
);
164173
} else {
165174
const classNames = [];
166175

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

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import React from "react";
2-
import TreeView from "@material-ui/lab/TreeView/";
2+
import TreeView from "@mui/lab/TreeView/";
33

4-
import {
5-
fade,
6-
withStyles,
7-
Theme,
8-
createStyles,
9-
} from "@material-ui/core/styles";
10-
import TreeItem, { TreeItemProps } from "@material-ui/lab/TreeItem";
11-
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
12-
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
4+
import TreeItem from "@mui/lab/TreeItem";
5+
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
6+
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
137

148
import {
159
StageInfo,
@@ -34,37 +28,11 @@ export interface StepInfo {
3428
totalDurationMillis: string;
3529
}
3630

37-
// Tree Item for stages
38-
const StageTreeItem = withStyles((theme: Theme) =>
39-
createStyles({
40-
iconContainer: {
41-
"& .close": {
42-
opacity: 0.3,
43-
},
44-
},
45-
// TODO: Make line show status of block (green = passed, red = failed, etc.)
46-
group: {
47-
marginLeft: 7,
48-
paddingLeft: 18,
49-
borderLeft: `1px dashed ${fade(theme.palette.text.primary, 0.4)}`,
50-
},
51-
label: {},
52-
})
53-
)((props: TreeItemProps) => <TreeItem {...props} />);
54-
55-
// Tree Item for steps
56-
const StepTreeItem = withStyles((theme: Theme) =>
57-
createStyles({
58-
label: {
59-
textDecoration: "underline",
60-
},
61-
})
62-
)((props: TreeItemProps) => <TreeItem {...props} />);
63-
6431
const getTreeItemsFromStepList = (stepsItems: StepInfo[]) => {
6532
return stepsItems.map((stepItemData) => {
6633
return (
67-
<StepTreeItem
34+
<TreeItem
35+
className="step-tree-item"
6836
key={stepItemData.id}
6937
nodeId={String(stepItemData.id)}
7038
label={
@@ -105,7 +73,8 @@ const getTreeItemsFromStage = (stageItems: StageInfo[], steps: StepInfo[]) => {
10573
children = [...children, ...stepsItems];
10674
}
10775
return (
108-
<StageTreeItem
76+
<TreeItem
77+
className="stage-tree-item"
10978
key={stageItemData.id}
11079
nodeId={String(stageItemData.id)}
11180
label={

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

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import React from "react";
22

3-
import SplitPane from "react-split-pane";
4-
import { DataTreeView } from "./DataTreeView";
3+
import { SplitPane } from "react-collapse-pane";
54
import { makeReactChildren, tokenizeANSIString } from "./Ansi";
65
import { StageInfo } from "../../../pipeline-graph-view/pipeline-graph/main/";
7-
import { StepInfo } from "./DataTreeView";
6+
import { DataTreeView, StepInfo } from "./DataTreeView";
87

9-
import Typography from "@material-ui/core/Typography";
8+
import Typography from "@mui/material/Typography";
109

11-
import HourglassEmptyIcon from "@material-ui/icons/HourglassEmpty";
12-
import ScheduleIcon from "@material-ui/icons/Schedule";
13-
import TimerIcon from "@material-ui/icons/Timer";
14-
import InfoIcon from "@material-ui/icons/Info";
15-
import LinkIcon from "@material-ui/icons/Link";
10+
import HourglassEmptyIcon from "@mui/icons-material/HourglassEmpty";
11+
import ScheduleIcon from "@mui/icons-material/Schedule";
12+
import TimerIcon from "@mui/icons-material/Timer";
13+
import InfoIcon from "@mui/icons-material/Info";
14+
import LinkIcon from "@mui/icons-material/Link";
1615

1716
import "./pipeline-console.scss";
1817

@@ -119,15 +118,19 @@ const ConsoleLine = (props: ConsoleLineProps) => (
119118
<div
120119
className="console-output-line-anchor"
121120
id={`log-${props.lineNumber}`}
121+
key={`${props.lineNumber}-anchor`}
122122
/>
123-
<div className="console-output-line">
123+
<div className="console-output-line" key={`${props.lineNumber}-body`}>
124124
<a
125125
className="console-line-number"
126126
href={`?selected-node=${props.stepId}#log-${props.lineNumber}`}
127127
>
128128
{props.lineNumber}
129129
</a>
130-
{makeReactChildren(tokenizeANSIString(props.content))}
130+
{makeReactChildren(
131+
tokenizeANSIString(props.content),
132+
`${props.stepId}-${props.lineNumber}`
133+
)}
131134
</div>
132135
</div>
133136
);
@@ -315,58 +318,49 @@ export class PipelineConsole extends React.Component<
315318
}
316319
}
317320
return (
318-
<div className="console-output">
321+
<pre className="console-output">
319322
<StageSummary stage={focusedStage} failedSteps={failedSteps} />
320-
</div>
323+
</pre>
321324
);
322325
}
323326
}
324-
return (
325-
// Return empty div
326-
<div></div>
327-
);
327+
return null;
328328
}
329329

330330
renderStepDetails() {
331331
for (let i = 0; i < this.state.steps.length; i++) {
332332
let step = this.state.steps[i];
333333
if ("" + step.id == this.state.selected) {
334334
return (
335-
<div className="console-output">
335+
<pre className="console-output">
336336
<StepSummary step={step} />
337-
</div>
337+
</pre>
338338
);
339339
}
340340
}
341-
return (
342-
// Return empty div
343-
<div></div>
344-
);
341+
return null;
345342
}
346343

347344
renderConsoleOutput() {
348345
if (this.state.consoleText.length > 0) {
349346
const lineChunks = this.state.consoleText.split("\n");
350347
return (
351-
<div className="console-output">
352-
<pre className="console-pane console-output-item">
353-
{lineChunks.map((line, index) => {
354-
let lineNumber = String(index + 1);
355-
return (
356-
<ConsoleLine
357-
content={line}
358-
lineNumber={lineNumber}
359-
stepId={this.state.selected}
360-
key={`${this.state.selected}-${lineNumber}`}
361-
/>
362-
);
363-
})}
364-
</pre>
365-
</div>
348+
<pre className="console-output">
349+
{lineChunks.map((line, index) => {
350+
let lineNumber = String(index + 1);
351+
return (
352+
<ConsoleLine
353+
content={line}
354+
lineNumber={lineNumber}
355+
stepId={this.state.selected}
356+
key={`${this.state.selected}-${lineNumber}`}
357+
/>
358+
);
359+
})}
360+
</pre>
366361
);
367362
} else {
368-
// Return empty div if no text.
369-
return <div></div>;
363+
return null;
370364
}
371365
}
372366

@@ -380,17 +374,18 @@ export class PipelineConsole extends React.Component<
380374
height: "calc(100vh - 300px)",
381375
overflowY: "auto",
382376
};
383-
384377
return (
385378
<React.Fragment>
386379
<div className="App">
387380
<SplitPane
388-
minSize={150}
389-
defaultSize={parseInt(localStorage.getItem("splitPos") || "250")}
390-
onChange={(size) => localStorage.setItem("splitPos", `${size}`)}
391-
style={splitPaneStyle}
381+
// intialSize ratio
382+
initialSizes={[3, 7]}
383+
// minSize in Pixels (for all panes)
384+
minSizes={250}
385+
className="split-pane"
386+
split="vertical"
392387
>
393-
<div style={paneStyle}>
388+
<div className="split-pane" key="tree-view">
394389
<DataTreeView
395390
onNodeSelect={this.handleActionNodeSelect}
396391
onNodeToggle={this.handleToggle}
@@ -401,7 +396,7 @@ export class PipelineConsole extends React.Component<
401396
/>
402397
</div>
403398

404-
<div style={paneStyle}>
399+
<div className="split-pane" key="console-view">
405400
{this.renderStageDetails()}
406401
{this.renderStepDetails()}
407402
{this.renderConsoleOutput()}

0 commit comments

Comments
 (0)