Skip to content

Commit

Permalink
dashboard: Add view for PR runs
Browse files Browse the repository at this point in the history
Added a script that fetches PR data and created a separate view on the dashboard.

Fixes #1

Signed-off-by: Anna Finn <[email protected]>
  • Loading branch information
afinn12 committed Nov 7, 2024
1 parent 054713a commit af17d13
Show file tree
Hide file tree
Showing 5 changed files with 506 additions and 240 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/fectch-ci-data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Fetch CI Data
run-name: Fetch CI Data
on:
schedule:
- cron: '0 */2 * * *'
workflow_dispatch:

jobs:
fetch-and-commit-data:
runs-on: ubuntu-22.04

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Update dashboard data
run: |
# fetch ci nightly data as temporary file
TOKEN=${{ secrets.GITHUB_TOKEN }} node scripts/fetch-ci-nightly-data.js | tee tmp-data.json
TOKEN=${{ secrets.GITHUB_TOKEN }} node scripts/fetch-ci-pr-data.js | tee tmp-data2.json
# switch to a branch specifically for holding latest data
git config --global user.name "GH Actions Workflow"
git config --global user.email "<gha@runner>"
git fetch --all
git checkout latest-dashboard-data
# back out whatever data was there
git reset HEAD~1
# overwrite the old data
mkdir -p data/
mv tmp-data.json data/job_stats.json
mv tmp-data2.json data/check_stats.json
# commit
git add data
git commit -m '[skip ci] latest ci nightly data'
git push --force
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
"private": true,
"scripts": {
"dev": "NODE_ENV=development next dev",
"win-dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "^14.2.13",
"next": "^15.0.2",
"primeflex": "^3.3.1",
"primeicons": "^6.0.1",
"primereact": "^10.8.3",
Expand All @@ -18,9 +19,10 @@
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"dotenv": "^16.4.5",
"eslint": "8.57.0",
"eslint-config-next": "^14.2.13",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13"
}
}
}
235 changes: 170 additions & 65 deletions pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,38 @@ import { weatherTemplate, getWeatherIndex } from "../components/weatherTemplate"


export default function Home() {
const [loading, setLoading] = useState(true);
const [jobs, setJobs] = useState([]);
const [rows, setRows] = useState([]);
const [expandedRows, setExpandedRows] = useState([]);
const [loading, setLoading] = useState(true);
const [jobs, setJobs] = useState([]);
const [checks, setChecks] = useState([]);
const [rowsPR, setRowsPR] = useState([]);
const [rowsNightly, setRowsNightly] = useState([]);
const [expandedRows, setExpandedRows] = useState([]);
const [display, setDisplay] = useState("nightly");


useEffect(() => {
const fetchData = async () => {
let data = {};
let nightlyData = {};
let prData = {};

if (process.env.NODE_ENV === "development") {
data = (await import("../job_stats.json")).default;
nightlyData = (await import("../localData/job_stats.json")).default;
prData = (await import("../localData/check_stats.json")).default;
} else {
const response = await fetch(
nightlyData = await fetch(
"https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
"/refs/heads/latest-dashboard-data/data/job_stats.json"
);
data = await response.json();
).then((res) => res.json());
prData = await fetch(
"https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
"/refs/heads/latest-dashboard-data/data/check_stats.json"
).then((res) => res.json());
}

try {
const jobData = Object.keys(data).map((key) => {
const job = data[key];
return { name: key, ...job };
});
setJobs(jobData);
const mapData = (data) => Object.keys(data).map((key) => ({ name: key, ...data[key] }));
setJobs(mapData(nightlyData));
setChecks(mapData(prData));
} catch (error) {
// TODO: Add pop-up/toast message for error
console.error("Error fetching data:", error);
Expand All @@ -42,17 +49,50 @@ export default function Home() {
fetchData();
}, []);

// Filter and set the rows for Nightly view.
useEffect(() => {
setLoading(true);
let filteredJobs = jobs;
//Set the rows for the table.
setRowsNightly(
filteredJobs.map((job) => ({
name : job.name,
runs : job.runs,
fails : job.fails,
skips : job.skips,
required : job.required,
weather : getWeatherIndex(job),
}))
);
setLoading(false);
}, [jobs]);

// Filter and set the rows for PR Checks view.
useEffect(() => {
setLoading(true);
let filteredChecks = checks

//Set the rows for the table.
setRowsPR(
filteredChecks.map((check) => ({
name : check.name,
runs : check.runs,
fails : check.fails,
skips : check.skips,
required : check.required,
weather : getWeatherIndex(check),
}))
);
setLoading(false);
}, [checks]);

// Close all rows on view switch.
// Needed because if view is switched, breaks expanded row toggling.
useEffect(() => {
setLoading(true);
setExpandedRows([])
}, [display]);


// Create rows to set into table.
const rows = jobs.map((job) => ({
...job,
weather: getWeatherIndex(job),
}));
setRows(rows);
setLoading(false);
}, [jobs]);

const toggleRow = (rowData) => {
const isRowExpanded = expandedRows.includes(rowData);
Expand All @@ -67,6 +107,11 @@ export default function Home() {
setExpandedRows(updatedExpandedRows);
};

const tabClass = (active) => `tab md:px-4 px-2 py-2 border-b-2 focus:outline-none
${active ? "border-blue-500 bg-gray-300"
: "border-gray-300 bg-white hover:bg-gray-100"}`;


// Template for rendering the Name column as a clickable item
const nameTemplate = (rowData) => {
return (
Expand All @@ -77,7 +122,10 @@ export default function Home() {
};

const rowExpansionTemplate = (data) => {
const job = jobs.find((job) => job.name === data.name);
const job = (display === "nightly"
? jobs
: checks).find((job) => job.name === data.name);


// Prepare run data
const runs = [];
Expand Down Expand Up @@ -121,71 +169,128 @@ export default function Home() {
);
};

const renderTable = () => (
// Render table for nightly view.
const renderNightlyTable = () => (
<DataTable
value={rows}
value={rowsNightly}
expandedRows={expandedRows}
stripedRows
rowExpansionTemplate={rowExpansionTemplate}
onRowToggle={(e) => setExpandedRows(e.data)}
loading={loading}
emptyMessage="No results found."
>
<Column expander style={{ width: "5rem" }} />
<Column expander/>
<Column
field="name"
header="Name"
body={nameTemplate}
className="select-all"
filter
sortable
maxConstraints={4}
filterHeader="Filter by Name"
filterPlaceholder="Search..."
/>
<Column field="required" header="Required" sortable />
<Column field="runs" header="Runs" sortable />
<Column field="fails" header="Fails" sortable />
<Column field="skips" header="Skips" sortable />
<Column field = "required" header = "Required" sortable/>
<Column
field = "runs"
header = "Runs"
className="whitespace-nowrap px-2"
sortable />
<Column field = "fails" header = "Fails" sortable/>
<Column field = "skips" header = "Skips" sortable/>
<Column
field = "weather"
header = "Weather"
body = {weatherTemplate}
sortable />
</DataTable>
);

const renderPRTable = () => (
<DataTable
value={rowsPR}
expandedRows={expandedRows}
stripedRows
rowExpansionTemplate={rowExpansionTemplate}
onRowToggle={(e) => setExpandedRows(e.data)}
loading={loading}
emptyMessage="No results found."
>
<Column expander/>
<Column
field="weather"
header="Weather"
body={weatherTemplate}
field="name"
header="Name"
body={nameTemplate}
className="select-all"
filter
sortable
/>
<Column field = "required" header = "Required" sortable/>
<Column
field = "runs"
header = "Runs"
className="whitespace-nowrap px-2"
sortable />
<Column field = "fails" header = "Fails" sortable/>
<Column field = "skips" header = "Skips" sortable/>
<Column
field = "weather"
header = "Weather"
body = {weatherTemplate}
sortable />
</DataTable>
);


return (
<div className="text-center">
<>

<Head>
<title>Kata CI Dashboard</title>
</Head>
<div className="text-center text-xs md:text-base">
<h1 className={"text-4xl mt-4 ml-4 mb-6 underline text-inherit \
hover:text-blue-500"}>
<a
href={display === 'nightly'
? "https://github.com/kata-containers/kata-containers/" +
"actions/workflows/ci-nightly.yaml"
: "https://github.com/kata-containers/kata-containers/" +
"actions/workflows/ci-on-push.yaml"}
target="_blank"
rel="noopener noreferrer"
>
Kata CI Dashboard
</a>
</h1>

<h1
className={
"text-4xl mt-4 mb-0 underline text-inherit hover:text-blue-500"
}
>
<a
href={
"https://github.com/kata-containers/kata-containers/" +
"actions/workflows/ci-nightly.yaml"
}
target="_blank"
rel="noopener noreferrer"
>
Kata CI Dashboard
</a>
</h1>

<main
className={
"m-0 h-full p-4 overflow-x-hidden overflow-y-auto bg-surface-ground font-normal text-text-color antialiased select-text"
}
>
<div>{renderTable()}</div>
<div className="mt-4 text-lg">Total Rows: {rows.length}</div>
</main>
</div>
<div className="flex flex-wrap mt-2 p-4 md:text-base text-xs">
<div className="space-x-2 pb-2 pr-3 mx-auto flex">
<button
className={tabClass(display === "nightly")}
onClick={() => {
setDisplay("nightly");
}}>
Nightly Jobs
</button>
<button
className={tabClass(display === "prchecks")}
onClick={() => {
setDisplay("prchecks");
}}>
PR Checks
</button>
</div>
</div>

<div className="mt-1 text-center md:text-lg text-base">
Total Rows: {display === "prchecks" ? rowsPR.length : rowsNightly.length}
</div>

<main className={"m-0 h-full px-4 overflow-x-hidden overflow-y-auto \
bg-surface-ground antialiased select-text"}>
<div>{display === "prchecks" ? renderPRTable() : renderNightlyTable()}</div>
</main>
</div>
</>
);
}
}
Loading

0 comments on commit af17d13

Please sign in to comment.