Skip to content

Commit 0469280

Browse files
authored
Make SideModal submit button copy consistent (#2048)
* Make SideModal button copy consistent * Refactor and remove title from most create forms * Add name of user/group to 'change role' form
1 parent 8c30305 commit 0469280

40 files changed

+119
-89
lines changed

app/components/form/SideModalForm.tsx

+27-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import { useEffect, type ReactNode } from 'react'
8+
import { useEffect, useId, type ReactNode } from 'react'
99
import type { FieldValues, UseFormReturn } from 'react-hook-form'
1010
import { useNavigationType } from 'react-router-dom'
1111

@@ -14,8 +14,19 @@ import type { ApiError } from '@oxide/api'
1414
import { Button } from '~/ui/lib/Button'
1515
import { SideModal } from '~/ui/lib/SideModal'
1616

17+
type CreateFormProps = {
18+
formType: 'create'
19+
/** Only needed if you need to override the default button text (`Create ${resourceName}`) */
20+
submitLabel?: string
21+
}
22+
23+
type EditFormProps = {
24+
formType: 'edit'
25+
/** Not permitted, as all edit form buttons should read `Update ${resourceName}` */
26+
submitLabel?: never
27+
}
28+
1729
type SideModalFormProps<TFieldValues extends FieldValues> = {
18-
id: string
1930
form: UseFormReturn<TFieldValues>
2031
/**
2132
* A function that returns the fields.
@@ -27,16 +38,17 @@ type SideModalFormProps<TFieldValues extends FieldValues> = {
2738
*/
2839
children: ReactNode
2940
onDismiss: () => void
41+
resourceName: string
3042
/** Must be provided with a reason describing why it's disabled */
3143
submitDisabled?: string
3244
/** Error from the API call */
3345
submitError: ApiError | null
3446
loading?: boolean
35-
title: string
47+
/** Only needed if you need to override the default title (Create/Edit ${resourceName}) */
48+
title?: string
3649
subtitle?: ReactNode
3750
onSubmit?: (values: TFieldValues) => void
38-
submitLabel?: string
39-
}
51+
} & (CreateFormProps | EditFormProps)
4052

4153
/**
4254
* Only animate the modal in when we're navigating by a client-side click.
@@ -49,10 +61,11 @@ export function useShouldAnimateModal() {
4961
}
5062

5163
export function SideModalForm<TFieldValues extends FieldValues>({
52-
id,
5364
form,
65+
formType,
5466
children,
5567
onDismiss,
68+
resourceName,
5669
submitDisabled,
5770
submitError,
5871
title,
@@ -61,6 +74,7 @@ export function SideModalForm<TFieldValues extends FieldValues>({
6174
loading,
6275
subtitle,
6376
}: SideModalFormProps<TFieldValues>) {
77+
const id = useId()
6478
const { isSubmitting } = form.formState
6579

6680
useEffect(() => {
@@ -70,11 +84,16 @@ export function SideModalForm<TFieldValues extends FieldValues>({
7084
}
7185
}, [submitError, form])
7286

87+
const label =
88+
formType === 'edit'
89+
? `Update ${resourceName}`
90+
: submitLabel || title || `Create ${resourceName}`
91+
7392
return (
7493
<SideModal
7594
onDismiss={onDismiss}
7695
isOpen
77-
title={title}
96+
title={title || `${formType === 'edit' ? 'Edit' : 'Create'} ${resourceName}`}
7897
animate={useShouldAnimateModal()}
7998
subtitle={subtitle}
8099
errors={submitError ? [submitError.message] : []}
@@ -111,7 +130,7 @@ export function SideModalForm<TFieldValues extends FieldValues>({
111130
loading={loading || isSubmitting}
112131
form={id}
113132
>
114-
{submitLabel || title}
133+
{label}
115134
</Button>
116135
)}
117136
</SideModal.Footer>

app/forms/access-util.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export type AddRoleModalProps = {
5050
}
5151

5252
export type EditRoleModalProps = AddRoleModalProps & {
53+
name?: string
5354
identityId: string
5455
identityType: IdentityType
5556
defaultValues: { roleName: RoleKey }

app/forms/disk-attach.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ export function AttachDiskSideModalForm({
4646

4747
return (
4848
<SideModalForm
49-
id="form-disk-attach"
50-
title="Attach Disk"
5149
form={form}
50+
formType="create"
51+
resourceName="disk"
52+
title="Attach Disk"
5253
onSubmit={onSubmit}
5354
loading={loading}
5455
submitError={submitError}

app/forms/disk-create.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ export function CreateDiskSideModalForm({
100100

101101
return (
102102
<SideModalForm
103-
id="create-disk-form"
104-
title="Create Disk"
105103
form={form}
104+
formType="create"
105+
resourceName="disk"
106106
onDismiss={() => onDismiss(navigate)}
107107
onSubmit={({ size, ...rest }) => {
108108
const body = { size: size * GiB, ...rest }

app/forms/firewall-rules-create.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,10 @@ export function CreateFirewallRuleForm({
504504

505505
return (
506506
<SideModalForm
507-
id="create-firewall-rule-form"
508-
title="Add firewall rule"
509507
form={form}
508+
formType="create"
509+
resourceName="rule"
510+
title="Add firewall rule"
510511
onDismiss={onDismiss}
511512
onSubmit={(values) => {
512513
// TODO: this silently overwrites existing rules with the current name.

app/forms/firewall-rules-edit.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ export function EditFirewallRuleForm({
6565

6666
return (
6767
<SideModalForm
68-
id="create-firewall-rule-form"
69-
title="Edit rule"
7068
form={form}
69+
formType="edit"
70+
resourceName="rule"
7171
onDismiss={onDismiss}
7272
onSubmit={(values) => {
7373
// note different filter logic from create: filter out the rule with the
@@ -86,7 +86,6 @@ export function EditFirewallRuleForm({
8686
// validateOnBlur
8787
loading={updateRules.isPending}
8888
submitError={updateRules.error}
89-
submitLabel="Update rule"
9089
>
9190
<CommonFields error={updateRules.error} control={form.control} />
9291
</SideModalForm>

app/forms/floating-ip-create.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ export function CreateFloatingIpSideModalForm() {
8383

8484
return (
8585
<SideModalForm
86-
id="create-floating-ip-form"
87-
title="Create Floating IP"
8886
form={form}
87+
formType="create"
88+
resourceName="floating IP"
8989
onDismiss={() => navigate(pb.floatingIps(projectSelector))}
9090
onSubmit={({ ip, ...rest }) => {
9191
createFloatingIp.mutate({

app/forms/floating-ip-edit.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ export function EditFloatingIpSideModalForm() {
5555

5656
return (
5757
<SideModalForm
58-
id="edit-floating-ip-form"
5958
form={form}
60-
title="Edit floating IP"
59+
formType="edit"
60+
resourceName="floating IP"
6161
onDismiss={onDismiss}
6262
onSubmit={({ name, description }) => {
6363
editFloatingIp.mutate({
@@ -68,7 +68,6 @@ export function EditFloatingIpSideModalForm() {
6868
}}
6969
loading={editFloatingIp.isPending}
7070
submitError={editFloatingIp.error}
71-
submitLabel="Save changes"
7271
>
7372
<NameField name="name" control={form.control} />
7473
<DescriptionField name="description" control={form.control} />

app/forms/idp/create.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ export function CreateIdpSideModalForm() {
6161

6262
return (
6363
<SideModalForm
64-
id="create-idp-form"
6564
form={form}
66-
title="Create identity provider"
65+
formType="create"
66+
resourceName="identity provider"
6767
onDismiss={onDismiss}
6868
onSubmit={async ({
6969
signingKeypair,

app/forms/idp/edit.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ export function EditIdpSideModalForm() {
4444

4545
return (
4646
<SideModalForm
47-
id="edit-idp-form"
4847
form={form}
48+
formType="edit"
49+
resourceName="identity provider"
4950
title="Identity provider"
5051
onDismiss={onDismiss}
5152
subtitle={

app/forms/image-edit.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ export function EditImageSideModalForm({
7272

7373
return (
7474
<SideModalForm
75-
id="edit-project-image-form"
7675
form={form}
77-
title={`${type} image`}
76+
formType="edit"
77+
resourceName={type === 'Project' ? 'project image' : 'silo image'}
7878
onDismiss={() => navigate(dismissLink)}
7979
subtitle={
8080
<ResourceLabel>

app/forms/image-from-snapshot.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,10 @@ export function CreateImageFromSnapshotSideModalForm() {
6969

7070
return (
7171
<SideModalForm
72-
id="create-image-from-snapshot-form"
7372
form={form}
74-
title={`Create image from snapshot`}
73+
formType="create"
74+
resourceName="image"
75+
title="Create image from snapshot"
7576
submitLabel="Create image"
7677
onDismiss={onDismiss}
7778
onSubmit={(body) =>

app/forms/image-upload.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,9 @@ export function CreateImageSideModalForm() {
471471

472472
return (
473473
<SideModalForm
474-
id="upload-image-form"
475474
form={form}
475+
formType="create"
476+
resourceName="image"
476477
title="Upload image"
477478
onDismiss={backToImages}
478479
onSubmit={async (values) => {

app/forms/ip-pool-create.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ export function CreateIpPoolSideModalForm() {
3939

4040
return (
4141
<SideModalForm
42-
id="create-pool-form"
4342
form={form}
44-
title="Create IP pool"
43+
formType="create"
44+
resourceName="IP pool"
4545
onDismiss={onDismiss}
4646
onSubmit={({ name, description }) => {
4747
createPool.mutate({ body: { name, description } })

app/forms/ip-pool-edit.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,15 @@ export function EditIpPoolSideModalForm() {
4949

5050
return (
5151
<SideModalForm
52-
id="edit-pool-form"
5352
form={form}
54-
title="Edit IP pool"
53+
formType="edit"
54+
resourceName="IP pool"
5555
onDismiss={onDismiss}
5656
onSubmit={({ name, description }) => {
5757
editPool.mutate({ path: poolSelector, body: { name, description } })
5858
}}
5959
loading={editPool.isPending}
6060
submitError={editPool.error}
61-
submitLabel="Save changes"
6261
>
6362
<NameField name="name" control={form.control} />
6463
<DescriptionField name="description" control={form.control} />

app/forms/ip-pool-range-add.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ export function IpPoolAddRangeSideModalForm() {
7777

7878
return (
7979
<SideModalForm
80-
id="add-ip-range-form"
8180
form={form}
81+
formType="create"
82+
resourceName="IP range"
8283
title="Add IP range"
8384
onDismiss={onDismiss}
8485
onSubmit={(body) => addRange.mutate({ path: { pool }, body })}

app/forms/network-interface-create.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ export function CreateNetworkInterfaceForm({
5252

5353
return (
5454
<SideModalForm
55-
id="create-network-interface-form"
56-
title="Add network interface"
5755
form={form}
56+
formType="create"
57+
resourceName="network interface"
58+
title="Add network interface"
5859
onDismiss={onDismiss}
5960
onSubmit={onSubmit}
6061
loading={loading}

app/forms/network-interface-edit.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ export function EditNetworkInterfaceForm({
4242

4343
return (
4444
<SideModalForm
45-
id="edit-network-interface-form"
46-
title="Edit network interface"
4745
form={form}
46+
formType="edit"
47+
resourceName="network interface"
4848
onDismiss={onDismiss}
4949
onSubmit={(body) => {
5050
const interfaceName = defaultValues.name
@@ -56,7 +56,6 @@ export function EditNetworkInterfaceForm({
5656
}}
5757
loading={editNetworkInterface.isPending}
5858
submitError={editNetworkInterface.error}
59-
submitLabel="Save changes"
6059
>
6160
<NameField name="name" control={form.control} />
6261
<DescriptionField name="description" control={form.control} />

app/forms/project-access.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ export function ProjectAccessAddUserSideModal({ onDismiss, policy }: AddRoleModa
4242
return (
4343
<SideModalForm
4444
title="Add user or group"
45-
id="project-access-add-user"
45+
resourceName="role"
4646
form={form}
47+
formType="create"
4748
onSubmit={({ identityId, roleName }) => {
4849
// can't happen because roleName is validated not to be '', but TS
4950
// wants to be sure
@@ -82,6 +83,7 @@ export function ProjectAccessAddUserSideModal({ onDismiss, policy }: AddRoleModa
8283

8384
export function ProjectAccessEditUserSideModal({
8485
onDismiss,
86+
name,
8587
identityId,
8688
identityType,
8789
policy,
@@ -102,9 +104,10 @@ export function ProjectAccessEditUserSideModal({
102104
return (
103105
<SideModalForm
104106
// TODO: show user name in header or SOMEWHERE
105-
title="Change user role"
106-
id="project-access-edit-user"
107107
form={form}
108+
formType="edit"
109+
resourceName="role"
110+
title={`Change role for ${name}`}
108111
onSubmit={({ roleName }) => {
109112
updatePolicy.mutate({
110113
path: { project },
@@ -113,7 +116,6 @@ export function ProjectAccessEditUserSideModal({
113116
}}
114117
loading={updatePolicy.isPending}
115118
submitError={updatePolicy.error}
116-
submitLabel="Update role"
117119
onDismiss={onDismiss}
118120
>
119121
<ListboxField

app/forms/project-create.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ export function CreateProjectSideModalForm() {
4242

4343
return (
4444
<SideModalForm
45-
id="create-project-form"
4645
form={form}
47-
title="Create project"
46+
formType="create"
47+
resourceName="project"
4848
onDismiss={onDismiss}
4949
onSubmit={({ name, description }) => {
5050
createProject.mutate({ body: { name, description } })

0 commit comments

Comments
 (0)