Skip to content

Commit 8405c7e

Browse files
committed
dashboard: Add view for PR runs
1 parent 9b993f0 commit 8405c7e

File tree

6 files changed

+489
-232
lines changed

6 files changed

+489
-232
lines changed
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
name: Fetch CI Nightly Data
2-
run-name: Fetch CI Nightly Data
1+
name: Fetch CI Data
2+
run-name: Fetch CI Data
33
on:
44
schedule:
5-
- cron: '0 4 * * *'
5+
- cron: '0 * * * *'
66
workflow_dispatch:
77

88
jobs:
@@ -15,18 +15,24 @@ jobs:
1515
- name: Update dashboard data
1616
run: |
1717
# fetch ci nightly data as temporary file
18-
node scripts/fetch-ci-nightly-data.js | tee tmp-data.json
18+
TOKEN=${{ secrets.GITHUB_TOKEN }} node scripts/fetch-ci-nightly-data.js | tee tmp-data.json
19+
TOKEN=${{ secrets.GITHUB_TOKEN }} node scripts/fetch-ci-pr-data.js | tee tmp-data2.json
20+
1921
# switch to a branch specifically for holding latest data
2022
git config --global user.name "GH Actions Workflow"
2123
git config --global user.email "<gha@runner>"
2224
git fetch --all
2325
git checkout latest-dashboard-data
26+
2427
# back out whatever data was there
2528
git reset HEAD~1
29+
2630
# overwrite the old data
2731
mkdir -p data/
2832
mv tmp-data.json data/job_stats.json
33+
mv tmp-data2.json data/check_stats.json
34+
2935
# commit
3036
git add data
3137
git commit -m '[skip ci] latest ci nightly data'
32-
git push --force
38+
git push --force

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"lint": "next lint"
99
},
1010
"dependencies": {
11+
"dotenv": "^16.4.5",
1112
"next": "^14.2.13",
1213
"primeflex": "^3.3.1",
1314
"primeicons": "^6.0.1",

pages/index.js

Lines changed: 171 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import { useEffect, useState } from "react";
23
import { DataTable } from "primereact/datatable";
34
import { Column } from "primereact/column";
@@ -7,29 +8,36 @@ import { weatherTemplate, getWeatherIndex } from "../components/weatherTemplate"
78
export default function Home() {
89
const [loading, setLoading] = useState(true);
910
const [jobs, setJobs] = useState([]);
10-
const [rows, setRows] = useState([]);
11-
const [expandedRows, setExpandedRows] = useState([]);
11+
const [checks, setChecks] = useState([]);
12+
const [rowsPR, setRowsPR] = useState([]);
13+
const [rowsNightly, setRowsNightly] = useState([]);
14+
const [expandedRows, setExpandedRows] = useState([]);
15+
const [display, setDisplay] = useState("nightly");
16+
1217

1318
useEffect(() => {
1419
const fetchData = async () => {
15-
let data = {};
20+
let nightlyData = {};
21+
let prData = {};
1622

1723
if (process.env.NODE_ENV === "development") {
18-
data = (await import("../job_stats.json")).default;
24+
nightlyData = (await import("../data/job_stats.json")).default;
25+
prData = (await import("../data/check_stats.json")).default;
1926
} else {
20-
const response = await fetch(
27+
nightlyData = await fetch(
2128
"https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
2229
"/refs/heads/latest-dashboard-data/data/job_stats.json"
23-
);
24-
data = await response.json();
30+
).then((res) => res.json());
31+
prData = await fetch(
32+
"https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
33+
"/refs/heads/latest-dashboard-data/data/check_stats.json"
34+
).then((res) => res.json());
2535
}
2636

2737
try {
28-
const jobData = Object.keys(data).map((key) => {
29-
const job = data[key];
30-
return { name: key, ...job };
31-
});
32-
setJobs(jobData);
38+
const mapData = (data) => Object.keys(data).map((key) => ({ name: key, ...data[key] }));
39+
setJobs(mapData(nightlyData));
40+
setChecks(mapData(prData));
3341
} catch (error) {
3442
// TODO: Add pop-up/toast message for error
3543
console.error("Error fetching data:", error);
@@ -41,17 +49,50 @@ export default function Home() {
4149
fetchData();
4250
}, []);
4351

52+
// Filter and set the rows for Nightly view.
53+
useEffect(() => {
54+
setLoading(true);
55+
let filteredJobs = jobs;
56+
//Set the rows for the table.
57+
setRowsNightly(
58+
filteredJobs.map((job) => ({
59+
name : job.name,
60+
runs : job.runs,
61+
fails : job.fails,
62+
skips : job.skips,
63+
required : job.required,
64+
weather : getWeatherIndex(job),
65+
}))
66+
);
67+
setLoading(false);
68+
}, [jobs]);
69+
70+
// Filter and set the rows for PR Checks view.
71+
useEffect(() => {
72+
setLoading(true);
73+
let filteredChecks = checks
74+
75+
//Set the rows for the table.
76+
setRowsPR(
77+
filteredChecks.map((check) => ({
78+
name : check.name,
79+
runs : check.runs,
80+
fails : check.fails,
81+
skips : check.skips,
82+
required : check.required,
83+
weather : getWeatherIndex(check),
84+
}))
85+
);
86+
setLoading(false);
87+
}, [checks]);
88+
89+
// Close all rows on view switch.
90+
// Needed because if view is switched, breaks expanded row toggling.
4491
useEffect(() => {
45-
setLoading(true);
92+
setExpandedRows([])
93+
}, [display]);
94+
4695

47-
// Create rows to set into table.
48-
const rows = jobs.map((job) => ({
49-
...job,
50-
weather: getWeatherIndex(job),
51-
}));
52-
setRows(rows);
53-
setLoading(false);
54-
}, [jobs]);
5596

5697
const toggleRow = (rowData) => {
5798
const isRowExpanded = expandedRows.includes(rowData);
@@ -66,6 +107,11 @@ export default function Home() {
66107
setExpandedRows(updatedExpandedRows);
67108
};
68109

110+
const tabClass = (active) => `tab md:px-4 px-2 py-2 border-b-2 focus:outline-none
111+
${active ? "border-blue-500 bg-gray-300"
112+
: "border-gray-300 bg-white hover:bg-gray-100"}`;
113+
114+
69115
// Template for rendering the Name column as a clickable item
70116
const nameTemplate = (rowData) => {
71117
return (
@@ -76,7 +122,10 @@ export default function Home() {
76122
};
77123

78124
const rowExpansionTemplate = (data) => {
79-
const job = jobs.find((job) => job.name === data.name);
125+
const job = (display === "nightly"
126+
? jobs
127+
: checks).find((job) => job.name === data.name);
128+
80129

81130
// Prepare run data
82131
const runs = [];
@@ -120,67 +169,126 @@ export default function Home() {
120169
);
121170
};
122171

123-
const renderTable = () => (
172+
// Render table for nightly view.
173+
const renderNightlyTable = () => (
124174
<DataTable
125-
value={rows}
175+
value={rowsNightly}
126176
expandedRows={expandedRows}
127177
stripedRows
128178
rowExpansionTemplate={rowExpansionTemplate}
129179
onRowToggle={(e) => setExpandedRows(e.data)}
130180
loading={loading}
131181
emptyMessage="No results found."
132182
>
133-
<Column expander style={{ width: "5rem" }} />
183+
<Column expander/>
134184
<Column
135185
field="name"
136186
header="Name"
137187
body={nameTemplate}
188+
className="select-all"
138189
filter
139190
sortable
140-
maxConstraints={4}
141-
filterHeader="Filter by Name"
142-
filterPlaceholder="Search..."
143191
/>
144-
<Column field="required" header="Required" sortable />
145-
<Column field="runs" header="Runs" sortable />
146-
<Column field="fails" header="Fails" sortable />
147-
<Column field="skips" header="Skips" sortable />
192+
<Column field = "required" header = "Required" sortable/>
193+
<Column
194+
field = "runs"
195+
header = "Runs"
196+
className="whitespace-nowrap px-2"
197+
sortable />
198+
<Column field = "fails" header = "Fails" sortable/>
199+
<Column field = "skips" header = "Skips" sortable/>
200+
<Column
201+
field = "weather"
202+
header = "Weather"
203+
body = {weatherTemplate}
204+
sortable />
205+
</DataTable>
206+
);
207+
208+
const renderPRTable = () => (
209+
<DataTable
210+
value={rowsPR}
211+
expandedRows={expandedRows}
212+
stripedRows
213+
rowExpansionTemplate={rowExpansionTemplate}
214+
onRowToggle={(e) => setExpandedRows(e.data)}
215+
loading={loading}
216+
emptyMessage="No results found."
217+
>
218+
<Column expander/>
148219
<Column
149-
field="weather"
150-
header="Weather"
151-
body={weatherTemplate}
220+
field="name"
221+
header="Name"
222+
body={nameTemplate}
223+
className="select-all"
224+
filter
152225
sortable
153226
/>
227+
<Column field = "required" header = "Required" sortable/>
228+
<Column
229+
field = "runs"
230+
header = "Runs"
231+
className="whitespace-nowrap px-2"
232+
sortable />
233+
<Column field = "fails" header = "Fails" sortable/>
234+
<Column field = "skips" header = "Skips" sortable/>
235+
<Column
236+
field = "weather"
237+
header = "Weather"
238+
body = {weatherTemplate}
239+
sortable />
154240
</DataTable>
155241
);
156242

243+
157244
return (
158-
<div className="text-center">
159-
<h1
160-
className={
161-
"text-4xl mt-4 mb-0 underline text-inherit hover:text-blue-500"
162-
}
163-
>
164-
<a
165-
href={
166-
"https://github.com/kata-containers/kata-containers/" +
167-
"actions/workflows/ci-nightly.yaml"
168-
}
169-
target="_blank"
170-
rel="noopener noreferrer"
171-
>
172-
Kata CI Dashboard
173-
</a>
174-
</h1>
175-
176-
<main
177-
className={
178-
"m-0 h-full p-4 overflow-x-hidden overflow-y-auto bg-surface-ground font-normal text-text-color antialiased select-text"
179-
}
180-
>
181-
<div>{renderTable()}</div>
182-
<div className="mt-4 text-lg">Total Rows: {rows.length}</div>
183-
</main>
184-
</div>
245+
<>
246+
247+
<title>Kata CI Dashboard</title>
248+
<div className="text-center text-xs md:text-base">
249+
<h1 className={"text-4xl mt-4 ml-4 mb-6 underline text-inherit \
250+
hover:text-blue-500"}>
251+
<a
252+
href={display === 'nightly'
253+
? "https://github.com/kata-containers/kata-containers/" +
254+
"actions/workflows/ci-nightly.yaml"
255+
: "https://github.com/kata-containers/kata-containers/" +
256+
"actions/workflows/ci-on-push.yaml"}
257+
target="_blank"
258+
rel="noopener noreferrer"
259+
>
260+
Kata CI Dashboard
261+
</a>
262+
</h1>
263+
264+
<div className="flex flex-wrap mt-2 p-4 md:text-base text-xs">
265+
<div className="space-x-2 pb-2 pr-3 mx-auto flex">
266+
<button
267+
className={tabClass(display === "nightly")}
268+
onClick={() => {
269+
setDisplay("nightly");
270+
}}>
271+
Nightly Jobs
272+
</button>
273+
<button
274+
className={tabClass(display === "prchecks")}
275+
onClick={() => {
276+
setDisplay("prchecks");
277+
}}>
278+
PR Checks
279+
</button>
280+
</div>
281+
</div>
282+
283+
<div className="mt-1 text-center md:text-lg text-base">
284+
Total Rows: {display === "prchecks" ? rowsPR.length : rowsNightly.length}
285+
</div>
286+
287+
<main className={"m-0 h-full px-4 overflow-x-hidden overflow-y-auto \
288+
bg-surface-ground antialiased select-text"}>
289+
<div>{display === "prchecks" ? renderPRTable() : renderNightlyTable()}</div>
290+
</main>
291+
</div>
292+
</>
185293
);
186-
}
294+
}

0 commit comments

Comments
 (0)