Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions app/components/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import './form.css'
interface FormActionsProps {
formId?: string
children: React.ReactNode
submitDisabled?: boolean
/** Must be provided with a reason why the submit button is disabled */
submitDisabled?: string
loading?: boolean
error?: Error | null
className?: string
}
Expand All @@ -27,9 +29,10 @@ export const Form = {
Actions: ({
children,
formId,
submitDisabled = true,
submitDisabled,
error,
className,
loading,
}: FormActionsProps) => {
const childArray = flattenChildren(children)

Expand All @@ -49,7 +52,12 @@ export const Form = {
className
)}
>
{cloneElement(submit, { form: formId, disabled: submitDisabled })}
{cloneElement(submit, {
form: formId,
disabled: !!submitDisabled,
disabledReason: submitDisabled,
loading,
})}
{childArray}
{error && (
<div className="flex !shrink grow items-start justify-end text-mono-sm text-error">
Expand Down
12 changes: 8 additions & 4 deletions app/components/form/FullPageForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ interface FullPageFormProps<TFieldValues extends FieldValues> {
id: string
title: string
icon: ReactElement
submitDisabled?: boolean
/** Must provide a reason for submit being disabled */
submitDisabled?: string
error?: Error
formOptions: UseFormProps<TFieldValues>
loading?: boolean
onSubmit: (values: TFieldValues) => void
/** Error from the API call */
submitError: ErrorResult | null
Expand All @@ -37,14 +39,15 @@ export function FullPageForm<TFieldValues extends FieldValues>({
id,
title,
children,
submitDisabled = false,
submitDisabled,
error,
icon,
loading,
formOptions,
onSubmit,
}: FullPageFormProps<TFieldValues>) {
const form = useForm(formOptions)
const { isSubmitting, isDirty } = form.formState
const { isSubmitting, isSubmitSuccessful } = form.formState

const childArray = flattenChildren(children(form))
const actions = pluckFirstOfType(childArray, Form.Actions)
Expand All @@ -62,7 +65,8 @@ export function FullPageForm<TFieldValues extends FieldValues>({
<PageActionsContainer>
{cloneElement(actions, {
formId: id,
submitDisabled: submitDisabled || isSubmitting || !isDirty,
submitDisabled,
loading: loading || isSubmitting || isSubmitSuccessful,
error,
})}
</PageActionsContainer>
Expand Down
20 changes: 14 additions & 6 deletions app/components/form/SideModalForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ type SideModalFormProps<TFieldValues extends FieldValues> = {
*/
children: (form: UseFormReturn<TFieldValues>) => ReactNode
onDismiss: () => void
submitDisabled?: boolean
/** Must be provided with a reason describing why it's disabled */
submitDisabled?: string
/** Error from the API call */
submitError: ErrorResult | null
loading?: boolean
title: string
onSubmit: (values: TFieldValues) => void
submitLabel?: string
Expand All @@ -33,19 +35,18 @@ export function SideModalForm<TFieldValues extends FieldValues>({
formOptions,
children,
onDismiss,
submitDisabled = false,
submitDisabled,
submitError,
title,
onSubmit,
submitLabel,
loading,
}: SideModalFormProps<TFieldValues>) {
// TODO: RHF docs warn about the performance impact of validating on every
// change
const form = useForm({ mode: 'all', ...formOptions })

const { isDirty, isValid } = form.formState

const canSubmit = isDirty && isValid
const { isSubmitting, isSubmitSuccessful } = form.formState

/**
* Only animate the modal in when we're navigating by a client-side click.
Expand Down Expand Up @@ -87,7 +88,14 @@ export function SideModalForm<TFieldValues extends FieldValues>({
<Button variant="ghost" size="sm" onClick={onDismiss}>
Cancel
</Button>
<Button type="submit" size="sm" disabled={submitDisabled || !canSubmit} form={id}>
<Button
type="submit"
size="sm"
disabled={!!submitDisabled}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The button is still clickable while the request is going through, which means you can submit multiple times. Rather than changing Button internally so that loading also causes it to be disabled, I think I prefer keeping the disabled prop as the only one that can actually disable the button and changing the call to be something like this:

Suggested change
disabled={!!submitDisabled}
disabled={!!submitDisabled || loading || isSubmitting}

Copy link
Contributor Author

@just-be-dev just-be-dev Nov 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that, I'd left out some logic. We have to supply loading with the proper state in order to provide the visual indication that it is indeed loading. Given we need to supply that state and it seems like invalid behavior to have a button both loading and clickable then it seems reasonable to expect the loading prop would disable the button.

If we don't then we must always pass the loading state twice in the same component usage. Not doing so would result in a bug.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's true. We'd never want a button clickable while loading. Fine with me.

disabledReason={submitDisabled}
loading={loading || isSubmitting || isSubmitSuccessful}
form={id}
>
{submitLabel || title}
</Button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/forms/disk-attach.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function AttachDiskSideModalForm({
})
})
}
submitDisabled={attachDisk.isLoading}
loading={attachDisk.isLoading}
submitError={attachDisk.error}
onDismiss={onDismiss}
>
Expand Down
2 changes: 1 addition & 1 deletion app/forms/disk-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function CreateDiskSideModalForm({
const body = { size: size * GiB, ...rest }
onSubmit ? onSubmit(body) : createDisk.mutate({ path: pathParams, body })
}}
submitDisabled={createDisk.isLoading}
loading={createDisk.isLoading}
submitError={createDisk.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/firewall-rules-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ export function CreateFirewallRuleForm({
},
})
}}
submitDisabled={updateRules.isLoading}
loading={updateRules.isLoading}
submitError={updateRules.error}
submitLabel="Add rule"
>
Expand Down
2 changes: 1 addition & 1 deletion app/forms/firewall-rules-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function EditFirewallRuleForm({
}}
// validationSchema={validationSchema}
// validateOnBlur
submitDisabled={updateRules.isLoading}
loading={updateRules.isLoading}
submitError={updateRules.error}
submitLabel="Update rule"
>
Expand Down
2 changes: 1 addition & 1 deletion app/forms/instance-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export function CreateInstanceForm() {
},
})
}}
submitDisabled={createInstance.isLoading}
loading={createInstance.isLoading}
submitError={createInstance.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/network-interface-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default function CreateNetworkInterfaceForm({
})
})
}
submitDisabled={createNetworkInterface.isLoading}
loading={createNetworkInterface.isLoading}
submitError={createNetworkInterface.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/network-interface-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function EditNetworkInterfaceForm({
body,
})
}}
submitDisabled={editNetworkInterface.isLoading}
loading={editNetworkInterface.isLoading}
submitError={editNetworkInterface.error}
submitLabel="Save changes"
>
Expand Down
4 changes: 2 additions & 2 deletions app/forms/org-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function OrgAccessAddUserSideModal({ onDismiss, policy }: AddRoleModalPro
body: setUserRole(userId, roleName, policy),
})
}}
submitDisabled={updatePolicy.isLoading}
loading={updatePolicy.isLoading}
submitError={updatePolicy.error}
submitLabel="Add user"
>
Expand Down Expand Up @@ -95,7 +95,7 @@ export function OrgAccessEditUserSideModal({
body: setUserRole(userId, roleName, policy),
})
}}
submitDisabled={updatePolicy.isLoading || !policy}
loading={updatePolicy.isLoading}
submitError={updatePolicy.error}
onDismiss={onDismiss}
submitLabel="Update role"
Expand Down
2 changes: 1 addition & 1 deletion app/forms/org-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function CreateOrgSideModalForm() {
title="Create organization"
onDismiss={() => navigate(pb.orgs())}
onSubmit={(values) => createOrg.mutate({ body: values })}
submitDisabled={createOrg.isLoading}
loading={createOrg.isLoading}
submitError={createOrg.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/org-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function EditOrgSideModalForm() {
body: { name, description },
})
}
submitDisabled={updateOrg.isLoading}
loading={updateOrg.isLoading}
submitError={updateOrg.error}
submitLabel="Save changes"
>
Expand Down
4 changes: 2 additions & 2 deletions app/forms/project-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function ProjectAccessAddUserSideModal({ onDismiss, policy }: AddRoleModa
body: setUserRole(userId, roleName, policy),
})
}}
submitDisabled={updatePolicy.isLoading}
loading={updatePolicy.isLoading}
submitError={updatePolicy.error}
submitLabel="Add user"
onDismiss={onDismiss}
Expand Down Expand Up @@ -96,7 +96,7 @@ export function ProjectAccessEditUserSideModal({
body: setUserRole(userId, roleName, policy),
})
}}
submitDisabled={updatePolicy.isLoading || !policy}
loading={updatePolicy.isLoading}
submitError={updatePolicy.error}
submitLabel="Update role"
onDismiss={onDismiss}
Expand Down
2 changes: 1 addition & 1 deletion app/forms/project-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function CreateProjectSideModalForm() {
body: { name, description },
})
}}
submitDisabled={createProject.isLoading}
loading={createProject.isLoading}
submitError={createProject.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/project-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function EditProjectSideModalForm() {
body: { name, description },
})
}}
submitDisabled={editProject.isLoading}
loading={editProject.isLoading}
submitError={editProject.error}
submitLabel="Save changes"
>
Expand Down
4 changes: 2 additions & 2 deletions app/forms/silo-access.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function SiloAccessAddUserSideModal({ onDismiss, policy }: AddRoleModalPr
body: setUserRole(userId, roleName, policy),
})
}}
submitDisabled={updatePolicy.isLoading}
loading={updatePolicy.isLoading}
submitError={updatePolicy.error}
submitLabel="Add user"
>
Expand Down Expand Up @@ -88,7 +88,7 @@ export function SiloAccessEditUserSideModal({
body: setUserRole(userId, roleName, policy),
})
}}
submitDisabled={updatePolicy.isLoading || !policy}
loading={updatePolicy.isLoading}
submitError={updatePolicy.error}
submitLabel="Update role"
onDismiss={onDismiss}
Expand Down
2 changes: 1 addition & 1 deletion app/forms/silo-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function CreateSiloSideModalForm() {
body: { name, description, discoverable, identityMode },
})
}
submitDisabled={createSilo.isLoading}
loading={createSilo.isLoading}
submitError={createSilo.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/ssh-key-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function CreateSSHKeySideModalForm() {
formOptions={{ defaultValues }}
onDismiss={onDismiss}
onSubmit={(body) => createSshKey.mutate({ body })}
submitDisabled={createSshKey.isLoading}
loading={createSshKey.isLoading}
submitError={createSshKey.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/subnet-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function CreateSubnetForm({ onDismiss }: CreateSubnetFormProps) {
formOptions={{ defaultValues }}
onDismiss={onDismiss}
onSubmit={(body) => createSubnet.mutate({ path: parentNames, body })}
submitDisabled={createSubnet.isLoading}
loading={createSubnet.isLoading}
submitError={createSubnet.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/subnet-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function EditSubnetForm({ onDismiss, editing }: EditSubnetFormProps) {
body,
})
}}
submitDisabled={updateSubnet.isLoading}
loading={updateSubnet.isLoading}
submitError={updateSubnet.error}
submitLabel="Update subnet"
>
Expand Down
2 changes: 1 addition & 1 deletion app/forms/vpc-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function CreateVpcSideModalForm() {
formOptions={{ defaultValues }}
onSubmit={(values) => createVpc.mutate({ path: parentNames, body: values })}
onDismiss={() => navigate(pb.vpcs(parentNames))}
submitDisabled={createVpc.isLoading}
loading={createVpc.isLoading}
submitError={createVpc.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/vpc-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function EditVpcSideModalForm() {
body: { name, description, dnsName },
})
}}
submitDisabled={editVpc.isLoading}
loading={editVpc.isLoading}
submitLabel="Save changes"
submitError={editVpc.error}
>
Expand Down
2 changes: 1 addition & 1 deletion app/forms/vpc-router-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function CreateVpcRouterForm({ onDismiss }: CreateVpcRouterFormProps) {
onSubmit={({ name, description }) =>
createRouter.mutate({ path: parentNames, body: { name, description } })
}
submitDisabled={createRouter.isLoading}
loading={createRouter.isLoading}
submitError={createRouter.error}
>
{({ control }) => (
Expand Down
2 changes: 1 addition & 1 deletion app/forms/vpc-router-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function EditVpcRouterForm({ onDismiss, editing }: EditVpcRouterFormProps
body: { name, description },
})
}}
submitDisabled={updateRouter.isLoading}
loading={updateRouter.isLoading}
submitError={updateRouter.error}
>
{({ control }) => (
Expand Down
Loading