@@ -20,6 +20,7 @@ import {
20
20
PopoverTrigger ,
21
21
} from "components/Popover/Popover" ;
22
22
import { Stack } from "components/Stack/Stack" ;
23
+ import { StatusIndicator } from "components/StatusIndicator/StatusIndicator" ;
23
24
import { type FC , useState } from "react" ;
24
25
import { createDayString } from "utils/createDayString" ;
25
26
import { docs } from "utils/docs" ;
@@ -31,7 +32,7 @@ interface ProvisionerGroupProps {
31
32
readonly buildInfo ?: BuildInfoResponse ;
32
33
readonly keyName ?: string ;
33
34
readonly type : ProvisionerGroupType ;
34
- readonly provisioners : ProvisionerDaemon [ ] ;
35
+ readonly provisioners : readonly ProvisionerDaemon [ ] ;
35
36
}
36
37
37
38
export const ProvisionerGroup : FC < ProvisionerGroupProps > = ( {
@@ -40,36 +41,65 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
40
41
type,
41
42
provisioners,
42
43
} ) => {
43
- const [ provisioner ] = provisioners ;
44
44
const theme = useTheme ( ) ;
45
45
46
46
const [ showDetails , setShowDetails ] = useState ( false ) ;
47
47
48
- const daemonScope = provisioner . tags . scope || "organization" ;
49
- const iconScope = daemonScope === "organization" ? < Business /> : < Person /> ;
48
+ const firstProvisioner = provisioners [ 0 ] ;
49
+ if ( ! firstProvisioner ) {
50
+ return null ;
51
+ }
50
52
51
- const provisionerVersion = provisioner . version ;
53
+ const daemonScope = firstProvisioner . tags . scope || "organization" ;
52
54
const allProvisionersAreSameVersion = provisioners . every (
53
- ( provisioner ) => provisioner . version === provisionerVersion ,
55
+ ( it ) => it . version === firstProvisioner . version ,
54
56
) ;
55
- const upToDate =
56
- allProvisionersAreSameVersion && buildInfo ?. version === provisioner . version ;
57
+ const provisionerVersion = allProvisionersAreSameVersion
58
+ ? firstProvisioner . version
59
+ : null ;
57
60
const provisionerCount =
58
61
provisioners . length === 1
59
62
? "1 provisioner"
60
63
: `${ provisioners . length } provisioners` ;
61
-
62
- const extraTags = Object . entries ( provisioner . tags ) . filter (
64
+ const extraTags = Object . entries ( firstProvisioner . tags ) . filter (
63
65
( [ key ] ) => key !== "scope" && key !== "owner" ,
64
66
) ;
65
67
68
+ let warnings = 0 ;
69
+ let provisionersWithWarnings = 0 ;
70
+ const provisionersWithWarningInfo = provisioners . map ( ( it ) => {
71
+ const outOfDate = Boolean ( buildInfo ) && it . version !== buildInfo ?. version ;
72
+ const warningCount = outOfDate ? 1 : 0 ;
73
+ warnings += warningCount ;
74
+ if ( warnings > 0 ) {
75
+ provisionersWithWarnings ++ ;
76
+ }
77
+
78
+ return { ...it , warningCount, outOfDate } ;
79
+ } ) ;
80
+
81
+ const hasWarning = warnings > 0 ;
82
+ const warningsCount =
83
+ warnings === 0
84
+ ? "No warnings"
85
+ : warnings === 1
86
+ ? "1 warning"
87
+ : `${ warnings } warnings` ;
88
+ const provisionersWithWarningsCount =
89
+ provisionersWithWarnings === 1
90
+ ? "1 provisioner"
91
+ : `${ provisionersWithWarnings } provisioners` ;
92
+
66
93
return (
67
94
< div
68
- css = { {
69
- borderRadius : 8 ,
70
- border : `1px solid ${ theme . palette . divider } ` ,
71
- fontSize : 14 ,
72
- } }
95
+ css = { [
96
+ {
97
+ borderRadius : 8 ,
98
+ border : `1px solid ${ theme . palette . divider } ` ,
99
+ fontSize : 14 ,
100
+ } ,
101
+ hasWarning && styles . warningBorder ,
102
+ ] }
73
103
>
74
104
< header
75
105
css = { {
@@ -80,48 +110,39 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
80
110
gap : 24 ,
81
111
} }
82
112
>
83
- < div
84
- css = { {
85
- display : "flex" ,
86
- alignItems : "center" ,
87
- gap : 24 ,
88
- objectFit : "fill" ,
89
- } }
90
- >
91
- { type === "builtin" && (
92
- < div css = { { lineHeight : "160%" } } >
93
- < BuiltinProvisionerTitle />
94
- < span css = { { color : theme . palette . text . secondary } } >
95
- { provisionerCount } — Built-in
96
- </ span >
97
- </ div >
98
- ) }
99
- { type === "psk" && (
100
- < div css = { { lineHeight : "160%" } } >
101
- < PskProvisionerTitle />
102
- < span css = { { color : theme . palette . text . secondary } } >
103
- { provisionerCount } —{ " " }
104
- { allProvisionersAreSameVersion ? (
105
- < code > { provisionerVersion } </ code >
106
- ) : (
107
- < span > Multiple versions</ span >
108
- ) }
109
- </ span >
110
- </ div >
111
- ) }
112
- { type === "key" && (
113
- < div css = { { lineHeight : "160%" } } >
113
+ < div css = { { display : "flex" , alignItems : "center" , gap : 16 } } >
114
+ < StatusIndicator color = { hasWarning ? "warning" : "success" } />
115
+ < div
116
+ css = { {
117
+ display : "flex" ,
118
+ flexDirection : "column" ,
119
+ lineHeight : 1.5 ,
120
+ } }
121
+ >
122
+ { type === "builtin" && (
123
+ < >
124
+ < BuiltinProvisionerTitle />
125
+ < span css = { { color : theme . palette . text . secondary } } >
126
+ { provisionerCount } — Built-in
127
+ </ span >
128
+ </ >
129
+ ) }
130
+
131
+ { type === "psk" && < PskProvisionerTitle /> }
132
+ { type === "key" && (
114
133
< h4 css = { styles . groupTitle } > Key group – { keyName } </ h4 >
134
+ ) }
135
+ { type !== "builtin" && (
115
136
< span css = { { color : theme . palette . text . secondary } } >
116
137
{ provisionerCount } —{ " " }
117
- { allProvisionersAreSameVersion ? (
138
+ { provisionerVersion ? (
118
139
< code > { provisionerVersion } </ code >
119
140
) : (
120
141
< span > Multiple versions</ span >
121
142
) }
122
143
</ span >
123
- </ div >
124
- ) }
144
+ ) }
145
+ </ div >
125
146
</ div >
126
147
< div
127
148
css = { {
@@ -133,7 +154,10 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
133
154
} }
134
155
>
135
156
< Tooltip title = "Scope" >
136
- < Pill size = "lg" icon = { iconScope } >
157
+ < Pill
158
+ size = "lg"
159
+ icon = { daemonScope === "organization" ? < Business /> : < Person /> }
160
+ >
137
161
< span css = { { textTransform : "capitalize" } } > { daemonScope } </ span >
138
162
</ Pill >
139
163
</ Tooltip >
@@ -153,16 +177,19 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
153
177
flexWrap : "wrap" ,
154
178
} }
155
179
>
156
- { provisioners . map ( ( provisioner ) => (
180
+ { provisionersWithWarningInfo . map ( ( provisioner ) => (
157
181
< div
158
182
key = { provisioner . id }
159
- css = { {
160
- borderRadius : 8 ,
161
- border : `1px solid ${ theme . palette . divider } ` ,
162
- fontSize : 14 ,
163
- padding : "14px 18px" ,
164
- width : 375 ,
165
- } }
183
+ css = { [
184
+ {
185
+ borderRadius : 8 ,
186
+ border : `1px solid ${ theme . palette . divider } ` ,
187
+ fontSize : 14 ,
188
+ padding : "14px 18px" ,
189
+ width : 375 ,
190
+ } ,
191
+ provisioner . warningCount > 0 && styles . warningBorder ,
192
+ ] }
166
193
>
167
194
< Stack
168
195
direction = "row"
@@ -215,7 +242,10 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
215
242
color : theme . palette . text . secondary ,
216
243
} }
217
244
>
218
- < span > No warnings from { provisionerCount } </ span >
245
+ < span >
246
+ { warningsCount } from{ " " }
247
+ { hasWarning ? provisionersWithWarningsCount : provisionerCount }
248
+ </ span >
219
249
< Button
220
250
variant = "text"
221
251
css = { {
@@ -379,6 +409,10 @@ const PskProvisionerTitle: FC = () => {
379
409
} ;
380
410
381
411
const styles = {
412
+ warningBorder : ( theme ) => ( {
413
+ borderColor : theme . roles . warning . fill . outline ,
414
+ } ) ,
415
+
382
416
groupTitle : {
383
417
fontWeight : 500 ,
384
418
margin : 0 ,
@@ -389,7 +423,7 @@ const styles = {
389
423
marginBottom : 0 ,
390
424
color : theme . palette . text . primary ,
391
425
fontSize : 14 ,
392
- lineHeight : "150%" ,
426
+ lineHeight : 1.5 ,
393
427
fontWeight : 600 ,
394
428
} ) ,
395
429
0 commit comments