@@ -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,18 @@ function AddServiceAccountForm(props: {
238239 nickname : "" ,
239240 } ) ;
240241
242+ const isValid =
243+ formInputs . nickname . trim ( ) . length > 0 &&
244+ formInputs . nickname . trim ( ) . length <= 32 ;
245+
241246 type SubmitorOutput = Awaited < ReturnType < typeof teamAddServiceAccount > > ;
242247
243248 async function submitor ( data : typeof formInputs ) : Promise < SubmitorOutput > {
244249 return await teamAddServiceAccount ( {
245250 config : props . config ,
246251 params : { team_name : props . teamName } ,
247252 queryParams : { } ,
248- data : { nickname : data . nickname } ,
253+ data : { nickname : data . nickname . trim ( ) } ,
249254 } ) ;
250255 }
251256
@@ -265,18 +270,15 @@ function AddServiceAccountForm(props: {
265270 submitor,
266271 onSubmitSuccess : ( result ) => {
267272 onSuccess ( result ) ;
268- toast . addToast ( {
269- csVariant : "success" ,
270- children : `Service account added` ,
271- duration : 4000 ,
272- } ) ;
273+ setError ( null ) ;
274+ // Refresh the service accounts list to show the newly created account
275+ // TODO: When API returns identifier in response, we can append the new
276+ // service account to the list instead of refreshing from backend
277+ props . serviceAccountRevalidate ?. ( ) ;
273278 } ,
274279 onSubmitError : ( error ) => {
275- toast . addToast ( {
276- csVariant : "danger" ,
277- children : `Error occurred: ${ error . message || "Unknown error" } ` ,
278- duration : 8000 ,
279- } ) ;
280+ const message = `Error occurred: ${ error . message || "Unknown error" } ` ;
281+ setError ( message ) ;
280282 } ,
281283 } ) ;
282284
@@ -286,6 +288,7 @@ function AddServiceAccountForm(props: {
286288 setServiceAccountAdded ( false ) ;
287289 setAddedServiceAccountToken ( "" ) ;
288290 setAddedServiceAccountNickname ( "" ) ;
291+ setError ( null ) ;
289292 updateFormFieldState ( { field : "nickname" , value : "" } ) ;
290293 }
291294 } ;
@@ -321,26 +324,44 @@ function AddServiceAccountForm(props: {
321324 </ Modal . Body >
322325 ) : (
323326 < 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 >
327+ < form
328+ className = "service-accounts__form"
329+ onSubmit = { ( e ) => {
330+ e . preventDefault ( ) ;
331+ if ( isValid ) {
332+ strongForm . submit ( ) ;
333+ }
334+ } }
335+ >
336+ < div >
337+ Enter the nickname of the service account you wish to add to the
338+ team < span > { props . teamName } </ span >
339+ </ div >
340+ < div className = "service-accounts__nickname-input" >
341+ < NewTextInput
342+ value = { formInputs . nickname }
343+ onChange = { ( e ) => {
344+ updateFormFieldState ( {
345+ field : "nickname" ,
346+ value : e . target . value ,
347+ } ) ;
348+ } }
349+ placeholder = { "ExampleName" }
350+ maxLength = { 32 }
351+ />
352+ < div className = "service-accounts__nickname-input-max-length" >
353+ Max. 32 characters
354+ </ div >
355+ </ div >
356+ { error && < NewAlert csVariant = "danger" > { error } </ NewAlert > }
357+ </ form >
339358 </ Modal . Body >
340359 ) }
341360 { serviceAccountAdded ? null : (
342361 < Modal . Footer >
343- < NewButton onClick = { strongForm . submit } > Add Service Account</ NewButton >
362+ < NewButton onClick = { strongForm . submit } disabled = { ! isValid } >
363+ Add Service Account
364+ </ NewButton >
344365 </ Modal . Footer >
345366 ) }
346367 </ Modal >
0 commit comments