1+
12import { useEffect , useState } from "react" ;
23import { DataTable } from "primereact/datatable" ;
34import { Column } from "primereact/column" ;
@@ -7,29 +8,36 @@ import { weatherTemplate, getWeatherIndex } from "../components/weatherTemplate"
78export 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