@@ -9,31 +9,39 @@ import MaintainerMapping from "../maintainers.yml";
99
1010export default function Home ( ) {
1111 const [ loading , setLoading ] = useState ( true ) ;
12+ const [ checks , setChecks ] = useState ( [ ] ) ;
1213 const [ jobs , setJobs ] = useState ( [ ] ) ;
13- const [ rows , setRows ] = useState ( [ ] ) ;
14+ const [ rowsPR , setRowsPR ] = useState ( [ ] ) ;
15+ const [ rowsNightly , setRowsNightly ] = useState ( [ ] ) ;
1416 const [ expandedRows , setExpandedRows ] = useState ( [ ] ) ;
1517 const [ requiredFilter , setRequiredFilter ] = useState ( false ) ;
18+ const [ display , setDisplay ] = useState ( "nightly" ) ;
1619
1720 useEffect ( ( ) => {
1821 const fetchData = async ( ) => {
19- let data = { } ;
22+ let nightlyData = { } ;
23+ let prData = { } ;
2024
2125 if ( process . env . NODE_ENV === "development" ) {
22- data = ( await import ( "../localData/job_stats.json" ) ) . default ;
26+ nightlyData = ( await import ( "../localData/job_stats.json" ) ) . default ;
27+ prData = ( await import ( "../localData/check_stats.json" ) ) . default ;
2328 } else {
24- const response = await fetch (
29+ nightlyData = await fetch (
2530 "https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
2631 "/refs/heads/latest-dashboard-data/data/job_stats.json"
27- ) ;
28- data = await response . json ( ) ;
32+ ) . then ( ( res ) => res . json ( ) ) ;
33+ prData = await fetch (
34+ "https://raw.githubusercontent.com/kata-containers/kata-containers.github.io" +
35+ "/refs/heads/latest-dashboard-data/data/check_stats.json"
36+ ) . then ( ( res ) => res . json ( ) ) ;
2937 }
3038
3139 try {
32- const jobData = Object . keys ( data ) . map ( ( key ) => {
33- const job = data [ key ] ;
34- return { name : key , ... job } ;
35- } ) ;
36- setJobs ( jobData ) ;
40+ const mapData = ( data ) => Object . keys ( data ) . map ( ( key ) =>
41+ ( { name : key , ... data [ key ] } )
42+ ) ;
43+ setJobs ( mapData ( nightlyData ) ) ;
44+ setChecks ( mapData ( prData ) ) ;
3745 } catch ( error ) {
3846 // TODO: Add pop-up/toast message for error
3947 console . error ( "Error fetching data:" , error ) ;
@@ -54,14 +62,12 @@ export default function Home() {
5462 return filteredJobs ;
5563 } ;
5664
65+ // Filter and set the rows for Nightly view.
5766 useEffect ( ( ) => {
5867 setLoading ( true ) ;
59-
60- // Filter based on required tag.
6168 let filteredJobs = filterRequired ( jobs ) ;
62-
6369 //Set the rows for the table.
64- setRows (
70+ setRowsNightly (
6571 filteredJobs . map ( ( job ) => ( {
6672 name : job . name ,
6773 runs : job . runs ,
@@ -74,6 +80,31 @@ export default function Home() {
7480 setLoading ( false ) ;
7581 } , [ jobs , requiredFilter ] ) ;
7682
83+ // Filter and set the rows for PR Checks view.
84+ useEffect ( ( ) => {
85+ setLoading ( true ) ;
86+ let filteredChecks = filterRequired ( checks )
87+
88+ //Set the rows for the table.
89+ setRowsPR (
90+ filteredChecks . map ( ( check ) => ( {
91+ name : check . name ,
92+ runs : check . runs ,
93+ fails : check . fails ,
94+ skips : check . skips ,
95+ required : check . required ,
96+ weather : getWeatherIndex ( check ) ,
97+ } ) )
98+ ) ;
99+ setLoading ( false ) ;
100+ } , [ checks , requiredFilter ] ) ;
101+
102+ // Close all rows on view switch.
103+ // Needed because if view is switched, breaks expanded row toggling.
104+ useEffect ( ( ) => {
105+ setExpandedRows ( [ ] )
106+ } , [ display ] ) ;
107+
77108 const toggleRow = ( rowData ) => {
78109 const isRowExpanded = expandedRows . includes ( rowData ) ;
79110
@@ -91,6 +122,10 @@ export default function Home() {
91122 ${ active ? "border-blue-500 bg-blue-500 text-white"
92123 : "border-gray-300 bg-white hover:bg-gray-100" } `;
93124
125+ const tabClass = ( active ) => `tab md:px-4 px-2 py-2 border-b-2 focus:outline-none
126+ ${ active ? "border-blue-500 bg-gray-300"
127+ : "border-gray-300 bg-white hover:bg-gray-100" } `;
128+
94129
95130 // Template for rendering the Name column as a clickable item
96131 const nameTemplate = ( rowData ) => {
@@ -104,7 +139,9 @@ export default function Home() {
104139 const maintainRefs = useRef ( [ ] ) ;
105140
106141 const rowExpansionTemplate = ( data ) => {
107- const job = jobs . find ( ( job ) => job . name === data . name ) ;
142+ const job = ( display === "nightly"
143+ ? jobs
144+ : checks ) . find ( ( job ) => job . name === data . name ) ;
108145
109146 // Prepare run data
110147 const runs = [ ] ;
@@ -115,7 +152,7 @@ export default function Home() {
115152 url : job . urls [ i ] ,
116153 } ) ;
117154 }
118-
155+
119156 // Find maintainers for the given job
120157 const maintainerData = MaintainerMapping . mappings
121158 . filter ( ( { regex } ) => new RegExp ( regex ) . test ( job . name ) )
@@ -135,6 +172,7 @@ export default function Home() {
135172 return acc ;
136173 } , { } ) ;
137174
175+
138176 return (
139177 < div key = { `${ job . name } -runs` } className = "p-3 bg-gray-100" >
140178 { /* Display last 10 runs */ }
@@ -149,7 +187,7 @@ export default function Home() {
149187 : "⚠️" ;
150188 return (
151189 < span key = { `${ job . name } -runs-${ run . run_num } ` } >
152- < a href = { run . url } >
190+ < a href = { run . url } target = "_blank" rel = "noopener noreferrer" >
153191 { emoji } { run . run_num }
154192 </ a >
155193
@@ -251,9 +289,10 @@ export default function Home() {
251289 ) ;
252290 } ;
253291
254- const renderTable = ( ) => (
292+ // Render table for nightly view.
293+ const renderNightlyTable = ( ) => (
255294 < DataTable
256- value = { rows }
295+ value = { rowsNightly }
257296 expandedRows = { expandedRows }
258297 stripedRows
259298 rowExpansionTemplate = { rowExpansionTemplate }
@@ -263,27 +302,63 @@ export default function Home() {
263302 sortField = "fails"
264303 sortOrder = { - 1 }
265304 >
266- < Column expander style = { { width : "5rem" } } />
305+ < Column expander />
267306 < Column
268307 field = "name"
269308 header = "Name"
270309 body = { nameTemplate }
271- filter
310+ className = "select-text"
272311 sortable
273- maxConstraints = { 4 }
274- filterHeader = "Filter by Name"
275- filterPlaceholder = "Search..."
276312 />
277- < Column field = "required" header = "Required" sortable />
278- < Column field = "runs" header = "Runs" sortable />
279- < Column field = "fails" header = "Fails" sortable />
280- < Column field = "skips" header = "Skips" sortable />
313+ < Column field = "required" header = "Required" sortable />
314+ < Column
315+ field = "runs"
316+ header = "Runs"
317+ className = "whitespace-nowrap px-2"
318+ sortable />
319+ < Column field = "fails" header = "Fails" sortable />
320+ < Column field = "skips" header = "Skips" sortable />
321+ < Column
322+ field = "weather"
323+ header = "Weather"
324+ body = { weatherTemplate }
325+ sortable />
326+ </ DataTable >
327+ ) ;
328+
329+ const renderPRTable = ( ) => (
330+ < DataTable
331+ value = { rowsPR }
332+ expandedRows = { expandedRows }
333+ stripedRows
334+ rowExpansionTemplate = { rowExpansionTemplate }
335+ onRowToggle = { ( e ) => setExpandedRows ( e . data ) }
336+ loading = { loading }
337+ emptyMessage = "No results found."
338+ sortField = "fails"
339+ sortOrder = { - 1 }
340+ >
341+ < Column expander />
281342 < Column
282- field = "weather"
283- header = "Weather"
284- body = { weatherTemplate }
343+ field = "name"
344+ header = "Name"
345+ body = { nameTemplate }
346+ className = "select-text"
285347 sortable
286348 />
349+ < Column field = "required" header = "Required" sortable />
350+ < Column
351+ field = "runs"
352+ header = "Runs"
353+ className = "whitespace-nowrap px-2"
354+ sortable />
355+ < Column field = "fails" header = "Fails" sortable />
356+ < Column field = "skips" header = "Skips" sortable />
357+ < Column
358+ field = "weather"
359+ header = "Weather"
360+ body = { weatherTemplate }
361+ sortable />
287362 </ DataTable >
288363 ) ;
289364
@@ -299,30 +374,49 @@ export default function Home() {
299374 }
300375 >
301376 < a
302- href = {
303- "https://github.com/kata-containers/kata-containers/" +
304- "actions/workflows/ci-nightly.yaml"
305- }
306- target = "_blank"
307- rel = "noopener noreferrer"
308- >
309- Kata CI Dashboard
310- </ a >
377+ href = { display === 'nightly'
378+ ? "https://github.com/kata-containers/kata-containers/" +
379+ "actions/workflows/ci-nightly.yaml"
380+ : "https://github.com/kata-containers/kata-containers/" +
381+ "/pulls?state=closed" }
382+ target = "_blank"
383+ rel = "noopener noreferrer"
384+ >
385+ Kata CI Dashboard
386+ </ a >
311387 </ h1 >
388+ < div className = "flex flex-wrap mt-2 p-4 md:text-base text-xs" >
389+ < div className = "space-x-2 pb-2 pr-3 mx-auto flex" >
390+ < button
391+ className = { tabClass ( display === "nightly" ) }
392+ onClick = { ( ) => {
393+ setDisplay ( "nightly" ) ;
394+ } } >
395+ Nightly Jobs
396+ </ button >
397+ < button
398+ className = { tabClass ( display === "prchecks" ) }
399+ onClick = { ( ) => {
400+ setDisplay ( "prchecks" ) ;
401+ } } >
402+ PR Checks
403+ </ button >
404+ </ div >
405+ </ div >
312406
313- < main
314- className = {
315- "m-0 h-full p-4 overflow-x-hidden overflow-y-auto bg-surface-ground font-normal text-text-color antialiased select-text"
316- }
317- >
407+
408+ < div className = { "m-0 h-full px-4 overflow-x-hidden overflow-y-auto \
409+ bg-surface-ground antialiased select-text" } >
318410 < button
319- className = { buttonClass ( requiredFilter ) }
320- onClick = { ( ) => setRequiredFilter ( ! requiredFilter ) } >
321- Required Jobs Only
411+ className = { buttonClass ( requiredFilter ) }
412+ onClick = { ( ) => setRequiredFilter ( ! requiredFilter ) } >
413+ Required Jobs Only
322414 </ button >
323- < div className = "mt-4 text-lg" > Total Rows: { rows . length } </ div >
324- < div > { renderTable ( ) } </ div >
325- </ main >
415+ < div className = "mt-4 text-center md:text-lg text-base" >
416+ Total Rows: { display === "prchecks" ? rowsPR . length : rowsNightly . length }
417+ </ div >
418+ < div > { display === "prchecks" ? renderPRTable ( ) : renderNightlyTable ( ) } </ div >
419+ </ div >
326420 </ div >
327421 ) ;
328422}
0 commit comments