@@ -75,6 +75,8 @@ export default function Home() {
75
75
skips : job . skips ,
76
76
required : job . required ,
77
77
weather : getWeatherIndex ( job ) ,
78
+ reruns : job . reruns ,
79
+ total_reruns : job . reruns . reduce ( ( total , r ) => total + r , 0 ) ,
78
80
} ) )
79
81
) ;
80
82
setLoading ( false ) ;
@@ -94,6 +96,8 @@ export default function Home() {
94
96
skips : check . skips ,
95
97
required : check . required ,
96
98
weather : getWeatherIndex ( check ) ,
99
+ reruns : check . reruns ,
100
+ total_reruns : check . reruns . reduce ( ( total , r ) => total + r , 0 ) ,
97
101
} ) )
98
102
) ;
99
103
setLoading ( false ) ;
@@ -137,21 +141,43 @@ export default function Home() {
137
141
} ;
138
142
139
143
const maintainRefs = useRef ( [ ] ) ;
144
+ const rerunRefs = useRef ( [ ] ) ;
140
145
141
146
const rowExpansionTemplate = ( data ) => {
142
147
const job = ( display === "nightly"
143
148
? jobs
144
149
: checks ) . find ( ( job ) => job . name === data . name ) ;
145
150
151
+ if ( ! job ) return (
152
+ < div className = "p-3 bg-gray-100" >
153
+ No data available for this job.
154
+ </ div >
155
+ ) ;
156
+
146
157
// Prepare run data
147
- const runs = [ ] ;
148
- for ( let i = 0 ; i < job . runs ; i ++ ) {
149
- runs . push ( {
150
- run_num : job . run_nums [ i ] ,
151
- result : job . results [ i ] ,
152
- url : job . urls [ i ] ,
153
- } ) ;
154
- }
158
+ const getRunStatusIcon = ( runs ) => {
159
+ if ( Array . isArray ( runs ) ) {
160
+ const allPass = runs . every ( run => run === "Pass" ) ;
161
+ const allFail = runs . every ( run => run === "Fail" ) ;
162
+
163
+ if ( allPass ) { return "✅" ; }
164
+ if ( allFail ) { return "❌" ; }
165
+ } else if ( runs === "Pass" ) {
166
+ return "✅" ;
167
+ } else if ( runs === "Fail" ) {
168
+ return "❌" ;
169
+ }
170
+ return "⚠️" ; // return a warning if a mix of results
171
+ } ;
172
+
173
+ const runEntries = job . run_nums . map ( ( run_num , idx ) => ( {
174
+ run_num,
175
+ result : job . results [ idx ] ,
176
+ reruns : job . reruns [ idx ] ,
177
+ rerun_result : job . rerun_results [ idx ] ,
178
+ url : job . urls [ idx ] ,
179
+ attempt_urls : job . attempt_urls [ idx ] ,
180
+ } ) ) ;
155
181
156
182
// Find maintainers for the given job
157
183
const maintainerData = MaintainerMapping . mappings
@@ -177,28 +203,70 @@ export default function Home() {
177
203
< div key = { `${ job . name } -runs` } className = "p-3 bg-gray-100" >
178
204
{ /* Display last 10 runs */ }
179
205
< div className = "flex flex-wrap gap-4" >
180
- { runs . length > 0 ? (
181
- runs . map ( ( run ) => {
182
- const emoji =
183
- run . result === "Pass"
184
- ? "✅"
185
- : run . result === "Fail"
186
- ? "❌"
187
- : "⚠️" ;
188
- return (
189
- < span key = { `${ job . name } -runs-${ run . run_num } ` } >
190
- < a href = { run . url } target = "_blank" rel = "noopener noreferrer" >
191
- { emoji } { run . run_num }
206
+ { runEntries . map ( ( {
207
+ run_num,
208
+ result,
209
+ url,
210
+ reruns,
211
+ rerun_result,
212
+ attempt_urls
213
+ } , idx ) => {
214
+ const allResults = rerun_result
215
+ ? [ result , ...rerun_result ]
216
+ : [ result ] ;
217
+
218
+ const runStatuses = allResults . map ( ( result , idx ) =>
219
+ `${ allResults . length - idx } . ${ result === 'Pass'
220
+ ? '✅ Success'
221
+ : result === 'Fail'
222
+ ? '❌ Fail'
223
+ : '⚠️ Warning' } `) ;
224
+
225
+ // IDs can't have a '/'...
226
+ const sanitizedJobName = job . name . replace ( / [ ^ a - z A - Z 0 - 9 - _ ] / g, '' ) ;
227
+
228
+ const badgeReruns = `reruns-${ sanitizedJobName } -${ run_num } ` ;
229
+
230
+ rerunRefs . current [ badgeReruns ] = rerunRefs . current [ badgeReruns ]
231
+ || React . createRef ( ) ;
232
+
233
+ return (
234
+ < div key = { run_num } className = "flex" >
235
+ < div key = { idx } className = "flex items-center" >
236
+ { /* <a href={url} target="_blank" rel="noopener noreferrer"> */ }
237
+ < a href = { attempt_urls [ 0 ] } target = "_blank" rel = "noopener noreferrer" >
238
+ { getRunStatusIcon ( allResults ) } { run_num }
192
239
</ a >
193
-
194
- </ span >
195
- ) ;
196
- } )
197
- ) : (
198
- < div > No Nightly Runs associated with this job</ div >
199
- ) }
240
+ </ div >
241
+ { reruns > 0 && (
242
+ < span className = "p-overlay-badge" >
243
+ < sup className = "text-xs font-bold align-super ml-1"
244
+ onMouseEnter = { ( e ) =>
245
+ rerunRefs . current [ badgeReruns ] . current . toggle ( e ) } >
246
+ { reruns + 1 }
247
+ </ sup >
248
+ < OverlayPanel ref = { rerunRefs . current [ badgeReruns ] } dismissable
249
+ onMouseLeave = { ( e ) =>
250
+ rerunRefs . current [ badgeReruns ] . current . toggle ( e ) } >
251
+ < ul className = "bg-white border rounded shadow-lg p-2" >
252
+ { runStatuses . map ( ( status , index ) => (
253
+ < li key = { index } className = "p-2 hover:bg-gray-200" >
254
+ < a
255
+ href = { attempt_urls [ index ] || `${ url } /attempts/${ index } ` }
256
+ target = "_blank"
257
+ rel = "noopener noreferrer" >
258
+ { status }
259
+ </ a >
260
+ </ li >
261
+ ) ) }
262
+ </ ul >
263
+ </ OverlayPanel >
264
+ </ span >
265
+ ) }
266
+ </ div >
267
+ ) ;
268
+ } ) }
200
269
</ div >
201
-
202
270
{ /* Display Maintainers, if there's any */ }
203
271
< div className = "mt-4 p-2 bg-gray-300 w-full" >
204
272
{ Object . keys ( groupedMaintainers ) . length > 0 ? (
@@ -316,6 +384,7 @@ export default function Home() {
316
384
header = "Runs"
317
385
className = "whitespace-nowrap px-2"
318
386
sortable />
387
+ < Column field = "total_reruns" header = "Reruns" sortable />
319
388
< Column field = "fails" header = "Fails" sortable />
320
389
< Column field = "skips" header = "Skips" sortable />
321
390
< Column
@@ -352,6 +421,7 @@ export default function Home() {
352
421
header = "Runs"
353
422
className = "whitespace-nowrap px-2"
354
423
sortable />
424
+ < Column field = "total_reruns" header = "Reruns" sortable />
355
425
< Column field = "fails" header = "Fails" sortable />
356
426
< Column field = "skips" header = "Skips" sortable />
357
427
< Column
0 commit comments