1
+ import { Button , styled } from "@mui/material" ;
1
2
import styles from "components/commit.module.css" ;
2
3
import { fetcher } from "lib/GeneralUtils" ;
3
4
import { isFailedJob } from "lib/jobUtils" ;
4
5
import { getSearchRes , LogSearchResult } from "lib/searchLogs" ;
5
6
import { Artifact , IssueData , JobData } from "lib/types" ;
7
+ import {
8
+ ListUtilizationMetadataInfoAPIResponse ,
9
+ UtilizationMetadataInfo ,
10
+ } from "lib/utilization/types" ;
6
11
import React , { useEffect , useState } from "react" ;
7
12
import useSWR from "swr" ;
8
13
import { getConclusionSeverityForSorting } from "../lib/JobClassifierUtil" ;
@@ -25,14 +30,22 @@ function sortJobsByConclusion(jobA: JobData, jobB: JobData): number {
25
30
return ( "" + jobA . jobName ) . localeCompare ( "" + jobB . jobName ) ; // the '' forces the type to be a string
26
31
}
27
32
33
+ const JobButton = styled ( Button ) ( {
34
+ fontSize : "8px" ,
35
+ padding : "0 1px 0 1px" ,
36
+ color : "green" ,
37
+ margin : "2px" ,
38
+ } ) ;
28
39
function WorkflowJobSummary ( {
29
40
job,
41
+ utilMetadata,
30
42
artifacts,
31
43
artifactsToShow,
32
44
setArtifactsToShow,
33
45
unstableIssues,
34
46
} : {
35
47
job : JobData ;
48
+ utilMetadata ?: UtilizationMetadataInfo [ ] ;
36
49
artifacts ?: Artifact [ ] ;
37
50
artifactsToShow : Set < string > ;
38
51
setArtifactsToShow : any ;
@@ -73,15 +86,34 @@ function WorkflowJobSummary({
73
86
74
87
if ( hasArtifacts ) {
75
88
subInfo . push (
76
- < a onClick = { ( ) => setArtifactsToShowHelper ( ) } > Show artifacts</ a >
89
+ < JobButton variant = "outlined" onClick = { ( ) => setArtifactsToShowHelper ( ) } >
90
+ artifacts
91
+ </ JobButton >
77
92
) ;
78
93
}
79
-
80
94
if ( job . logUrl ) {
81
95
subInfo . push (
82
- < a target = "_blank" rel = "noreferrer " href = { job . logUrl } >
96
+ < JobButton variant = "outlined " href = { job . logUrl } >
83
97
Raw logs
84
- </ a >
98
+ </ JobButton >
99
+ ) ;
100
+ }
101
+ if ( utilMetadata && utilMetadata . length > 0 ) {
102
+ if ( utilMetadata . length > 1 ) {
103
+ console . log (
104
+ `Multiple util metadata found for job ${ job . id } , currently only showing the first one`
105
+ ) ;
106
+ }
107
+ const m = utilMetadata [ 0 ] ;
108
+ subInfo . push (
109
+ < >
110
+ < JobButton
111
+ variant = "outlined"
112
+ href = { `/utilization/${ m . workflow_id } /${ m . job_id } /${ m . run_attempt } ` }
113
+ >
114
+ Utilization Report{ " " }
115
+ </ JobButton >
116
+ </ >
85
117
) ;
86
118
}
87
119
@@ -95,7 +127,7 @@ function WorkflowJobSummary({
95
127
return (
96
128
< span key = { ind } >
97
129
{ info }
98
- { ind < subInfo . length - 1 && ", " }
130
+ { ind < subInfo . length - 1 && " " }
99
131
</ span >
100
132
) ;
101
133
} ) }
@@ -124,18 +156,20 @@ export default function WorkflowBox({
124
156
setWide : any ;
125
157
repoFullName : string ;
126
158
} ) {
159
+ const workflowId = jobs [ 0 ] . workflowId ;
127
160
const isFailed = jobs . some ( isFailedJob ) !== false ;
128
161
const workflowClass = isFailed
129
162
? styles . workflowBoxFail
130
163
: styles . workflowBoxSuccess ;
131
164
132
- const workflowId = jobs [ 0 ] . workflowId ;
133
165
const anchorName = encodeURIComponent ( workflowName . toLowerCase ( ) ) ;
134
166
167
+ const { utilMetadataList } = useUtilMetadata ( workflowId ) ;
168
+ const groupUtilMetadataList = groupMetadataByJobId ( utilMetadataList ) ;
169
+
135
170
const { artifacts, error } = useArtifacts ( workflowId ) ;
136
171
const [ artifactsToShow , setArtifactsToShow ] = useState ( new Set < string > ( ) ) ;
137
172
const groupedArtifacts = groupArtifacts ( jobs , artifacts ) ;
138
-
139
173
const [ searchString , setSearchString ] = useState ( "" ) ;
140
174
const [ searchRes , setSearchRes ] = useState < {
141
175
results : Map < string , LogSearchResult > ;
@@ -144,6 +178,7 @@ export default function WorkflowBox({
144
178
results : new Map ( ) ,
145
179
info : undefined ,
146
180
} ) ;
181
+
147
182
useEffect ( ( ) => {
148
183
getSearchRes ( jobs , searchString , setSearchRes ) ;
149
184
} , [ jobs , searchString ] ) ;
@@ -216,6 +251,11 @@ export default function WorkflowBox({
216
251
< div key = { job . id } id = { `${ job . id } -box` } >
217
252
< WorkflowJobSummary
218
253
job = { job }
254
+ utilMetadata = {
255
+ job . id
256
+ ? groupUtilMetadataList . get ( job . id . toString ( ) )
257
+ : undefined
258
+ }
219
259
artifacts = { groupedArtifacts ?. get ( job . id ?. toString ( ) ) }
220
260
artifactsToShow = { artifactsToShow }
221
261
setArtifactsToShow = { setArtifactsToShow }
@@ -236,6 +276,43 @@ export default function WorkflowBox({
236
276
) ;
237
277
}
238
278
279
+ function useUtilMetadata ( workflowId : string | undefined ) : {
280
+ utilMetadataList : UtilizationMetadataInfo [ ] ;
281
+ metaError : any ;
282
+ } {
283
+ const { data, error } = useSWR < ListUtilizationMetadataInfoAPIResponse > (
284
+ `/api/list_utilization_metadata_info/${ workflowId } ` ,
285
+ fetcher ,
286
+ {
287
+ refreshInterval : 60 * 1000 , // refresh every minute
288
+ // Refresh even when the user isn't looking, so that switching to the tab
289
+ // will always have fresh info.
290
+ refreshWhenHidden : true ,
291
+ }
292
+ ) ;
293
+
294
+ if ( ! workflowId ) {
295
+ return { utilMetadataList : [ ] , metaError : "No workflow ID" } ;
296
+ }
297
+
298
+ if ( error != null ) {
299
+ return {
300
+ utilMetadataList : [ ] ,
301
+ metaError : "Error occured while fetching util metadata" ,
302
+ } ;
303
+ }
304
+
305
+ if ( data == null ) {
306
+ return { utilMetadataList : [ ] , metaError : "Loading..." } ;
307
+ }
308
+
309
+ if ( data . metadata_list == null ) {
310
+ return { utilMetadataList : [ ] , metaError : "No metadata list found" } ;
311
+ }
312
+
313
+ return { utilMetadataList : data . metadata_list , metaError : null } ;
314
+ }
315
+
239
316
function useArtifacts ( workflowId : string | undefined ) : {
240
317
artifacts : Artifact [ ] ;
241
318
error : any ;
@@ -260,6 +337,25 @@ function useArtifacts(workflowId: string | undefined): {
260
337
return { artifacts : data , error } ;
261
338
}
262
339
340
+ function groupMetadataByJobId (
341
+ utilMetadataList : UtilizationMetadataInfo [ ]
342
+ ) : Map < string , UtilizationMetadataInfo [ ] > {
343
+ const grouping = new Map < string , UtilizationMetadataInfo [ ] > ( ) ;
344
+ for ( const utilMetadata of utilMetadataList ) {
345
+ if ( ! utilMetadata . job_id ) {
346
+ continue ;
347
+ }
348
+
349
+ const jobId = utilMetadata . job_id . toString ( ) ;
350
+ if ( grouping . has ( jobId ) ) {
351
+ grouping . get ( jobId ) ! . push ( utilMetadata ) ;
352
+ } else {
353
+ grouping . set ( jobId , [ utilMetadata ] ) ;
354
+ }
355
+ }
356
+ return grouping ;
357
+ }
358
+
263
359
function groupArtifacts ( jobs : JobData [ ] , artifacts : Artifact [ ] ) {
264
360
// Group artifacts by job id if possible
265
361
const jobIds = jobs . map ( ( job ) => job . id ?. toString ( ) ) ;
0 commit comments