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
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ module.exports = {
radix: 'error',
'react-hooks/exhaustive-deps': 'error',
'react-hooks/rules-of-hooks': 'error',
'react/button-has-type': 'error',
'react/jsx-boolean-value': 'error',
'react/display-name': 'off',
'react/react-in-jsx-scope': 'off',
Expand Down
1 change: 1 addition & 0 deletions app/components/MswBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function MswBanner() {
<label className="absolute z-topBar flex h-10 w-full items-center justify-center text-sans-md text-info-secondary bg-info-secondary [&+*]:pt-10">
<Info16Icon className="mr-2" /> This is a technical preview.
<button
type="button"
className="ml-2 flex items-center gap-0.5 text-sans-md hover:text-info"
onClick={() => setIsOpen(true)}
>
Expand Down
1 change: 1 addition & 0 deletions app/components/RefetchIntervalPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export function useIntervalPicker({ enabled, isLoading, fn }: Props) {
</div>
<div className="flex">
<button
type="button"
className={cn(
'flex w-10 items-center justify-center rounded-l border-b border-l border-t border-default disabled:cursor-default',
isLoading && 'hover:bg-hover',
Expand Down
12 changes: 4 additions & 8 deletions app/components/form/fields/DisksTableField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { useState } from 'react'
import { useController, type Control } from 'react-hook-form'

import type { DiskCreate } from '@oxide/api'
import { Error16Icon } from '@oxide/design-system/icons/react'

import { AttachDiskSideModalForm } from '~/forms/disk-attach'
import { CreateDiskSideModalForm } from '~/forms/disk-create'
Expand Down Expand Up @@ -77,13 +76,10 @@ export function DisksTableField({
</>
)}
</MiniTable.Cell>
<MiniTable.Cell>
<button
onClick={() => onChange(items.filter((i) => i.name !== item.name))}
>
<Error16Icon title={`remove ${item.name}`} />
</button>
</MiniTable.Cell>
<MiniTable.RemoveCell
onClick={() => onChange(items.filter((i) => i.name !== item.name))}
label={`remove disk ${item.name}`}
/>
</MiniTable.Row>
))}
</MiniTable.Body>
Expand Down
22 changes: 9 additions & 13 deletions app/components/form/fields/NetworkInterfaceField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type {
InstanceNetworkInterfaceAttachment,
InstanceNetworkInterfaceCreate,
} from '@oxide/api'
import { Error16Icon } from '@oxide/design-system/icons/react'

import type { InstanceCreateInput } from '~/forms/instance-create'
import { CreateNetworkInterfaceForm } from '~/forms/network-interface-create'
Expand Down Expand Up @@ -94,18 +93,15 @@ export function NetworkInterfaceField({
<MiniTable.Cell>{item.name}</MiniTable.Cell>
<MiniTable.Cell>{item.vpcName}</MiniTable.Cell>
<MiniTable.Cell>{item.subnetName}</MiniTable.Cell>
<MiniTable.Cell>
<button
onClick={() =>
onChange({
type: 'create',
params: value.params.filter((i) => i.name !== item.name),
})
}
>
<Error16Icon title={`remove ${item.name}`} />
</button>
</MiniTable.Cell>
<MiniTable.RemoveCell
onClick={() =>
onChange({
type: 'create',
params: value.params.filter((i) => i.name !== item.name),
})
}
label={`remove network interface ${item.name}`}
/>
</MiniTable.Row>
))}
</MiniTable.Body>
Expand Down
12 changes: 4 additions & 8 deletions app/components/form/fields/TlsCertsField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { useController, type Control } from 'react-hook-form'
import type { Merge } from 'type-fest'

import type { CertificateCreate } from '@oxide/api'
import { Error16Icon } from '@oxide/design-system/icons/react'

import type { SiloCreateFormValues } from '~/forms/silo-create'
import { useForm } from '~/hooks'
Expand Down Expand Up @@ -53,13 +52,10 @@ export function TlsCertsField({ control }: { control: Control<SiloCreateFormValu
key={item.name}
>
<MiniTable.Cell>{item.name}</MiniTable.Cell>
<MiniTable.Cell>
<button
onClick={() => onChange(items.filter((i) => i.name !== item.name))}
>
<Error16Icon title={`remove ${item.name}`} />
</button>
</MiniTable.Cell>
<MiniTable.RemoveCell
onClick={() => onChange(items.filter((i) => i.name !== item.name))}
label={`remove cert ${item.name}`}
/>
</MiniTable.Row>
))}
</MiniTable.Body>
Expand Down
54 changes: 22 additions & 32 deletions app/forms/firewall-rules-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
type VpcFirewallRuleTarget,
type VpcFirewallRuleUpdate,
} from '@oxide/api'
import { Error16Icon } from '@oxide/design-system/icons/react'

import { CheckboxField } from '~/components/form/fields/CheckboxField'
import { DescriptionField } from '~/components/form/fields/DescriptionField'
Expand Down Expand Up @@ -317,19 +316,16 @@ export const CommonFields = ({ error, control }: CommonFieldsProps) => {
<Badge variant="solid">{t.type}</Badge>
</MiniTable.Cell>
<MiniTable.Cell>{t.value}</MiniTable.Cell>
<MiniTable.Cell>
<button
onClick={() =>
targets.onChange(
targets.value.filter(
(i) => !(i.value === t.value && i.type === t.type)
)
<MiniTable.RemoveCell
onClick={() =>
targets.onChange(
targets.value.filter(
(i) => !(i.value === t.value && i.type === t.type)
)
}
>
<Error16Icon title={`remove ${t.value}`} />
</button>
</MiniTable.Cell>
)
}
label={`remove target ${t.value}`}
/>
</MiniTable.Row>
))}
</MiniTable.Body>
Expand Down Expand Up @@ -399,13 +395,10 @@ export const CommonFields = ({ error, control }: CommonFieldsProps) => {
{ports.value.map((p) => (
<MiniTable.Row tabIndex={0} aria-label={p} key={p}>
<MiniTable.Cell>{p}</MiniTable.Cell>
<MiniTable.Cell>
<button
onClick={() => ports.onChange(ports.value.filter((p1) => p1 !== p))}
>
<Error16Icon title={`remove ${p}`} />
</button>
</MiniTable.Cell>
<MiniTable.RemoveCell
onClick={() => ports.onChange(ports.value.filter((p1) => p1 !== p))}
label={`remove port ${p}`}
/>
</MiniTable.Row>
))}
</MiniTable.Body>
Expand Down Expand Up @@ -501,19 +494,16 @@ export const CommonFields = ({ error, control }: CommonFieldsProps) => {
<Badge variant="solid">{h.type}</Badge>
</MiniTable.Cell>
<MiniTable.Cell>{h.value}</MiniTable.Cell>
<MiniTable.Cell>
<button
onClick={() =>
hosts.onChange(
hosts.value.filter(
(i) => !(i.value === h.value && i.type === h.type)
)
<MiniTable.RemoveCell
onClick={() =>
hosts.onChange(
hosts.value.filter(
(i) => !(i.value === h.value && i.type === h.type)
)
}
>
<Error16Icon title={`remove ${h.value}`} />
</button>
</MiniTable.Cell>
)
}
label={`remove host ${h.value}`}
/>
</MiniTable.Row>
))}
</MiniTable.Body>
Expand Down
2 changes: 1 addition & 1 deletion app/table/cells/LinkCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function LinkCell({ to, children }: { to: string; children: React.ReactNo

export const ButtonCell = ({ children, ...props }: React.ComponentProps<'button'>) => {
return (
<button className={linkClass} {...props}>
<button type="button" className={linkClass} {...props}>
<Pusher />
<div className="relative">{children}</div>
</button>
Expand Down
2 changes: 2 additions & 0 deletions app/ui/lib/ActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export function ActionMenu(props: ActionMenuProps) {

{input.length > 0 && (
<button
type="button"
className="flex items-center py-6 pl-6 pr-4 text-secondary"
onClick={() => {
setInput('')
Expand All @@ -147,6 +148,7 @@ export function ActionMenu(props: ActionMenuProps) {
)}

<button
type="button"
onClick={onDismiss}
className="flex h-full items-center border-l px-6 align-middle text-mono-sm text-secondary border-secondary"
>
Expand Down
1 change: 1 addition & 0 deletions app/ui/lib/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
'visually-disabled': isDisabled,
})}
ref={ref}
/* eslint-disable-next-line react/button-has-type */
type={type}
onMouseDown={isDisabled ? noop : undefined}
onClick={isDisabled ? noop : onClick}
Expand Down
1 change: 1 addition & 0 deletions app/ui/lib/FileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const FileInput = forwardRef(
({filesize(file.size, { base: 2, pad: true })})
</span>
<button
type="button"
onClick={handleResetInput}
className="pointer-events-auto ml-1 inline-flex rounded p-1 hover:children:text-tertiary"
aria-label="Clear file"
Expand Down
12 changes: 12 additions & 0 deletions app/ui/lib/MiniTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*
* Copyright Oxide Computer Company
*/
import Error16Icon from '@oxide/design-system/icons/react/Error16Icon'

import { classed } from '~/util/classed'

import { Table as BigTable } from './Table'
Expand Down Expand Up @@ -32,3 +34,13 @@ export const Cell = ({ children }: Children) => {
</td>
)
}

// followed this for icon in button best practices
// https://www.sarasoueidan.com/blog/accessible-icon-buttons/
export const RemoveCell = ({ onClick, label }: { onClick: () => void; label: string }) => (
<Cell>
<button type="button" onClick={onClick} aria-label={label}>
<Error16Icon aria-hidden focusable="false" />
</button>
</Cell>
)
1 change: 1 addition & 0 deletions app/ui/lib/NumberInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ function IncrementButton(props: AriaButtonProps<'button'> & { className?: string

return (
<button
type="button"
{...buttonProps}
className={cn(
'flex h-1/2 w-8 items-center justify-center hover:bg-hover',
Expand Down
2 changes: 2 additions & 0 deletions app/ui/lib/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const Pagination = ({
</span>
<span className="flex space-x-3">
<button
type="button"
className={cn(
hasPrev ? 'text-secondary hover:text-default' : 'text-disabled',
'flex items-center text-mono-sm'
Expand All @@ -73,6 +74,7 @@ export const Pagination = ({
prev
</button>
<button
type="button"
className={cn(
hasNext ? 'text-secondary hover:text-default' : 'text-disabled',
'flex items-center text-mono-sm'
Expand Down
1 change: 1 addition & 0 deletions app/ui/lib/RangeCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const CalendarButton = ({
isDisabled: boolean
}) => (
<button
type="button"
onClick={handleClick}
disabled={isDisabled}
className={cn(
Expand Down
1 change: 1 addition & 0 deletions app/ui/lib/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export const Toast = ({
)}
</div>
<button
type="button"
aria-label="Dismiss notification"
className={cn('-m-2 flex h-auto !border-transparent p-2', textColor[variant])}
onClick={onClose}
Expand Down
2 changes: 1 addition & 1 deletion app/ui/lib/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Tooltip } from './Tooltip'
export const Default = () => (
<>
<Tooltip content="Filter">
<button>
<button type="button">
<Filter12Icon />
</button>
</Tooltip>
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/silos.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ test('Create silo', async ({ page }) => {
await expect(page.getByRole('cell', { name: 'test-cert-2', exact: true })).toBeVisible()

// now delete the first
await page.getByRole('button', { name: 'remove test-cert', exact: true }).click()
await page.getByRole('button', { name: 'remove cert test-cert', exact: true }).click()
// Cert should not appear after it has been deleted
await expect(certCell).toBeHidden()

Expand Down