Skip to content

Commit d7fd3c4

Browse files
authored
Make pressing enter submit instance resize modal form (#2586)
* make pressing enter submit resize modal form * eh do it the good way * expectToast and expectNoToast use toContainText instead of toHaveText
1 parent 23423c2 commit d7fd3c4

File tree

3 files changed

+27
-16
lines changed

3 files changed

+27
-16
lines changed

app/pages/project/instances/instance/InstancePage.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Copyright Oxide Computer Company
77
*/
88
import { filesize } from 'filesize'
9-
import { useMemo, useState } from 'react'
9+
import { useId, useMemo, useState } from 'react'
1010
import { useForm } from 'react-hook-form'
1111
import { Link, useNavigate, type LoaderFunctionArgs } from 'react-router-dom'
1212

@@ -314,13 +314,14 @@ export function ResizeInstanceModal({
314314
form.watch('ncpus') !== instance.ncpus || form.watch('memory') !== instance.memory / GiB
315315
const isDisabled = !form.formState.isValid || !canResize || !willChange
316316

317-
const onAction = form.handleSubmit(({ ncpus, memory }) => {
317+
const onSubmit = form.handleSubmit(({ ncpus, memory }) => {
318318
instanceUpdate.mutate({
319319
path: { instance: instance.name },
320320
query: { project },
321321
body: { ncpus, memory: memory * GiB, bootDisk: instance.bootDiskId },
322322
})
323323
})
324+
const formId = useId()
324325

325326
return (
326327
<Modal title="Resize instance" isOpen onDismiss={onDismiss}>
@@ -340,7 +341,7 @@ export function ResizeInstanceModal({
340341
}
341342
/>
342343
)}
343-
<form autoComplete="off" className="space-y-4">
344+
<form id={formId} autoComplete="off" className="space-y-4" onSubmit={onSubmit}>
344345
<NumberField
345346
required
346347
label="vCPUs"
@@ -383,8 +384,8 @@ export function ResizeInstanceModal({
383384
</Modal.Section>
384385
</Modal.Body>
385386
<Modal.Footer
387+
formId={formId}
386388
onDismiss={onDismiss}
387-
onAction={onAction}
388389
actionText="Resize"
389390
actionLoading={instanceUpdate.isPending}
390391
disabled={isDisabled}

app/ui/lib/Modal.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as Dialog from '@radix-ui/react-dialog'
99
import { animated, useTransition } from '@react-spring/web'
1010
import cn from 'classnames'
1111
import React, { forwardRef, useId } from 'react'
12+
import type { MergeExclusive } from 'type-fest'
1213

1314
import { Close12Icon } from '@oxide/design-system/icons/react'
1415

@@ -125,6 +126,21 @@ Modal.Body = classed.div`py-2 overflow-y-auto`
125126

126127
Modal.Section = classed.div`p-4 space-y-4 border-b border-secondary text-secondary last-of-type:border-none text-sans-md`
127128

129+
/**
130+
* `formId` and `onAction` are mutually exclusive. If there is a form associated,
131+
* the button becomes a submit button for that form, and the action is assumed to
132+
* be hooked up in the form's `onSubmit`.
133+
*/
134+
type FooterProps = {
135+
children?: React.ReactNode
136+
onDismiss: () => void
137+
actionType?: 'primary' | 'danger'
138+
actionText: React.ReactNode
139+
actionLoading?: boolean
140+
cancelText?: string
141+
disabled?: boolean
142+
} & MergeExclusive<{ formId: string }, { onAction: () => void }>
143+
128144
Modal.Footer = ({
129145
children,
130146
onDismiss,
@@ -134,23 +150,17 @@ Modal.Footer = ({
134150
actionLoading,
135151
cancelText,
136152
disabled = false,
137-
}: {
138-
children?: React.ReactNode
139-
onDismiss: () => void
140-
onAction: () => void
141-
actionType?: 'primary' | 'danger'
142-
actionText: React.ReactNode
143-
actionLoading?: boolean
144-
cancelText?: string
145-
disabled?: boolean
146-
}) => (
153+
formId,
154+
}: FooterProps) => (
147155
<footer className="flex items-center justify-between border-t px-3 py-3 border-secondary">
148156
<div className="mr-4">{children}</div>
149157
<div className="space-x-2">
150158
<Button variant="secondary" size="sm" onClick={onDismiss}>
151159
{cancelText || 'Cancel'}
152160
</Button>
153161
<Button
162+
type={formId ? 'submit' : 'button'}
163+
form={formId}
154164
size="sm"
155165
variant={actionType}
156166
onClick={onAction}

test/e2e/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,15 @@ export async function stopInstance(page: Page) {
118118
* Assert that a toast with text matching `expectedText` is visible.
119119
*/
120120
export async function expectToast(page: Page, expectedText: string | RegExp) {
121-
await expect(page.getByTestId('Toasts')).toHaveText(expectedText)
121+
await expect(page.getByTestId('Toasts')).toContainText(expectedText)
122122
await closeToast(page)
123123
}
124124

125125
/**
126126
* Assert that a toast with text matching `expectedText` is not visible.
127127
*/
128128
export async function expectNoToast(page: Page, expectedText: string | RegExp) {
129-
await expect(page.getByTestId('Toasts')).not.toHaveText(expectedText)
129+
await expect(page.getByTestId('Toasts')).not.toContainText(expectedText)
130130
}
131131

132132
/**

0 commit comments

Comments
 (0)