Skip to content

Commit 2124cdb

Browse files
committed
form handling improvements
1 parent efa919f commit 2124cdb

14 files changed

Lines changed: 106 additions & 107 deletions

File tree

frontend/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
"@furystack/cache": "^6.0.0",
2222
"@furystack/core": "^15.1.0",
2323
"@furystack/entity-sync": "^0.1.1",
24-
"@furystack/entity-sync-client": "^0.1.1",
24+
"@furystack/entity-sync-client": "^0.2.0",
2525
"@furystack/inject": "^12.0.30",
2626
"@furystack/logging": "^8.0.30",
2727
"@furystack/rest-client-fetch": "^8.0.37",
28-
"@furystack/shades": "^12.1.0",
29-
"@furystack/shades-common-components": "^12.3.0",
28+
"@furystack/shades": "^12.2.0",
29+
"@furystack/shades-common-components": "^12.4.0",
3030
"@furystack/utils": "^8.1.10",
3131
"common": "workspace:^"
3232
}

frontend/src/components/entity-forms/dependency-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ export const DependencyForm = Shade<DependencyFormProps>({
2828
<Form<DependencyFormPayload>
2929
validate={isDependencyFormPayload}
3030
onSubmit={(data) =>
31-
void props.onSubmit({
31+
props.onSubmit({
3232
stackName: props.stackName,
3333
name: data.name,
3434
checkCommand: data.checkCommand,
3535
installationHelp: data.installationHelp,
3636
})
3737
}
38+
disableOnSubmit
3839
style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '600px' }}
3940
>
4041
<h2 style={{ margin: '0' }}>{props.mode === 'create' ? 'Add Dependency' : 'Edit Dependency'}</h2>

frontend/src/components/entity-forms/github-repo-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ export const GitHubRepoForm = Shade<GitHubRepoFormProps>({
2929
<Form<GitHubRepoFormPayload>
3030
validate={isGitHubRepoFormPayload}
3131
onSubmit={(data) =>
32-
void props.onSubmit({
32+
props.onSubmit({
3333
stackName: props.stackName,
3434
url: data.url,
3535
displayName: data.displayName,
3636
description: data.description,
3737
})
3838
}
39+
disableOnSubmit
3940
style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '600px' }}
4041
>
4142
<h2 style={{ margin: '0' }}>{props.mode === 'create' ? 'Add GitHub Repository' : 'Edit Repository'}</h2>

frontend/src/components/entity-forms/service-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const ServiceForm = Shade<ServiceFormProps>({
3737
<Form<ServiceFormPayload>
3838
validate={isServiceFormPayload}
3939
onSubmit={(data) =>
40-
void props.onSubmit({
40+
props.onSubmit({
4141
stackName: props.stackName,
4242
displayName: data.displayName,
4343
description: data.description,
@@ -51,6 +51,7 @@ export const ServiceForm = Shade<ServiceFormProps>({
5151
autoRestartOnFetch: data.autoRestartOnFetch === 'on',
5252
})
5353
}
54+
disableOnSubmit
5455
style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '600px' }}
5556
>
5657
<h2 style={{ margin: '0' }}>{props.mode === 'create' ? 'Create Service' : 'Edit Service'}</h2>

frontend/src/components/entity-forms/stack-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ export const StackForm = Shade<StackFormProps>({
2929
<Form<StackFormPayload>
3030
validate={isStackFormPayload}
3131
onSubmit={(data) =>
32-
void props.onSubmit({
32+
props.onSubmit({
3333
name: data.name,
3434
displayName: data.displayName,
3535
description: data.description,
3636
mainDirectory: data.mainDirectory,
3737
})
3838
}
39+
disableOnSubmit
3940
style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '600px' }}
4041
>
4142
<h2 style={{ margin: '0' }}>{props.mode === 'create' ? 'Create Stack' : 'Edit Stack'}</h2>

frontend/src/pages/import-export/import-stack.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export const ImportStack = Shade({
3535
const [jsonInput, setJsonInput] = useState('json', '')
3636
const [parsed, setParsed] = useState<ParsedExport | null>('parsed', null)
3737
const [parseError, setParseError] = useState('parseError', '')
38-
const [isImporting, setIsImporting] = useState('isImporting', false)
3938

4039
const handleParse = () => {
4140
try {
@@ -55,7 +54,6 @@ export const ImportStack = Shade({
5554

5655
const handleImport = async (formData: ImportConfigPayload) => {
5756
if (!parsed) return
58-
setIsImporting(true)
5957
try {
6058
await injector.getInstance(StacksApiClient).call({
6159
method: 'POST',
@@ -83,7 +81,6 @@ export const ImportStack = Shade({
8381
type: 'error',
8482
})
8583
}
86-
setIsImporting(false)
8784
}
8885

8986
return (
@@ -133,7 +130,7 @@ export const ImportStack = Shade({
133130
</div>
134131
</Paper>
135132
) : (
136-
<Form<ImportConfigPayload> validate={isImportConfigPayload} onSubmit={(data) => void handleImport(data)}>
133+
<Form<ImportConfigPayload> validate={isImportConfigPayload} onSubmit={handleImport} disableOnSubmit>
137134
<Paper elevation={1} style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
138135
<h3 style={{ margin: '0' }}>Import: {parsed.stack.displayName}</h3>
139136
<div style={{ display: 'flex', gap: '24px', flexWrap: 'wrap' }}>
@@ -169,7 +166,6 @@ export const ImportStack = Shade({
169166
<Button
170167
type="submit"
171168
variant="contained"
172-
loading={isImporting}
173169
startIcon={<Icon icon={icons.upload} size="small" />}
174170
>
175171
Import

frontend/src/pages/installer/create-admin-step.tsx

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,21 @@ const isAdminPayload = (data: unknown): data is AdminPayload => {
1515

1616
export const CreateAdminStep = Shade<WizardStepProps>({
1717
shadowDomName: 'shade-create-admin-step',
18-
render: ({ props, injector, useState }) => {
19-
const [isInstalling, setIsInstalling] = useState('isInstalling', false)
20-
21-
const handleSubmit = (data: AdminPayload) => {
22-
setIsInstalling(true)
23-
injector
24-
.getInstance(InstallApiClient)
25-
.call({
26-
method: 'POST',
27-
action: '/install',
28-
body: data,
29-
})
30-
.then(() => {
31-
props.onNext?.()
32-
setIsInstalling(false)
33-
})
34-
.catch(() => {
35-
setIsInstalling(false)
36-
})
18+
render: ({ props, injector }) => {
19+
const handleSubmit = async (data: AdminPayload) => {
20+
await injector.getInstance(InstallApiClient).call({
21+
method: 'POST',
22+
action: '/install',
23+
body: data,
24+
})
25+
props.onNext?.()
3726
}
3827

3928
return (
4029
<Form<AdminPayload>
4130
validate={isAdminPayload}
4231
onSubmit={handleSubmit}
32+
disableOnSubmit
4333
style={{
4434
padding: '32px',
4535
display: 'flex',
@@ -61,7 +51,6 @@ export const CreateAdminStep = Shade<WizardStepProps>({
6151
labelTitle="Username"
6252
type="text"
6353
required
64-
disabled={isInstalling}
6554
getHelperText={() => 'Choose a username for the admin account'}
6655
/>
6756
<Input
@@ -72,7 +61,6 @@ export const CreateAdminStep = Shade<WizardStepProps>({
7261
autocomplete="off"
7362
minLength={4}
7463
required
75-
disabled={isInstalling}
7664
getHelperText={() => 'Must be at least 4 characters'}
7765
/>
7866
</div>
@@ -83,7 +71,6 @@ export const CreateAdminStep = Shade<WizardStepProps>({
8371
<Button
8472
type="submit"
8573
disabled={props.currentPage > props.maxPages - 1}
86-
loading={isInstalling}
8774
variant="contained"
8875
color={props.currentPage === props.maxPages - 1 ? 'success' : 'primary'}
8976
>

frontend/src/pages/login.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,17 @@ export const Login = Shade({
131131
validate={(data): data is LoginPayload => {
132132
return (data as LoginPayload).userName?.length > 0 && (data as LoginPayload).password?.length > 0
133133
}}
134-
onSubmit={({ userName, password }) => {
135-
void sessionService.login(userName, password)
134+
onSubmit={async ({ userName, password }) => {
135+
await sessionService.login(userName, password)
136136
}}
137+
disableOnSubmit
137138
>
138139
<div className="login-fields">
139140
<Input
140141
labelTitle="Username"
141142
name="userName"
142143
autofocus
143144
required
144-
disabled={isOperationInProgress}
145145
variant="outlined"
146146
type="text"
147147
getStartIcon={() => <Icon icon={icons.user} size="small" />}
@@ -150,7 +150,6 @@ export const Login = Shade({
150150
labelTitle="Password"
151151
name="password"
152152
required
153-
disabled={isOperationInProgress}
154153
variant="outlined"
155154
type="password"
156155
getStartIcon={() => <Icon icon={icons.lock} size="small" />}
@@ -167,7 +166,6 @@ export const Login = Shade({
167166
<Button
168167
type="submit"
169168
variant="contained"
170-
disabled={isOperationInProgress}
171169
loading={isOperationInProgress}
172170
>
173171
Sign in

frontend/src/pages/settings/api-tokens-section.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ export const ApiTokensSection = Shade({
3131
filter: currentUser ? { username: { $eq: currentUser.username } } : undefined,
3232
})
3333

34-
const [isCreating, setIsCreating] = useState('isCreating', false)
3534
const [revokingTokenId, setRevokingTokenId] = useState<string | null>('revokingTokenId', null)
3635

3736
const handleCreateToken = async (payload: CreateTokenPayload) => {
38-
setIsCreating(true)
3937
try {
4038
const { result } = await tokensApi.call({
4139
method: 'POST',
@@ -50,8 +48,6 @@ export const ApiTokensSection = Shade({
5048
})
5149
} catch {
5250
notys.emit('onNotyAdded', { title: 'Error', body: 'Failed to create token.', type: 'error' })
53-
} finally {
54-
setIsCreating(false)
5551
}
5652
}
5753

@@ -98,14 +94,14 @@ export const ApiTokensSection = Shade({
9894

9995
<Form<CreateTokenPayload>
10096
validate={isCreateTokenPayload}
101-
onSubmit={(data) => void handleCreateToken(data)}
97+
onSubmit={handleCreateToken}
98+
disableOnSubmit
10299
style={{ display: 'flex', gap: '8px', marginBottom: '16px', alignItems: 'center' }}
103100
>
104101
<Input variant="outlined" labelTitle="Token name" name="name" style={{ flex: '1' }} required />
105102
<Button
106103
variant="contained"
107104
type="submit"
108-
loading={isCreating}
109105
startIcon={<Icon icon={icons.plus} size="small" />}
110106
style={{ height: '100%', display: 'flex', alignItems: 'center' }}
111107
>

frontend/src/pages/settings/password-change-form.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ export const PasswordChangeForm = Shade({
2121
const notys = injector.getInstance(NotyService)
2222

2323
const [newPassword, setNewPassword] = useState('newPassword', '')
24-
const [isSubmitting, setIsSubmitting] = useState('isSubmitting', false)
2524

2625
const handleSubmit = async (payload: PasswordChangePayload) => {
27-
setIsSubmitting(true)
2826
try {
2927
await identityApi.call({
3028
method: 'POST',
@@ -41,8 +39,6 @@ export const PasswordChangeForm = Shade({
4139
})
4240
} catch {
4341
notys.emit('onNotyAdded', { title: 'Error', body: 'Failed to change password.', type: 'error' })
44-
} finally {
45-
setIsSubmitting(false)
4642
}
4743
}
4844

@@ -54,7 +50,8 @@ export const PasswordChangeForm = Shade({
5450
</h3>
5551
<Form<PasswordChangePayload>
5652
validate={isPasswordChangePayload}
57-
onSubmit={(data) => void handleSubmit(data)}
53+
onSubmit={handleSubmit}
54+
disableOnSubmit
5855
style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}
5956
>
6057
<Input name="currentPassword" labelTitle="Current Password" type="password" variant="outlined" required />
@@ -84,7 +81,6 @@ export const PasswordChangeForm = Shade({
8481
<Button
8582
type="submit"
8683
variant="contained"
87-
loading={isSubmitting}
8884
startIcon={<Icon icon={icons.save} size="small" />}
8985
style={{ alignSelf: 'flex-start' }}
9086
>

0 commit comments

Comments
 (0)