From cfa1972494a71f4b5956ed0cd42db8e094b71ef9 Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Thu, 7 Mar 2024 16:01:27 -0800 Subject: [PATCH 01/11] Make SideModal button copy consistent --- app/components/form/SideModalForm.tsx | 12 +++++++----- app/forms/disk-attach.tsx | 2 +- app/forms/disk-create.tsx | 2 +- app/forms/firewall-rules-create.tsx | 2 +- app/forms/firewall-rules-edit.tsx | 3 +-- app/forms/floating-ip-create.tsx | 2 +- app/forms/floating-ip-edit.tsx | 3 +-- app/forms/idp/create.tsx | 2 +- app/forms/idp/edit.tsx | 2 +- app/forms/image-edit.tsx | 2 +- app/forms/image-from-snapshot.tsx | 2 +- app/forms/image-upload.tsx | 2 +- app/forms/ip-pool-create.tsx | 2 +- app/forms/ip-pool-edit.tsx | 3 +-- app/forms/ip-pool-range-add.tsx | 2 +- app/forms/network-interface-create.tsx | 2 +- app/forms/network-interface-edit.tsx | 3 +-- app/forms/project-access.tsx | 5 ++--- app/forms/project-create.tsx | 2 +- app/forms/project-edit.tsx | 3 +-- app/forms/silo-access.tsx | 5 ++--- app/forms/silo-create.tsx | 2 +- app/forms/snapshot-create.tsx | 2 +- app/forms/ssh-key-create.tsx | 2 +- app/forms/subnet-create.tsx | 2 +- app/forms/subnet-edit.tsx | 2 +- app/forms/vpc-create.tsx | 2 +- app/forms/vpc-edit.tsx | 3 +-- 28 files changed, 36 insertions(+), 42 deletions(-) diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx index c11a9ebd73..46bd9fd877 100644 --- a/app/components/form/SideModalForm.tsx +++ b/app/components/form/SideModalForm.tsx @@ -5,7 +5,7 @@ * * Copyright Oxide Computer Company */ -import { useEffect, type ReactNode } from 'react' +import { useEffect, useId, type ReactNode } from 'react' import type { FieldValues, UseFormReturn } from 'react-hook-form' import { useNavigationType } from 'react-router-dom' @@ -15,8 +15,8 @@ import { Button } from '~/ui/lib/Button' import { SideModal } from '~/ui/lib/SideModal' type SideModalFormProps = { - id: string form: UseFormReturn + formType: 'create' | 'edit' /** * A function that returns the fields. * @@ -49,8 +49,8 @@ export function useShouldAnimateModal() { } export function SideModalForm({ - id, form, + formType, children, onDismiss, submitDisabled, @@ -61,6 +61,7 @@ export function SideModalForm({ loading, subtitle, }: SideModalFormProps) { + const id = useId() const { isSubmitting } = form.formState useEffect(() => { @@ -69,6 +70,7 @@ export function SideModalForm({ form.setError('name', { message: 'Name already exists' }) } }, [submitError, form]) + const defaultLabel = formType === 'edit' ? 'Save changes' : title return ( ({ )} diff --git a/app/forms/disk-attach.tsx b/app/forms/disk-attach.tsx index 60ec1f417c..1aba4b0c7f 100644 --- a/app/forms/disk-attach.tsx +++ b/app/forms/disk-attach.tsx @@ -46,9 +46,9 @@ export function AttachDiskSideModalForm({ return ( onDismiss(navigate)} onSubmit={({ size, ...rest }) => { const body = { size: size * GiB, ...rest } diff --git a/app/forms/firewall-rules-create.tsx b/app/forms/firewall-rules-create.tsx index be4ec6dc00..8db1c35d19 100644 --- a/app/forms/firewall-rules-create.tsx +++ b/app/forms/firewall-rules-create.tsx @@ -504,9 +504,9 @@ export function CreateFirewallRuleForm({ return ( { // TODO: this silently overwrites existing rules with the current name. diff --git a/app/forms/firewall-rules-edit.tsx b/app/forms/firewall-rules-edit.tsx index 5fe192f074..f949ba1024 100644 --- a/app/forms/firewall-rules-edit.tsx +++ b/app/forms/firewall-rules-edit.tsx @@ -65,9 +65,9 @@ export function EditFirewallRuleForm({ return ( { // note different filter logic from create: filter out the rule with the @@ -86,7 +86,6 @@ export function EditFirewallRuleForm({ // validateOnBlur loading={updateRules.isPending} submitError={updateRules.error} - submitLabel="Update rule" > diff --git a/app/forms/floating-ip-create.tsx b/app/forms/floating-ip-create.tsx index 4b138a5941..d2575d42f2 100644 --- a/app/forms/floating-ip-create.tsx +++ b/app/forms/floating-ip-create.tsx @@ -83,9 +83,9 @@ export function CreateFloatingIpSideModalForm() { return ( navigate(pb.floatingIps(projectSelector))} onSubmit={({ ip, ...rest }) => { createFloatingIp.mutate({ diff --git a/app/forms/floating-ip-edit.tsx b/app/forms/floating-ip-edit.tsx index cab8e03019..fa58117aed 100644 --- a/app/forms/floating-ip-edit.tsx +++ b/app/forms/floating-ip-edit.tsx @@ -55,8 +55,8 @@ export function EditFloatingIpSideModalForm() { return ( { @@ -68,7 +68,6 @@ export function EditFloatingIpSideModalForm() { }} loading={editFloatingIp.isPending} submitError={editFloatingIp.error} - submitLabel="Save changes" > diff --git a/app/forms/idp/create.tsx b/app/forms/idp/create.tsx index d8b185109d..0d99580f01 100644 --- a/app/forms/idp/create.tsx +++ b/app/forms/idp/create.tsx @@ -61,8 +61,8 @@ export function CreateIdpSideModalForm() { return ( navigate(dismissLink)} subtitle={ diff --git a/app/forms/image-from-snapshot.tsx b/app/forms/image-from-snapshot.tsx index da0c61eb8c..799a9e8832 100644 --- a/app/forms/image-from-snapshot.tsx +++ b/app/forms/image-from-snapshot.tsx @@ -69,8 +69,8 @@ export function CreateImageFromSnapshotSideModalForm() { return ( { diff --git a/app/forms/ip-pool-create.tsx b/app/forms/ip-pool-create.tsx index af360cc8bc..342b2e02b7 100644 --- a/app/forms/ip-pool-create.tsx +++ b/app/forms/ip-pool-create.tsx @@ -39,8 +39,8 @@ export function CreateIpPoolSideModalForm() { return ( { diff --git a/app/forms/ip-pool-edit.tsx b/app/forms/ip-pool-edit.tsx index 22407ad158..181f09f1e5 100644 --- a/app/forms/ip-pool-edit.tsx +++ b/app/forms/ip-pool-edit.tsx @@ -49,8 +49,8 @@ export function EditIpPoolSideModalForm() { return ( { @@ -58,7 +58,6 @@ export function EditIpPoolSideModalForm() { }} loading={editPool.isPending} submitError={editPool.error} - submitLabel="Save changes" > diff --git a/app/forms/ip-pool-range-add.tsx b/app/forms/ip-pool-range-add.tsx index 9c16060e1a..de2b0ef22a 100644 --- a/app/forms/ip-pool-range-add.tsx +++ b/app/forms/ip-pool-range-add.tsx @@ -77,8 +77,8 @@ export function IpPoolAddRangeSideModalForm() { return ( addRange.mutate({ path: { pool }, body })} diff --git a/app/forms/network-interface-create.tsx b/app/forms/network-interface-create.tsx index 19732a6009..be01e00334 100644 --- a/app/forms/network-interface-create.tsx +++ b/app/forms/network-interface-create.tsx @@ -52,9 +52,9 @@ export default function CreateNetworkInterfaceForm({ return ( { const interfaceName = defaultValues.name @@ -56,7 +56,6 @@ export default function EditNetworkInterfaceForm({ }} loading={editNetworkInterface.isPending} submitError={editNetworkInterface.error} - submitLabel="Save changes" > diff --git a/app/forms/project-access.tsx b/app/forms/project-access.tsx index 02f83b75e6..74e52cc772 100644 --- a/app/forms/project-access.tsx +++ b/app/forms/project-access.tsx @@ -42,8 +42,8 @@ export function ProjectAccessAddUserSideModal({ onDismiss, policy }: AddRoleModa return ( { // can't happen because roleName is validated not to be '', but TS // wants to be sure @@ -103,8 +103,8 @@ export function ProjectAccessEditUserSideModal({ { updatePolicy.mutate({ path: { project }, @@ -113,7 +113,6 @@ export function ProjectAccessEditUserSideModal({ }} loading={updatePolicy.isPending} submitError={updatePolicy.error} - submitLabel="Update role" onDismiss={onDismiss} > { diff --git a/app/forms/project-edit.tsx b/app/forms/project-edit.tsx index 68985c4218..1e09b93fc6 100644 --- a/app/forms/project-edit.tsx +++ b/app/forms/project-edit.tsx @@ -55,8 +55,8 @@ export function EditProjectSideModalForm() { return ( { @@ -64,7 +64,6 @@ export function EditProjectSideModalForm() { }} loading={editProject.isPending} submitError={editProject.error} - submitLabel="Save changes" > diff --git a/app/forms/silo-access.tsx b/app/forms/silo-access.tsx index 9771ce5965..7903d668a2 100644 --- a/app/forms/silo-access.tsx +++ b/app/forms/silo-access.tsx @@ -41,8 +41,8 @@ export function SiloAccessAddUserSideModal({ onDismiss, policy }: AddRoleModalPr { // can't happen because roleName is validated not to be '', but TS // wants to be sure @@ -98,8 +98,8 @@ export function SiloAccessEditUserSideModal({ { updatePolicy.mutate({ body: updateRole({ identityId, identityType, roleName }, policy), @@ -107,7 +107,6 @@ export function SiloAccessEditUserSideModal({ }} loading={updatePolicy.isPending} submitError={updatePolicy.error} - submitLabel="Update role" onDismiss={onDismiss} > { createSnapshot.mutate({ query: projectSelector, body: values }) diff --git a/app/forms/ssh-key-create.tsx b/app/forms/ssh-key-create.tsx index 65f4332cc1..ee6e111479 100644 --- a/app/forms/ssh-key-create.tsx +++ b/app/forms/ssh-key-create.tsx @@ -44,9 +44,9 @@ export function CreateSSHKeySideModalForm({ return ( createSshKey.mutate({ body })} loading={createSshKey.isPending} diff --git a/app/forms/subnet-create.tsx b/app/forms/subnet-create.tsx index 4b74f87a14..3c1b4b35bf 100644 --- a/app/forms/subnet-create.tsx +++ b/app/forms/subnet-create.tsx @@ -39,9 +39,9 @@ export function CreateSubnetForm({ onDismiss }: CreateSubnetFormProps) { return ( createSubnet.mutate({ query: vpcSelector, body })} loading={createSubnet.isPending} diff --git a/app/forms/subnet-edit.tsx b/app/forms/subnet-edit.tsx index 7810960097..98137a6c4f 100644 --- a/app/forms/subnet-edit.tsx +++ b/app/forms/subnet-edit.tsx @@ -35,10 +35,10 @@ export function EditSubnetForm({ onDismiss, editing }: EditSubnetFormProps) { return ( { updateSubnet.mutate({ path: { subnet: editing.name }, diff --git a/app/forms/vpc-create.tsx b/app/forms/vpc-create.tsx index da5db90b2d..a9e84ed4fb 100644 --- a/app/forms/vpc-create.tsx +++ b/app/forms/vpc-create.tsx @@ -47,7 +47,7 @@ export function CreateVpcSideModalForm() { return ( createVpc.mutate({ query: projectSelector, body: values })} onDismiss={() => navigate(pb.vpcs(projectSelector))} diff --git a/app/forms/vpc-edit.tsx b/app/forms/vpc-edit.tsx index 7b2e5877e5..343544948d 100644 --- a/app/forms/vpc-edit.tsx +++ b/app/forms/vpc-edit.tsx @@ -56,9 +56,9 @@ export function EditVpcSideModalForm() { return ( { editVpc.mutate({ @@ -68,7 +68,6 @@ export function EditVpcSideModalForm() { }) }} loading={editVpc.isPending} - submitLabel="Save changes" submitError={editVpc.error} > From 52b14b31e184c76fe7bcbda4c6b3eceace1a44ca Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Thu, 7 Mar 2024 16:34:29 -0800 Subject: [PATCH 02/11] Fix test issues --- app/components/form/SideModalForm.tsx | 2 +- test/e2e/firewall-rules.e2e.ts | 2 +- test/e2e/project-access.e2e.ts | 2 +- test/e2e/silo-access.e2e.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx index 46bd9fd877..3ad1ed8467 100644 --- a/app/components/form/SideModalForm.tsx +++ b/app/components/form/SideModalForm.tsx @@ -108,7 +108,7 @@ export function SideModalForm({ )} diff --git a/app/forms/firewall-rules-edit.tsx b/app/forms/firewall-rules-edit.tsx index f79e9920ef..44c662c8e1 100644 --- a/app/forms/firewall-rules-edit.tsx +++ b/app/forms/firewall-rules-edit.tsx @@ -65,7 +65,6 @@ export function EditFirewallRuleForm({ return ( { editFloatingIp.mutate({ diff --git a/app/forms/idp/edit.tsx b/app/forms/idp/edit.tsx index e9ee4016c0..2712214d06 100644 --- a/app/forms/idp/edit.tsx +++ b/app/forms/idp/edit.tsx @@ -47,7 +47,6 @@ export function EditIdpSideModalForm() { form={form} resourceName="identity provider" formType="edit" - title="Identity provider" onDismiss={onDismiss} subtitle={ diff --git a/app/forms/image-edit.tsx b/app/forms/image-edit.tsx index 26a1aec44e..2fe023c895 100644 --- a/app/forms/image-edit.tsx +++ b/app/forms/image-edit.tsx @@ -73,9 +73,8 @@ export function EditImageSideModalForm({ return ( navigate(dismissLink)} subtitle={ diff --git a/app/forms/ip-pool-edit.tsx b/app/forms/ip-pool-edit.tsx index d94edbaa4e..b44df0ab5f 100644 --- a/app/forms/ip-pool-edit.tsx +++ b/app/forms/ip-pool-edit.tsx @@ -52,7 +52,6 @@ export function EditIpPoolSideModalForm() { form={form} resourceName="IP pool" formType="edit" - title="Edit IP pool" onDismiss={onDismiss} onSubmit={({ name, description }) => { editPool.mutate({ path: poolSelector, body: { name, description } }) diff --git a/app/forms/network-interface-edit.tsx b/app/forms/network-interface-edit.tsx index fbdb60840c..6deacfc8f4 100644 --- a/app/forms/network-interface-edit.tsx +++ b/app/forms/network-interface-edit.tsx @@ -42,7 +42,6 @@ export default function EditNetworkInterfaceForm({ return ( Date: Fri, 8 Mar 2024 16:42:39 -0800 Subject: [PATCH 06/11] Refactor and remove title from most create forms --- app/components/form/SideModalForm.tsx | 29 +++++---------------------- app/forms/disk-create.tsx | 1 - app/forms/floating-ip-create.tsx | 1 - app/forms/idp/create.tsx | 1 - app/forms/idp/edit.tsx | 1 + app/forms/image-from-snapshot.tsx | 2 +- app/forms/ip-pool-create.tsx | 1 - app/forms/project-create.tsx | 1 - app/forms/silo-create.tsx | 1 - app/forms/snapshot-create.tsx | 1 - app/forms/subnet-create.tsx | 1 - app/forms/vpc-create.tsx | 1 - test/e2e/click-everything.e2e.ts | 4 ++-- test/e2e/firewall-rules.e2e.ts | 2 +- test/e2e/floating-ip-create.e2e.ts | 8 ++++---- test/e2e/floating-ip-update.e2e.ts | 6 +++--- test/e2e/instance/disks.e2e.ts | 2 +- test/e2e/instance/networking.e2e.ts | 2 +- test/e2e/networking.e2e.ts | 4 ++-- test/e2e/project-access.e2e.ts | 4 ++-- test/e2e/silo-access.e2e.ts | 4 ++-- 21 files changed, 25 insertions(+), 52 deletions(-) diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx index c5b7390f8b..00970ec67b 100644 --- a/app/components/form/SideModalForm.tsx +++ b/app/components/form/SideModalForm.tsx @@ -14,35 +14,14 @@ import type { ApiError } from '@oxide/api' import { Button } from '~/ui/lib/Button' import { SideModal } from '~/ui/lib/SideModal' -type ResourceName = - | 'disk' - | 'floating IP' - | 'identity provider' - | 'image' - | 'IP pool' - | 'IP range' - | 'network interface' - | 'project' - | 'project image' - | 'role' - | 'rule' - | 'silo' - | 'silo image' - | 'snapshot' - | 'SSH key' - | 'subnet' - | 'VPC' - type CreateFormProps = { formType: 'create' submitLabel?: string - title?: string } type EditFormProps = { formType: 'edit' submitLabel?: never - title?: never } type SideModalFormProps = { @@ -57,12 +36,13 @@ type SideModalFormProps = { */ children: ReactNode onDismiss: () => void - resourceName: ResourceName + resourceName: string /** Must be provided with a reason describing why it's disabled */ submitDisabled?: string /** Error from the API call */ submitError: ApiError | null loading?: boolean + title?: string subtitle?: ReactNode onSubmit?: (values: TFieldValues) => void } & (CreateFormProps | EditFormProps) @@ -100,8 +80,9 @@ export function SideModalForm({ form.setError('name', { message: 'Name already exists' }) } }, [submitError, form]) - const defaultTitle = formType === 'edit' ? `Edit ${resourceName}` : title - const label = formType === 'edit' ? `Update ${resourceName}` : submitLabel || title + const defaultTitle = title || `${formType === 'edit' ? 'Edit' : 'Create'} ${resourceName}` + const label = + submitLabel || title || `${formType === 'edit' ? 'Update' : 'Create'} ${resourceName}` return ( diff --git a/app/forms/ip-pool-create.tsx b/app/forms/ip-pool-create.tsx index 5aa37727ed..ebfab20d86 100644 --- a/app/forms/ip-pool-create.tsx +++ b/app/forms/ip-pool-create.tsx @@ -42,7 +42,6 @@ export function CreateIpPoolSideModalForm() { form={form} resourceName="IP pool" formType="create" - title="Create IP pool" onDismiss={onDismiss} onSubmit={({ name, description }) => { createPool.mutate({ body: { name, description } }) diff --git a/app/forms/project-create.tsx b/app/forms/project-create.tsx index d1f0463866..1c74429fe7 100644 --- a/app/forms/project-create.tsx +++ b/app/forms/project-create.tsx @@ -45,7 +45,6 @@ export function CreateProjectSideModalForm() { form={form} resourceName="project" formType="create" - title="Create project" onDismiss={onDismiss} onSubmit={({ name, description }) => { createProject.mutate({ body: { name, description } }) diff --git a/app/forms/silo-create.tsx b/app/forms/silo-create.tsx index 413b454a15..c9f0caaf37 100644 --- a/app/forms/silo-create.tsx +++ b/app/forms/silo-create.tsx @@ -66,7 +66,6 @@ export function CreateSiloSideModalForm() { return ( createVpc.mutate({ query: projectSelector, body: values })} onDismiss={() => navigate(pb.vpcs(projectSelector))} loading={createVpc.isPending} diff --git a/test/e2e/click-everything.e2e.ts b/test/e2e/click-everything.e2e.ts index 50bfae8091..8db2064c09 100644 --- a/test/e2e/click-everything.e2e.ts +++ b/test/e2e/click-everything.e2e.ts @@ -48,12 +48,12 @@ test('Click through disks page', async ({ page }) => { // Create disk form await page.click('role=link[name="New Disk"]') await expectVisible(page, [ - 'role=heading[name*="Create Disk"]', + 'role=heading[name*="Create disk"]', 'role=textbox[name="Name"]', 'role=textbox[name="Description"]', 'role=radiogroup[name="Block size (Bytes)"]', 'role=textbox[name="Size (GiB)"]', - 'role=button[name="Create Disk"]', + 'role=button[name="Create disk"]', ]) await page.goBack() }) diff --git a/test/e2e/firewall-rules.e2e.ts b/test/e2e/firewall-rules.e2e.ts index 7fbb07cf7f..ae376b7465 100644 --- a/test/e2e/firewall-rules.e2e.ts +++ b/test/e2e/firewall-rules.e2e.ts @@ -238,7 +238,7 @@ test('can update firewall rule', async ({ page }) => { await expect(page.locator('role=cell >> text="edit-filter-subnet"')).toBeVisible() // submit the form - await page.locator('text="Save changes"').click() + await page.locator('text="Update rule"').click() // modal closes again await expect(modal).toBeHidden() diff --git a/test/e2e/floating-ip-create.e2e.ts b/test/e2e/floating-ip-create.e2e.ts index 35a821c6ab..04d902696e 100644 --- a/test/e2e/floating-ip-create.e2e.ts +++ b/test/e2e/floating-ip-create.e2e.ts @@ -22,11 +22,11 @@ test('can create a floating IP', async ({ page }) => { await page.locator('text="New Floating IP"').click() await expectVisible(page, [ - 'role=heading[name*="Create Floating IP"]', + 'role=heading[name*="Create floating IP"]', 'role=textbox[name="Name"]', 'role=textbox[name="Description"]', 'role=button[name="Advanced"]', - 'role=button[name="Create Floating IP"]', + 'role=button[name="Create floating IP"]', ]) const floatingIpName = 'my-floating-ip' @@ -51,14 +51,14 @@ test('can create a floating IP', async ({ page }) => { await poolListbox.click() await page.getByRole('option', { name: 'ip-pool-1' }).click() await ipTextbox.fill('256.256.256.256') - await page.getByRole('button', { name: 'Create Floating IP' }).click() + await page.getByRole('button', { name: 'Create floating IP' }).click() await expect(page.getByText('Not a valid IP address').first()).toBeVisible() // correct IP and submit await ipTextbox.clear() await ipTextbox.fill('12.34.56.78') - await page.getByRole('button', { name: 'Create Floating IP' }).click() + await page.getByRole('button', { name: 'Create floating IP' }).click() await expect(page).toHaveURL(floatingIpsPage) diff --git a/test/e2e/floating-ip-update.e2e.ts b/test/e2e/floating-ip-update.e2e.ts index 0453358eeb..68bcf0d05d 100644 --- a/test/e2e/floating-ip-update.e2e.ts +++ b/test/e2e/floating-ip-update.e2e.ts @@ -16,7 +16,7 @@ const expectedFormElements = [ 'role=heading[name*="Edit floating IP"]', 'role=textbox[name="Name"]', 'role=textbox[name="Description"]', - 'role=button[name="Save changes"]', + 'role=button[name="Update floating IP"]', ] test('can update a floating IP', async ({ page }) => { @@ -26,7 +26,7 @@ test('can update a floating IP', async ({ page }) => { await page.fill('input[name=name]', updatedName) await page.getByRole('textbox', { name: 'Description' }).fill(updatedDescription) - await page.getByRole('button', { name: 'Save changes' }).click() + await page.getByRole('button', { name: 'Update floating IP' }).click() await expect(page).toHaveURL(floatingIpsPage) await expectRowVisible(page.getByRole('table'), { name: updatedName, @@ -41,7 +41,7 @@ test('can update *just* the floating IP description', async ({ page }) => { await expectVisible(page, expectedFormElements) await page.getByRole('textbox', { name: 'Description' }).fill(updatedDescription) - await page.getByRole('button', { name: 'Save changes' }).click() + await page.getByRole('button', { name: 'Update floating IP' }).click() await expect(page).toHaveURL(floatingIpsPage) await expectRowVisible(page.getByRole('table'), { name: originalName, diff --git a/test/e2e/instance/disks.e2e.ts b/test/e2e/instance/disks.e2e.ts index 98e377162d..a9d4279f0e 100644 --- a/test/e2e/instance/disks.e2e.ts +++ b/test/e2e/instance/disks.e2e.ts @@ -46,7 +46,7 @@ test('Attach disk', async ({ page }) => { 'role=textbox[name="Description"]', 'role=radiogroup[name="Block size (Bytes)"]', 'role=textbox[name="Size (GiB)"]', - 'role=button[name="Create Disk"]', + 'role=button[name="Create disk"]', ]) await page.click('role=button[name="Cancel"]') diff --git a/test/e2e/instance/networking.e2e.ts b/test/e2e/instance/networking.e2e.ts index fe0ccba638..43ef5064de 100644 --- a/test/e2e/instance/networking.e2e.ts +++ b/test/e2e/instance/networking.e2e.ts @@ -66,7 +66,7 @@ test('Instance networking tab', async ({ page }) => { // Make an edit to the network interface await clickRowAction(page, 'nic-2', 'Edit') await page.fill('role=textbox[name="Name"]', 'nic-3') - await page.click('role=button[name="Save changes"]') + await page.click('role=button[name="Update network interface"]') await expectNotVisible(page, ['role=cell[name="nic-2"]']) const nic3 = page.getByRole('cell', { name: 'nic-3' }) await expect(nic3).toBeVisible() diff --git a/test/e2e/networking.e2e.ts b/test/e2e/networking.e2e.ts index 999ef18907..e2f6637302 100644 --- a/test/e2e/networking.e2e.ts +++ b/test/e2e/networking.e2e.ts @@ -40,10 +40,10 @@ test('Create and edit VPC', async ({ page }) => { 'role=textbox[name="Name"]', 'role=textbox[name="Description"]', 'role=textbox[name="DNS name"]', - 'role=button[name="Save changes"]', + 'role=button[name="Update VPC"]', ]) await page.fill('role=textbox[name="Name"]', 'new-vpc') - await page.click('role=button[name="Save changes"]') + await page.click('role=button[name="Update VPC"]') // Close toast, it holds up the test for some reason await page.click('role=button[name="Dismiss notification"]') diff --git a/test/e2e/project-access.e2e.ts b/test/e2e/project-access.e2e.ts index f5ea668965..877fc7d709 100644 --- a/test/e2e/project-access.e2e.ts +++ b/test/e2e/project-access.e2e.ts @@ -78,12 +78,12 @@ test('Click through project access page', async ({ page }) => { .click() await page.click('role=menuitem[name="Change role"]') - await expectVisible(page, ['role=heading[name*="Change user role"]']) + await expectVisible(page, ['role=heading[name*="Edit role"]']) await expectVisible(page, ['button:has-text("Collaborator")']) await page.click('role=button[name*="Role"]') await page.click('role=option[name="Viewer"]') - await page.click('role=button[name="Save changes"]') + await page.click('role=button[name="Update role"]') await expectRowVisible(table, { Name: user4.display_name, 'Project role': 'viewer' }) diff --git a/test/e2e/silo-access.e2e.ts b/test/e2e/silo-access.e2e.ts index 6f9399642a..833dcce6d9 100644 --- a/test/e2e/silo-access.e2e.ts +++ b/test/e2e/silo-access.e2e.ts @@ -67,12 +67,12 @@ test('Click through silo access page', async ({ page }) => { .click() await page.click('role=menuitem[name="Change role"]') - await expectVisible(page, ['role=heading[name*="Change user role"]']) + await expectVisible(page, ['role=heading[name*="Edit role"]']) await expectVisible(page, ['button:has-text("Collaborator")']) await page.click('role=button[name*="Role"]') await page.click('role=option[name="Viewer"]') - await page.click('role=button[name="Save changes"]') + await page.click('role=button[name="Update role"]') await expectRowVisible(table, { Name: user3.display_name, 'Silo role': 'viewer' }) From 6cc0a63afb0f74bd43949ab11818ab333e2dc430 Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Fri, 8 Mar 2024 16:53:01 -0800 Subject: [PATCH 07/11] Refactor --- app/components/form/SideModalForm.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx index 00970ec67b..8a9b04eb8e 100644 --- a/app/components/form/SideModalForm.tsx +++ b/app/components/form/SideModalForm.tsx @@ -80,15 +80,12 @@ export function SideModalForm({ form.setError('name', { message: 'Name already exists' }) } }, [submitError, form]) - const defaultTitle = title || `${formType === 'edit' ? 'Edit' : 'Create'} ${resourceName}` - const label = - submitLabel || title || `${formType === 'edit' ? 'Update' : 'Create'} ${resourceName}` return ( ({ loading={loading || isSubmitting} form={id} > - {label} + {submitLabel || + title || + `${formType === 'edit' ? 'Update' : 'Create'} ${resourceName}`} )} From e83dd480674fd454385f9226564b66041b799a96 Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Fri, 8 Mar 2024 17:07:14 -0800 Subject: [PATCH 08/11] Reorder props for easier legibility --- app/forms/disk-attach.tsx | 4 ++-- app/forms/disk-create.tsx | 2 +- app/forms/firewall-rules-create.tsx | 4 ++-- app/forms/firewall-rules-edit.tsx | 2 +- app/forms/floating-ip-create.tsx | 2 +- app/forms/floating-ip-edit.tsx | 2 +- app/forms/idp/create.tsx | 2 +- app/forms/idp/edit.tsx | 2 +- app/forms/image-edit.tsx | 2 +- app/forms/image-from-snapshot.tsx | 2 +- app/forms/image-upload.tsx | 2 +- app/forms/ip-pool-create.tsx | 2 +- app/forms/ip-pool-edit.tsx | 2 +- app/forms/ip-pool-range-add.tsx | 2 +- app/forms/network-interface-create.tsx | 4 ++-- app/forms/network-interface-edit.tsx | 2 +- app/forms/project-access.tsx | 2 +- app/forms/project-create.tsx | 2 +- app/forms/project-edit.tsx | 2 +- app/forms/silo-access.tsx | 8 ++++---- app/forms/silo-create.tsx | 2 +- app/forms/snapshot-create.tsx | 2 +- app/forms/ssh-key-create.tsx | 4 ++-- app/forms/subnet-create.tsx | 2 +- app/forms/subnet-edit.tsx | 4 ++-- app/forms/vpc-create.tsx | 2 +- app/forms/vpc-edit.tsx | 2 +- 27 files changed, 35 insertions(+), 35 deletions(-) diff --git a/app/forms/disk-attach.tsx b/app/forms/disk-attach.tsx index a43163d1c3..94f75e86ef 100644 --- a/app/forms/disk-attach.tsx +++ b/app/forms/disk-attach.tsx @@ -46,10 +46,10 @@ export function AttachDiskSideModalForm({ return ( onDismiss(navigate)} onSubmit={({ size, ...rest }) => { const body = { size: size * GiB, ...rest } diff --git a/app/forms/firewall-rules-create.tsx b/app/forms/firewall-rules-create.tsx index 6b8e6b1afe..43afafdf1e 100644 --- a/app/forms/firewall-rules-create.tsx +++ b/app/forms/firewall-rules-create.tsx @@ -504,10 +504,10 @@ export function CreateFirewallRuleForm({ return ( { // TODO: this silently overwrites existing rules with the current name. diff --git a/app/forms/firewall-rules-edit.tsx b/app/forms/firewall-rules-edit.tsx index 44c662c8e1..e23428bdc2 100644 --- a/app/forms/firewall-rules-edit.tsx +++ b/app/forms/firewall-rules-edit.tsx @@ -65,9 +65,9 @@ export function EditFirewallRuleForm({ return ( { // note different filter logic from create: filter out the rule with the diff --git a/app/forms/floating-ip-create.tsx b/app/forms/floating-ip-create.tsx index 5c3620defa..0ad8e21545 100644 --- a/app/forms/floating-ip-create.tsx +++ b/app/forms/floating-ip-create.tsx @@ -83,9 +83,9 @@ export function CreateFloatingIpSideModalForm() { return ( navigate(pb.floatingIps(projectSelector))} onSubmit={({ ip, ...rest }) => { createFloatingIp.mutate({ diff --git a/app/forms/floating-ip-edit.tsx b/app/forms/floating-ip-edit.tsx index 4201b992f6..94b568adfa 100644 --- a/app/forms/floating-ip-edit.tsx +++ b/app/forms/floating-ip-edit.tsx @@ -56,8 +56,8 @@ export function EditFloatingIpSideModalForm() { return ( { editFloatingIp.mutate({ diff --git a/app/forms/idp/create.tsx b/app/forms/idp/create.tsx index f675d8102d..8bed8ea2db 100644 --- a/app/forms/idp/create.tsx +++ b/app/forms/idp/create.tsx @@ -62,8 +62,8 @@ export function CreateIdpSideModalForm() { return ( diff --git a/app/forms/image-edit.tsx b/app/forms/image-edit.tsx index 2fe023c895..1871960436 100644 --- a/app/forms/image-edit.tsx +++ b/app/forms/image-edit.tsx @@ -73,8 +73,8 @@ export function EditImageSideModalForm({ return ( navigate(dismissLink)} subtitle={ diff --git a/app/forms/image-from-snapshot.tsx b/app/forms/image-from-snapshot.tsx index 8ef86aa39b..14126fc975 100644 --- a/app/forms/image-from-snapshot.tsx +++ b/app/forms/image-from-snapshot.tsx @@ -70,8 +70,8 @@ export function CreateImageFromSnapshotSideModalForm() { return ( { diff --git a/app/forms/ip-pool-create.tsx b/app/forms/ip-pool-create.tsx index ebfab20d86..f3d633fbc1 100644 --- a/app/forms/ip-pool-create.tsx +++ b/app/forms/ip-pool-create.tsx @@ -40,8 +40,8 @@ export function CreateIpPoolSideModalForm() { return ( { createPool.mutate({ body: { name, description } }) diff --git a/app/forms/ip-pool-edit.tsx b/app/forms/ip-pool-edit.tsx index b44df0ab5f..da2467ebf8 100644 --- a/app/forms/ip-pool-edit.tsx +++ b/app/forms/ip-pool-edit.tsx @@ -50,8 +50,8 @@ export function EditIpPoolSideModalForm() { return ( { editPool.mutate({ path: poolSelector, body: { name, description } }) diff --git a/app/forms/ip-pool-range-add.tsx b/app/forms/ip-pool-range-add.tsx index e61878215c..332a6cf904 100644 --- a/app/forms/ip-pool-range-add.tsx +++ b/app/forms/ip-pool-range-add.tsx @@ -78,8 +78,8 @@ export function IpPoolAddRangeSideModalForm() { return ( addRange.mutate({ path: { pool }, body })} diff --git a/app/forms/network-interface-create.tsx b/app/forms/network-interface-create.tsx index 455bde4baa..ffedcce784 100644 --- a/app/forms/network-interface-create.tsx +++ b/app/forms/network-interface-create.tsx @@ -52,10 +52,10 @@ export default function CreateNetworkInterfaceForm({ return ( { const interfaceName = defaultValues.name diff --git a/app/forms/project-access.tsx b/app/forms/project-access.tsx index 85d8ef1be4..19d961a8c5 100644 --- a/app/forms/project-access.tsx +++ b/app/forms/project-access.tsx @@ -103,9 +103,9 @@ export function ProjectAccessEditUserSideModal({ return ( { updatePolicy.mutate({ path: { project }, diff --git a/app/forms/project-create.tsx b/app/forms/project-create.tsx index 1c74429fe7..81d7e846d8 100644 --- a/app/forms/project-create.tsx +++ b/app/forms/project-create.tsx @@ -43,8 +43,8 @@ export function CreateProjectSideModalForm() { return ( { createProject.mutate({ body: { name, description } }) diff --git a/app/forms/project-edit.tsx b/app/forms/project-edit.tsx index 561a728421..300df72b92 100644 --- a/app/forms/project-edit.tsx +++ b/app/forms/project-edit.tsx @@ -55,9 +55,9 @@ export function EditProjectSideModalForm() { return ( { editProject.mutate({ path: projectSelector, body: { name, description } }) diff --git a/app/forms/silo-access.tsx b/app/forms/silo-access.tsx index c5a610f9ea..a4cb336ed3 100644 --- a/app/forms/silo-access.tsx +++ b/app/forms/silo-access.tsx @@ -39,11 +39,11 @@ export function SiloAccessAddUserSideModal({ onDismiss, policy }: AddRoleModalPr return ( { // can't happen because roleName is validated not to be '', but TS // wants to be sure @@ -98,9 +98,9 @@ export function SiloAccessEditUserSideModal({ return ( { updatePolicy.mutate({ body: updateRole({ identityId, identityType, roleName }, policy), diff --git a/app/forms/silo-create.tsx b/app/forms/silo-create.tsx index c9f0caaf37..76bd9c4efd 100644 --- a/app/forms/silo-create.tsx +++ b/app/forms/silo-create.tsx @@ -66,9 +66,9 @@ export function CreateSiloSideModalForm() { return ( { createSnapshot.mutate({ query: projectSelector, body: values }) diff --git a/app/forms/ssh-key-create.tsx b/app/forms/ssh-key-create.tsx index a752e7d81a..8b4044f179 100644 --- a/app/forms/ssh-key-create.tsx +++ b/app/forms/ssh-key-create.tsx @@ -44,10 +44,10 @@ export function CreateSSHKeySideModalForm({ return ( createSshKey.mutate({ body })} loading={createSshKey.isPending} diff --git a/app/forms/subnet-create.tsx b/app/forms/subnet-create.tsx index c46671755f..a240c61544 100644 --- a/app/forms/subnet-create.tsx +++ b/app/forms/subnet-create.tsx @@ -39,9 +39,9 @@ export function CreateSubnetForm({ onDismiss }: CreateSubnetFormProps) { return ( createSubnet.mutate({ query: vpcSelector, body })} loading={createSubnet.isPending} diff --git a/app/forms/subnet-edit.tsx b/app/forms/subnet-edit.tsx index 030f6c4f98..ed93841a54 100644 --- a/app/forms/subnet-edit.tsx +++ b/app/forms/subnet-edit.tsx @@ -35,10 +35,10 @@ export function EditSubnetForm({ onDismiss, editing }: EditSubnetFormProps) { return ( { updateSubnet.mutate({ path: { subnet: editing.name }, diff --git a/app/forms/vpc-create.tsx b/app/forms/vpc-create.tsx index 18200b10a7..e89683e40d 100644 --- a/app/forms/vpc-create.tsx +++ b/app/forms/vpc-create.tsx @@ -47,8 +47,8 @@ export function CreateVpcSideModalForm() { return ( createVpc.mutate({ query: projectSelector, body: values })} onDismiss={() => navigate(pb.vpcs(projectSelector))} loading={createVpc.isPending} diff --git a/app/forms/vpc-edit.tsx b/app/forms/vpc-edit.tsx index 10fbc0d63e..169098cd51 100644 --- a/app/forms/vpc-edit.tsx +++ b/app/forms/vpc-edit.tsx @@ -56,9 +56,9 @@ export function EditVpcSideModalForm() { return ( { editVpc.mutate({ From b130a15d8f3164602604a7cbed9178f80481b344 Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Fri, 8 Mar 2024 17:11:51 -0800 Subject: [PATCH 09/11] Comments on props --- app/components/form/SideModalForm.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx index 8a9b04eb8e..8cad703f81 100644 --- a/app/components/form/SideModalForm.tsx +++ b/app/components/form/SideModalForm.tsx @@ -16,11 +16,13 @@ import { SideModal } from '~/ui/lib/SideModal' type CreateFormProps = { formType: 'create' + /** Only needed if you need to override the default button text (`Create ${resourceName}`) */ submitLabel?: string } type EditFormProps = { formType: 'edit' + /** Not permitted, as all edit form buttons should read `Update ${resourceName}` */ submitLabel?: never } @@ -42,6 +44,7 @@ type SideModalFormProps = { /** Error from the API call */ submitError: ApiError | null loading?: boolean + /** Only needed if you need to override the default title (Create/Edit ${resourceName}) */ title?: string subtitle?: ReactNode onSubmit?: (values: TFieldValues) => void From bdfc280f45a2e906236f22d471ab7cd339d1fcd3 Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Mon, 11 Mar 2024 11:09:37 -0700 Subject: [PATCH 10/11] Update sidemodal header, tests --- app/components/form/SideModalForm.tsx | 9 ++++++--- app/forms/access-util.tsx | 1 + app/forms/project-access.tsx | 2 ++ app/forms/silo-access.tsx | 2 ++ app/pages/SiloAccessPage.tsx | 1 + app/pages/project/access/ProjectAccessPage.tsx | 1 + app/ui/lib/SideModal.tsx | 5 ++++- test/e2e/project-access.e2e.ts | 2 +- test/e2e/silo-access.e2e.ts | 2 +- 9 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx index 8cad703f81..e066f1bd3f 100644 --- a/app/components/form/SideModalForm.tsx +++ b/app/components/form/SideModalForm.tsx @@ -84,6 +84,11 @@ export function SideModalForm({ } }, [submitError, form]) + const label = + formType === 'edit' + ? `Update ${resourceName}` + : submitLabel || title || `Create ${resourceName}` + return ( ({ loading={loading || isSubmitting} form={id} > - {submitLabel || - title || - `${formType === 'edit' ? 'Update' : 'Create'} ${resourceName}`} + {label} )} diff --git a/app/forms/access-util.tsx b/app/forms/access-util.tsx index 58087231c1..62af6c9e0c 100644 --- a/app/forms/access-util.tsx +++ b/app/forms/access-util.tsx @@ -50,6 +50,7 @@ export type AddRoleModalProps = { } export type EditRoleModalProps = AddRoleModalProps & { + name?: string identityId: string identityType: IdentityType defaultValues: { roleName: RoleKey } diff --git a/app/forms/project-access.tsx b/app/forms/project-access.tsx index 19d961a8c5..9ac407e749 100644 --- a/app/forms/project-access.tsx +++ b/app/forms/project-access.tsx @@ -83,6 +83,7 @@ export function ProjectAccessAddUserSideModal({ onDismiss, policy }: AddRoleModa export function ProjectAccessEditUserSideModal({ onDismiss, + name, identityId, identityType, policy, @@ -106,6 +107,7 @@ export function ProjectAccessEditUserSideModal({ form={form} formType="edit" resourceName="role" + title={`Change role for ${name}`} onSubmit={({ roleName }) => { updatePolicy.mutate({ path: { project }, diff --git a/app/forms/silo-access.tsx b/app/forms/silo-access.tsx index a4cb336ed3..d1bd8c3f0f 100644 --- a/app/forms/silo-access.tsx +++ b/app/forms/silo-access.tsx @@ -81,6 +81,7 @@ export function SiloAccessAddUserSideModal({ onDismiss, policy }: AddRoleModalPr export function SiloAccessEditUserSideModal({ onDismiss, + name, identityId, identityType, policy, @@ -101,6 +102,7 @@ export function SiloAccessEditUserSideModal({ form={form} formType="edit" resourceName="role" + title={`Change role for ${name}`} onSubmit={({ roleName }) => { updatePolicy.mutate({ body: updateRole({ identityId, identityType, roleName }, policy), diff --git a/app/pages/SiloAccessPage.tsx b/app/pages/SiloAccessPage.tsx index 2fd87ea148..0ba0d4f014 100644 --- a/app/pages/SiloAccessPage.tsx +++ b/app/pages/SiloAccessPage.tsx @@ -172,6 +172,7 @@ export function SiloAccessPage() { setEditingUserRow(null)} policy={siloPolicy} + name={editingUserRow.name} identityId={editingUserRow.id} identityType={editingUserRow.identityType} defaultValues={{ roleName: editingUserRow.siloRole }} diff --git a/app/pages/project/access/ProjectAccessPage.tsx b/app/pages/project/access/ProjectAccessPage.tsx index 6bc38461e4..a83756d870 100644 --- a/app/pages/project/access/ProjectAccessPage.tsx +++ b/app/pages/project/access/ProjectAccessPage.tsx @@ -199,6 +199,7 @@ export function ProjectAccessPage() { setEditingUserRow(null)} policy={projectPolicy} + name={editingUserRow.name} identityId={editingUserRow.id} identityType={editingUserRow.identityType} defaultValues={{ roleName: editingUserRow.projectRole }} diff --git a/app/ui/lib/SideModal.tsx b/app/ui/lib/SideModal.tsx index 341afb585f..5227da1da5 100644 --- a/app/ui/lib/SideModal.tsx +++ b/app/ui/lib/SideModal.tsx @@ -142,7 +142,10 @@ SideModal.Title = ({ subtitle?: ReactNode }) => (
-

+

{title}

{subtitle} diff --git a/test/e2e/project-access.e2e.ts b/test/e2e/project-access.e2e.ts index 877fc7d709..a6481688bc 100644 --- a/test/e2e/project-access.e2e.ts +++ b/test/e2e/project-access.e2e.ts @@ -78,7 +78,7 @@ test('Click through project access page', async ({ page }) => { .click() await page.click('role=menuitem[name="Change role"]') - await expectVisible(page, ['role=heading[name*="Edit role"]']) + await expectVisible(page, ['role=heading[name*="Change role for Simone de Beauvoir"]']) await expectVisible(page, ['button:has-text("Collaborator")']) await page.click('role=button[name*="Role"]') diff --git a/test/e2e/silo-access.e2e.ts b/test/e2e/silo-access.e2e.ts index 833dcce6d9..aaf6142c59 100644 --- a/test/e2e/silo-access.e2e.ts +++ b/test/e2e/silo-access.e2e.ts @@ -67,7 +67,7 @@ test('Click through silo access page', async ({ page }) => { .click() await page.click('role=menuitem[name="Change role"]') - await expectVisible(page, ['role=heading[name*="Edit role"]']) + await expectVisible(page, ['role=heading[name*="Change role for Jacob Klein"]']) await expectVisible(page, ['button:has-text("Collaborator")']) await page.click('role=button[name*="Role"]') From ade7a538183638f8d09791661c644c6cc3bf5e7d Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Mon, 11 Mar 2024 11:39:46 -0700 Subject: [PATCH 11/11] better text wrapping with break-words --- app/ui/lib/SideModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ui/lib/SideModal.tsx b/app/ui/lib/SideModal.tsx index 5227da1da5..f1404a4a4b 100644 --- a/app/ui/lib/SideModal.tsx +++ b/app/ui/lib/SideModal.tsx @@ -143,7 +143,7 @@ SideModal.Title = ({ }) => (

{title}