88 NewTextInput ,
99 Heading ,
1010 CodeBox ,
11- useToast ,
1211} from "@thunderstore/cyberstorm" ;
1312import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
1413import { faPlus } from "@fortawesome/free-solid-svg-icons" ;
@@ -73,6 +72,11 @@ export default function ServiceAccounts() {
7372
7473 const revalidator = useRevalidator ( ) ;
7574
75+ const currentUserTeam = outletContext . currentUser ?. teams_full ?. find (
76+ ( team ) => team . name === teamName
77+ ) ;
78+ const isOwner = currentUserTeam ?. role === "owner" ;
79+
7680 async function serviceAccountRevalidate ( ) {
7781 revalidator . revalidate ( ) ;
7882 }
@@ -116,11 +120,13 @@ export default function ServiceAccounts() {
116120 < div className = "settings-items__meta" >
117121 < p className = "settings-items__title" > Service accounts</ p >
118122 < p className = "settings-items__description" > Your loyal servants</ p >
119- < AddServiceAccountForm
120- teamName = { teamName }
121- config = { outletContext . requestConfig }
122- serviceAccountRevalidate = { serviceAccountRevalidate }
123- />
123+ { isOwner && (
124+ < AddServiceAccountForm
125+ teamName = { teamName }
126+ config = { outletContext . requestConfig }
127+ serviceAccountRevalidate = { serviceAccountRevalidate }
128+ />
129+ ) }
124130 </ div >
125131 < div className = "settings-items__content" >
126132 < NewTable
@@ -146,6 +152,7 @@ function AddServiceAccountForm(props: {
146152 const [ addedServiceAccountToken , setAddedServiceAccountToken ] = useState ( "" ) ;
147153 const [ addedServiceAccountNickname , setAddedServiceAccountNickname ] =
148154 useState ( "" ) ;
155+ const [ error , setError ] = useState < string | null > ( null ) ;
149156
150157 function onSuccess (
151158 result : Awaited < ReturnType < typeof teamAddServiceAccount > >
@@ -155,8 +162,6 @@ function AddServiceAccountForm(props: {
155162 setAddedServiceAccountNickname ( result . nickname ) ;
156163 }
157164
158- const toast = useToast ( ) ;
159-
160165 function formFieldUpdateAction (
161166 state : TeamServiceAccountAddRequestData ,
162167 action : {
@@ -174,14 +179,16 @@ function AddServiceAccountForm(props: {
174179 nickname : "" ,
175180 } ) ;
176181
182+ const isValid = formInputs . nickname . trim ( ) . length > 0 ;
183+
177184 type SubmitorOutput = Awaited < ReturnType < typeof teamAddServiceAccount > > ;
178185
179186 async function submitor ( data : typeof formInputs ) : Promise < SubmitorOutput > {
180187 return await teamAddServiceAccount ( {
181188 config : props . config ,
182189 params : { team_name : props . teamName } ,
183190 queryParams : { } ,
184- data : { nickname : data . nickname } ,
191+ data : { nickname : data . nickname . trim ( ) } ,
185192 } ) ;
186193 }
187194
@@ -201,18 +208,15 @@ function AddServiceAccountForm(props: {
201208 submitor,
202209 onSubmitSuccess : ( result ) => {
203210 onSuccess ( result ) ;
204- toast . addToast ( {
205- csVariant : "success" ,
206- children : `Service account added` ,
207- duration : 4000 ,
208- } ) ;
211+ setError ( null ) ;
212+ // Refresh the service accounts list to show the newly created account
213+ // TODO: When API returns identifier in response, we can append the new
214+ // service account to the list instead of refreshing from backend
215+ props . serviceAccountRevalidate ?. ( ) ;
209216 } ,
210217 onSubmitError : ( error ) => {
211- toast . addToast ( {
212- csVariant : "danger" ,
213- children : `Error occurred: ${ error . message || "Unknown error" } ` ,
214- duration : 8000 ,
215- } ) ;
218+ const message = `Error occurred: ${ error . message || "Unknown error" } ` ;
219+ setError ( message ) ;
216220 } ,
217221 } ) ;
218222
@@ -222,6 +226,7 @@ function AddServiceAccountForm(props: {
222226 setServiceAccountAdded ( false ) ;
223227 setAddedServiceAccountToken ( "" ) ;
224228 setAddedServiceAccountNickname ( "" ) ;
229+ setError ( null ) ;
225230 updateFormFieldState ( { field : "nickname" , value : "" } ) ;
226231 }
227232 } ;
@@ -257,30 +262,44 @@ function AddServiceAccountForm(props: {
257262 </ Modal . Body >
258263 ) : (
259264 < Modal . Body >
260- < div >
261- Enter the nickname of the service account you wish to add to the
262- team < span > { props . teamName } </ span >
263- </ div >
264- < div className = "service-accounts__nickname-input" >
265- < NewTextInput
266- onChange = { ( e ) => {
267- updateFormFieldState ( {
268- field : "nickname" ,
269- value : e . target . value ,
270- } ) ;
271- } }
272- placeholder = { "ExampleName" }
273- maxLength = { 32 }
274- />
275- < div className = "service-accounts__nickname-input-max-length" >
276- Max. 32 characters
265+ < form
266+ className = "service-accounts__form"
267+ onSubmit = { ( e ) => {
268+ e . preventDefault ( ) ;
269+ if ( isValid ) {
270+ strongForm . submit ( ) ;
271+ }
272+ } }
273+ >
274+ < div >
275+ Enter the nickname of the service account you wish to add to the
276+ team < span > { props . teamName } </ span >
277277 </ div >
278- </ div >
278+ < div className = "service-accounts__nickname-input" >
279+ < NewTextInput
280+ value = { formInputs . nickname }
281+ onChange = { ( e ) => {
282+ updateFormFieldState ( {
283+ field : "nickname" ,
284+ value : e . target . value ,
285+ } ) ;
286+ } }
287+ placeholder = { "ExampleName" }
288+ maxLength = { 32 }
289+ />
290+ < div className = "service-accounts__nickname-input-max-length" >
291+ Max. 32 characters
292+ </ div >
293+ </ div >
294+ { error && < NewAlert csVariant = "danger" > { error } </ NewAlert > }
295+ </ form >
279296 </ Modal . Body >
280297 ) }
281298 { serviceAccountAdded ? null : (
282299 < Modal . Footer >
283- < NewButton onClick = { strongForm . submit } > Add Service Account</ NewButton >
300+ < NewButton onClick = { strongForm . submit } disabled = { ! isValid } >
301+ Add Service Account
302+ </ NewButton >
284303 </ Modal . Footer >
285304 ) }
286305 </ Modal >
0 commit comments