Skip to content

Commit b86ba42

Browse files
committed
dashboard: Add view for PR runs
Added a script that fetches PR data and created a separate view on the dashboard. Fixes #1 Signed-off-by: Anna Finn <[email protected]>
1 parent 9b993f0 commit b86ba42

File tree

5 files changed

+508
-240
lines changed

5 files changed

+508
-240
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Fetch CI Data
2+
run-name: Fetch CI Data
3+
on:
4+
schedule:
5+
- cron: '0 */2 * * *'
6+
workflow_dispatch:
7+
8+
jobs:
9+
fetch-and-commit-data:
10+
runs-on: ubuntu-22.04
11+
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
- name: Update dashboard data
16+
run: |
17+
# fetch ci nightly data as temporary file
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+
21+
# switch to a branch specifically for holding latest data
22+
git config --global user.name "GH Actions Workflow"
23+
git config --global user.email "<gha@runner>"
24+
git fetch --all
25+
git checkout latest-dashboard-data
26+
27+
# back out whatever data was there
28+
git reset HEAD~1
29+
30+
# overwrite the old data
31+
mkdir -p data/
32+
mv tmp-data.json data/job_stats.json
33+
mv tmp-data2.json data/check_stats.json
34+
35+
# commit
36+
git add data
37+
git commit -m '[skip ci] latest ci nightly data'
38+
git push --force

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
"private": true,
44
"scripts": {
55
"dev": "NODE_ENV=development next dev",
6+
"win-dev": "next dev",
67
"build": "next build",
78
"start": "next start",
89
"lint": "next lint"
910
},
1011
"dependencies": {
11-
"next": "^14.2.13",
12+
"next": "^15.0.2",
1213
"primeflex": "^3.3.1",
1314
"primeicons": "^6.0.1",
1415
"primereact": "^10.8.3",
@@ -18,9 +19,10 @@
1819
},
1920
"devDependencies": {
2021
"autoprefixer": "^10.4.20",
22+
"dotenv": "^16.4.5",
2123
"eslint": "8.57.0",
2224
"eslint-config-next": "^14.2.13",
2325
"postcss": "^8.4.47",
2426
"tailwindcss": "^3.4.13"
2527
}
26-
}
28+
}

pages/index.js

Lines changed: 172 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,38 @@ import { weatherTemplate, getWeatherIndex } from "../components/weatherTemplate"
55

66

77
export default function Home() {
8-
const [loading, setLoading] = useState(true);
9-
const [jobs, setJobs] = useState([]);
10-
const [rows, setRows] = useState([]);
11-
const [expandedRows, setExpandedRows] = useState([]);
8+
const [loading, setLoading] = useState(true);
9+
const [jobs, setJobs] = useState([]);
10+
const [checks, setChecks] = useState([]);
11+
const [rowsPR, setRowsPR] = useState([]);
12+
const [rowsNightly, setRowsNightly] = useState([]);
13+
const [expandedRows, setExpandedRows] = useState([]);
14+
const [display, setDisplay] = useState("nightly");
15+
1216

1317
useEffect(() => {
1418
const fetchData = async () => {
15-
let data = {};
19+
let nightlyData = {};
20+
let prData = {};
1621

1722
if (process.env.NODE_ENV === "development") {
18-
data = (await import("../job_stats.json")).default;
23+
nightlyData = (await import("../localData/job_stats.json")).default;
24+
prData = (await import("../localData/check_stats.json")).default;
1925
} else {
20-
const response = await fetch(
26+
nightlyData = await fetch(
2127
"https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
2228
"/refs/heads/latest-dashboard-data/data/job_stats.json"
23-
);
24-
data = await response.json();
29+
).then((res) => res.json());
30+
prData = await fetch(
31+
"https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
32+
"/refs/heads/latest-dashboard-data/data/check_stats.json"
33+
).then((res) => res.json());
2534
}
2635

2736
try {
28-
const jobData = Object.keys(data).map((key) => {
29-
const job = data[key];
30-
return { name: key, ...job };
31-
});
32-
setJobs(jobData);
37+
const mapData = (data) => Object.keys(data).map((key) => ({ name: key, ...data[key] }));
38+
setJobs(mapData(nightlyData));
39+
setChecks(mapData(prData));
3340
} catch (error) {
3441
// TODO: Add pop-up/toast message for error
3542
console.error("Error fetching data:", error);
@@ -41,17 +48,50 @@ export default function Home() {
4148
fetchData();
4249
}, []);
4350

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

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]);
5595

5696
const toggleRow = (rowData) => {
5797
const isRowExpanded = expandedRows.includes(rowData);
@@ -66,6 +106,11 @@ export default function Home() {
66106
setExpandedRows(updatedExpandedRows);
67107
};
68108

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

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

81129
// Prepare run data
82130
const runs = [];
@@ -120,67 +168,126 @@ export default function Home() {
120168
);
121169
};
122170

123-
const renderTable = () => (
171+
// Render table for nightly view.
172+
const renderNightlyTable = () => (
124173
<DataTable
125-
value={rows}
174+
value={rowsNightly}
126175
expandedRows={expandedRows}
127176
stripedRows
128177
rowExpansionTemplate={rowExpansionTemplate}
129178
onRowToggle={(e) => setExpandedRows(e.data)}
130179
loading={loading}
131180
emptyMessage="No results found."
132181
>
133-
<Column expander style={{ width: "5rem" }} />
182+
<Column expander/>
134183
<Column
135184
field="name"
136185
header="Name"
137186
body={nameTemplate}
187+
className="select-all"
138188
filter
139189
sortable
140-
maxConstraints={4}
141-
filterHeader="Filter by Name"
142-
filterPlaceholder="Search..."
143190
/>
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 />
191+
<Column field = "required" header = "Required" sortable/>
192+
<Column
193+
field = "runs"
194+
header = "Runs"
195+
className="whitespace-nowrap px-2"
196+
sortable />
197+
<Column field = "fails" header = "Fails" sortable/>
198+
<Column field = "skips" header = "Skips" sortable/>
199+
<Column
200+
field = "weather"
201+
header = "Weather"
202+
body = {weatherTemplate}
203+
sortable />
204+
</DataTable>
205+
);
206+
207+
const renderPRTable = () => (
208+
<DataTable
209+
value={rowsPR}
210+
expandedRows={expandedRows}
211+
stripedRows
212+
rowExpansionTemplate={rowExpansionTemplate}
213+
onRowToggle={(e) => setExpandedRows(e.data)}
214+
loading={loading}
215+
emptyMessage="No results found."
216+
>
217+
<Column expander/>
148218
<Column
149-
field="weather"
150-
header="Weather"
151-
body={weatherTemplate}
219+
field="name"
220+
header="Name"
221+
body={nameTemplate}
222+
className="select-all"
223+
filter
152224
sortable
153225
/>
226+
<Column field = "required" header = "Required" sortable/>
227+
<Column
228+
field = "runs"
229+
header = "Runs"
230+
className="whitespace-nowrap px-2"
231+
sortable />
232+
<Column field = "fails" header = "Fails" sortable/>
233+
<Column field = "skips" header = "Skips" sortable/>
234+
<Column
235+
field = "weather"
236+
header = "Weather"
237+
body = {weatherTemplate}
238+
sortable />
154239
</DataTable>
155240
);
156241

242+
157243
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>
244+
<>
245+
246+
<title>Kata CI Dashboard</title>
247+
<div className="text-center text-xs md:text-base">
248+
<h1 className={"text-4xl mt-4 ml-4 mb-6 underline text-inherit \
249+
hover:text-blue-500"}>
250+
<a
251+
href={display === 'nightly'
252+
? "https://github.com/kata-containers/kata-containers/" +
253+
"actions/workflows/ci-nightly.yaml"
254+
: "https://github.com/kata-containers/kata-containers/" +
255+
"actions/workflows/ci-on-push.yaml"}
256+
target="_blank"
257+
rel="noopener noreferrer"
258+
>
259+
Kata CI Dashboard
260+
</a>
261+
</h1>
262+
263+
<div className="flex flex-wrap mt-2 p-4 md:text-base text-xs">
264+
<div className="space-x-2 pb-2 pr-3 mx-auto flex">
265+
<button
266+
className={tabClass(display === "nightly")}
267+
onClick={() => {
268+
setDisplay("nightly");
269+
}}>
270+
Nightly Jobs
271+
</button>
272+
<button
273+
className={tabClass(display === "prchecks")}
274+
onClick={() => {
275+
setDisplay("prchecks");
276+
}}>
277+
PR Checks
278+
</button>
279+
</div>
280+
</div>
281+
282+
<div className="mt-1 text-center md:text-lg text-base">
283+
Total Rows: {display === "prchecks" ? rowsPR.length : rowsNightly.length}
284+
</div>
285+
286+
<main className={"m-0 h-full px-4 overflow-x-hidden overflow-y-auto \
287+
bg-surface-ground antialiased select-text"}>
288+
<div>{display === "prchecks" ? renderPRTable() : renderNightlyTable()}</div>
289+
</main>
290+
</div>
291+
</>
185292
);
186-
}
293+
}

0 commit comments

Comments
 (0)