@@ -104,45 +104,52 @@ export default function UserDetail(p: { user: User }) {
104
104
< div className = "flex w-full mt-6" >
105
105
< Property name = "Sign Up Date" > { moment ( user . creationDate ) . format ( 'MMM D, YYYY' ) } </ Property >
106
106
< Property name = "Remaining Hours"
107
- action = {
108
- accountStatement && {
107
+ actions = {
108
+ accountStatement && [ {
109
109
label : 'View Account Statement' ,
110
110
onClick : ( ) => setViewAccountStatement ( true )
111
- }
111
+ } , {
112
+ label : 'Grant 20 Extra Hours' ,
113
+ onClick : async ( ) => {
114
+ await getGitpodService ( ) . server . adminGrantExtraHours ( user . id , 20 ) ;
115
+ setAccountStatement ( await getGitpodService ( ) . server . adminGetAccountStatement ( user . id ) ) ;
116
+ }
117
+ } ]
112
118
}
113
119
> { accountStatement ?. remainingHours ? accountStatement ?. remainingHours . toString ( ) : '---' } </ Property >
114
120
< Property
115
121
name = "Plan"
116
- action = { accountStatement && {
122
+ actions = { accountStatement && [ {
117
123
label : ( isProfessionalOpenSource ? 'Disable' : 'Enable' ) + ' Professional OSS' ,
118
- onClick : ( ) => {
119
- getGitpodService ( ) . server . adminSetProfessionalOpenSource ( user . id , ! isProfessionalOpenSource ) ;
124
+ onClick : async ( ) => {
125
+ await getGitpodService ( ) . server . adminSetProfessionalOpenSource ( user . id , ! isProfessionalOpenSource ) ;
126
+ setAccountStatement ( await getGitpodService ( ) . server . adminGetAccountStatement ( user . id ) ) ;
120
127
}
121
- } }
128
+ } ] }
122
129
> { accountStatement ?. subscriptions ? accountStatement . subscriptions . filter ( s => Subscription . isActive ( s , new Date ( ) . toISOString ( ) ) ) . map ( s => Plans . getById ( s . planId ) ?. name ) . join ( ', ' ) : '---' } </ Property >
123
130
</ div >
124
131
< div className = "flex w-full mt-6" >
125
132
< Property name = "Feature Flags"
126
- action = { {
133
+ actions = { [ {
127
134
label : 'Edit Feature Flags' ,
128
135
onClick : ( ) => {
129
136
setEditFeatureFlags ( true ) ;
130
137
}
131
- } }
138
+ } ] }
132
139
> { user . featureFlags ?. permanentWSFeatureFlags ?. join ( ', ' ) || '---' } </ Property >
133
140
< Property name = "Roles"
134
- action = { {
141
+ actions = { [ {
135
142
label : 'Edit Roles' ,
136
143
onClick : ( ) => {
137
144
setEditRoles ( true ) ;
138
145
}
139
- } }
146
+ } ] }
140
147
> { user . rolesOrPermissions ?. join ( ', ' ) || '---' } </ Property >
141
148
< Property name = "Student"
142
- action = { ! isStudent ? {
149
+ actions = { ! isStudent ? [ {
143
150
label : `Make '${ emailDomain } ' a student domain` ,
144
151
onClick : addStudentDomain
145
- } : undefined }
152
+ } ] : undefined }
146
153
> { isStudent === undefined ? '---' : ( isStudent ? 'Enabled' : 'Disabled' ) } </ Property >
147
154
</ div >
148
155
</ div >
@@ -185,17 +192,19 @@ function Label(p: { text: string, color: string }) {
185
192
return < div className = { `ml-3 text-sm text-${ p . color } -600 truncate bg-${ p . color } -100 px-1.5 py-0.5 rounded-md my-auto` } > { p . text } </ div > ;
186
193
}
187
194
188
- export function Property ( p : { name : string , children : string | ReactChild , action ?: { label : string , onClick : ( ) => void } } ) {
195
+ export function Property ( p : { name : string , children : string | ReactChild , actions ?: { label : string , onClick : ( ) => void } [ ] } ) {
189
196
return < div className = "ml-3 flex flex-col w-4/12 truncate" >
190
197
< div className = "text-base text-gray-500 truncate" >
191
198
{ p . name }
192
199
</ div >
193
200
< div className = "text-lg text-gray-600 font-semibold truncate" >
194
201
{ p . children }
195
202
</ div >
196
- < div className = "cursor-pointer text-sm text-blue-400 hover:text-blue-500 truncate" onClick = { p . action ?. onClick } >
197
- { p . action ?. label || '' }
198
- </ div >
203
+ { ( p . actions || [ ] ) . map ( a =>
204
+ < div className = "cursor-pointer text-sm text-blue-400 hover:text-blue-500 truncate" onClick = { a . onClick } >
205
+ { a . label || '' }
206
+ </ div >
207
+ ) }
199
208
</ div > ;
200
209
}
201
210
@@ -253,4 +262,4 @@ function getRopEntries(user: User, updateUser: UpdateUserFunction): Entry[] {
253
262
...Object . entries ( Permissions ) . map ( e => createRopEntry ( e [ 0 ] as RoleOrPermission ) ) ,
254
263
...Object . entries ( Roles ) . map ( e => createRopEntry ( e [ 0 ] as RoleOrPermission , true ) )
255
264
] ;
256
- } ;
265
+ } ;
0 commit comments