@@ -76,6 +76,11 @@ export default function ServiceAccounts() {
7676
7777 const toast = useToast ( ) ;
7878
79+ const currentUserTeam = outletContext . currentUser ?. teams_full ?. find (
80+ ( team ) => team . name === teamName
81+ ) ;
82+ const isOwner = currentUserTeam ?. role === "owner" ;
83+
7984 async function serviceAccountRevalidate ( ) {
8085 revalidator . revalidate ( ) ;
8186 }
@@ -84,11 +89,6 @@ export default function ServiceAccounts() {
8489 const removeServiceAccountAction = ApiAction ( {
8590 endpoint : teamServiceAccountRemove ,
8691 onSubmitSuccess : ( ) => {
87- toast . addToast ( {
88- csVariant : "success" ,
89- children : `Service account removed` ,
90- duration : 4000 ,
91- } ) ;
9292 serviceAccountRevalidate ( ) ;
9393 } ,
9494 onSubmitError : ( error ) => {
@@ -180,11 +180,13 @@ export default function ServiceAccounts() {
180180 < div className = "settings-items__meta" >
181181 < p className = "settings-items__title" > Service accounts</ p >
182182 < p className = "settings-items__description" > Your loyal servants</ p >
183- < AddServiceAccountForm
184- teamName = { teamName }
185- config = { outletContext . requestConfig }
186- serviceAccountRevalidate = { serviceAccountRevalidate }
187- />
183+ { isOwner && (
184+ < AddServiceAccountForm
185+ teamName = { teamName }
186+ config = { outletContext . requestConfig }
187+ serviceAccountRevalidate = { serviceAccountRevalidate }
188+ />
189+ ) }
188190 </ div >
189191 < div className = "settings-items__content" >
190192 < NewTable
@@ -210,6 +212,7 @@ function AddServiceAccountForm(props: {
210212 const [ addedServiceAccountToken , setAddedServiceAccountToken ] = useState ( "" ) ;
211213 const [ addedServiceAccountNickname , setAddedServiceAccountNickname ] =
212214 useState ( "" ) ;
215+ const [ error , setError ] = useState < string | null > ( null ) ;
213216
214217 function onSuccess (
215218 result : Awaited < ReturnType < typeof teamAddServiceAccount > >
@@ -219,8 +222,6 @@ function AddServiceAccountForm(props: {
219222 setAddedServiceAccountNickname ( result . nickname ) ;
220223 }
221224
222- const toast = useToast ( ) ;
223-
224225 function formFieldUpdateAction (
225226 state : TeamServiceAccountAddRequestData ,
226227 action : {
@@ -238,14 +239,17 @@ function AddServiceAccountForm(props: {
238239 nickname : "" ,
239240 } ) ;
240241
242+ const isValid =
243+ formInputs . nickname . trim ( ) . length > 0 && formInputs . nickname . length <= 32 ;
244+
241245 type SubmitorOutput = Awaited < ReturnType < typeof teamAddServiceAccount > > ;
242246
243247 async function submitor ( data : typeof formInputs ) : Promise < SubmitorOutput > {
244248 return await teamAddServiceAccount ( {
245249 config : props . config ,
246250 params : { team_name : props . teamName } ,
247251 queryParams : { } ,
248- data : { nickname : data . nickname } ,
252+ data : { nickname : data . nickname . trim ( ) } ,
249253 } ) ;
250254 }
251255
@@ -265,18 +269,15 @@ function AddServiceAccountForm(props: {
265269 submitor,
266270 onSubmitSuccess : ( result ) => {
267271 onSuccess ( result ) ;
268- toast . addToast ( {
269- csVariant : "success" ,
270- children : `Service account added` ,
271- duration : 4000 ,
272- } ) ;
272+ setError ( null ) ;
273+ // Refresh the service accounts list to show the newly created account
274+ // TODO: When API returns identifier in response, we can append the new
275+ // service account to the list instead of refreshing from backend
276+ props . serviceAccountRevalidate ?. ( ) ;
273277 } ,
274278 onSubmitError : ( error ) => {
275- toast . addToast ( {
276- csVariant : "danger" ,
277- children : `Error occurred: ${ error . message || "Unknown error" } ` ,
278- duration : 8000 ,
279- } ) ;
279+ const message = `Error occurred: ${ error . message || "Unknown error" } ` ;
280+ setError ( message ) ;
280281 } ,
281282 } ) ;
282283
@@ -286,6 +287,7 @@ function AddServiceAccountForm(props: {
286287 setServiceAccountAdded ( false ) ;
287288 setAddedServiceAccountToken ( "" ) ;
288289 setAddedServiceAccountNickname ( "" ) ;
290+ setError ( null ) ;
289291 updateFormFieldState ( { field : "nickname" , value : "" } ) ;
290292 }
291293 } ;
@@ -321,26 +323,47 @@ function AddServiceAccountForm(props: {
321323 </ Modal . Body >
322324 ) : (
323325 < Modal . Body >
324- < div >
325- Enter the nickname of the service account you wish to add to the
326- team < span > { props . teamName } </ span >
327- </ div >
328- < div >
329- < NewTextInput
330- onChange = { ( e ) => {
331- updateFormFieldState ( {
332- field : "nickname" ,
333- value : e . target . value ,
334- } ) ;
335- } }
336- placeholder = { "ExampleName" }
337- />
338- </ div >
326+ < form
327+ className = "service-accounts__form"
328+ onSubmit = { ( e ) => {
329+ e . preventDefault ( ) ;
330+ if ( isValid ) {
331+ strongForm . submit ( ) ;
332+ }
333+ } }
334+ >
335+ < div >
336+ Enter the nickname of the service account you wish to add to the
337+ team < span > { props . teamName } </ span >
338+ </ div >
339+ < div className = "service-accounts__nickname-input" >
340+ < NewTextInput
341+ onChange = { ( e ) => {
342+ updateFormFieldState ( {
343+ field : "nickname" ,
344+ value : e . target . value ,
345+ } ) ;
346+ } }
347+ placeholder = { "ExampleName" }
348+ maxLength = { 32 }
349+ />
350+ < div className = "service-accounts__nickname-input-max-length" >
351+ Max. 32 characters
352+ </ div >
353+ </ div >
354+ { error && (
355+ < div style = { { width : "100%" } } >
356+ < NewAlert csVariant = "danger" > { error } </ NewAlert >
357+ </ div >
358+ ) }
359+ </ form >
339360 </ Modal . Body >
340361 ) }
341362 { serviceAccountAdded ? null : (
342363 < Modal . Footer >
343- < NewButton onClick = { strongForm . submit } > Add Service Account</ NewButton >
364+ < NewButton onClick = { strongForm . submit } disabled = { ! isValid } >
365+ Add Service Account
366+ </ NewButton >
344367 </ Modal . Footer >
345368 ) }
346369 </ Modal >
0 commit comments