Skip to content

Commit 7596d63

Browse files
authored
Add TableControls (#2073)
* Add TableControls
1 parent 65531bf commit 7596d63

File tree

6 files changed

+46
-22
lines changed

6 files changed

+46
-22
lines changed

app/pages/project/floating-ips/FloatingIpsPage.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import { useState } from 'react'
99
import { useForm } from 'react-hook-form'
10-
import { Link, Outlet, useNavigate, type LoaderFunctionArgs } from 'react-router-dom'
10+
import { Outlet, useNavigate, type LoaderFunctionArgs } from 'react-router-dom'
1111

1212
import {
1313
apiQueryClient,
@@ -19,6 +19,7 @@ import {
1919
} from '@oxide/api'
2020
import { IpGlobal24Icon, Networking24Icon } from '@oxide/design-system/icons/react'
2121

22+
import { ExternalLink } from '~/components/ExternalLink'
2223
import { HL } from '~/components/HL'
2324
import { getProjectSelector, useProjectSelector } from '~/hooks'
2425
import { confirmAction } from '~/stores/confirm-action'
@@ -27,13 +28,13 @@ import { addToast } from '~/stores/toast'
2728
import { InstanceLinkCell } from '~/table/cells/InstanceLinkCell'
2829
import type { MenuAction } from '~/table/columns/action-col'
2930
import { useQueryTable } from '~/table/QueryTable'
30-
import { buttonStyle } from '~/ui/lib/Button'
3131
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
3232
import { Listbox } from '~/ui/lib/Listbox'
3333
import { Message } from '~/ui/lib/Message'
3434
import { Modal } from '~/ui/lib/Modal'
3535
import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
36-
import { TableActions } from '~/ui/lib/Table'
36+
import { TableControls, TableControlsLink, TableControlsText } from '~/ui/lib/Table'
37+
import { links } from '~/util/links'
3738
import { pb } from '~/util/path-builder'
3839

3940
const EmptyState = () => (
@@ -161,11 +162,16 @@ export function FloatingIpsPage() {
161162
<PageHeader>
162163
<PageTitle icon={<IpGlobal24Icon />}>Floating IPs</PageTitle>
163164
</PageHeader>
164-
<TableActions>
165-
<Link to={pb.floatingIpsNew({ project })} className={buttonStyle({ size: 'sm' })}>
165+
<TableControls>
166+
<TableControlsText>
167+
Floating IPs are public IP addresses that can be attached to instances. They allow
168+
your instances to be reachable from the internet. Find out more about{' '}
169+
<ExternalLink href={links.floatingIpsDocs}>managing floating IPs</ExternalLink>.
170+
</TableControlsText>
171+
<TableControlsLink to={pb.floatingIpsNew({ project })}>
166172
New Floating IP
167-
</Link>
168-
</TableActions>
173+
</TableControlsLink>
174+
</TableControls>
169175
<Table emptyState={<EmptyState />} makeActions={makeActions}>
170176
<Column accessor="name" />
171177
<Column accessor="description" />

app/pages/system/networking/IpPoolPage.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ import { LinkCell } from '~/table/cells/LinkCell'
3333
import type { MenuAction } from '~/table/columns/action-col'
3434
import { useQueryTable } from '~/table/QueryTable'
3535
import { Badge } from '~/ui/lib/Badge'
36-
import { Button, buttonStyle } from '~/ui/lib/Button'
36+
import { buttonStyle } from '~/ui/lib/Button'
3737
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
3838
import { Message } from '~/ui/lib/Message'
3939
import { Modal } from '~/ui/lib/Modal'
4040
import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
41+
import { TableControls, TableControlsButton, TableControlsText } from '~/ui/lib/Table'
4142
import { Tabs } from '~/ui/lib/Tabs'
4243
import { links } from '~/util/links'
4344
import { pb } from '~/util/path-builder'
@@ -216,18 +217,18 @@ function LinkedSilosTable() {
216217

217218
return (
218219
<>
219-
<div className="mb-4 flex items-end justify-between space-x-2">
220-
<p className="mr-8 max-w-2xl text-sans-md text-secondary">
220+
<TableControls>
221+
<TableControlsText>
221222
Users in linked silos can allocate external IPs from this pool for their
222223
instances. A silo can have at most one default pool. IPs are allocated from the
223224
default pool when users ask for one without specifying a pool. Read the docs to
224225
learn more about{' '}
225226
<ExternalLink href={links.ipPoolsDocs}>managing IP pools</ExternalLink>.
226-
</p>
227-
<Button onClick={() => setShowLinkModal(true)} size="sm" className="shrink-0">
227+
</TableControlsText>
228+
<TableControlsButton onClick={() => setShowLinkModal(true)}>
228229
Link silo
229-
</Button>
230-
</div>
230+
</TableControlsButton>
231+
</TableControls>
231232
<Table emptyState={emptyState} makeActions={makeActions}>
232233
<Column accessor="siloId" id="Silo" cell={SiloNameFromId} />
233234
<Column

app/pages/system/silos/SiloIpPoolsTab.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import { linkCell } from '~/table/cells/LinkCell'
2121
import type { MenuAction } from '~/table/columns/action-col'
2222
import { useQueryTable } from '~/table/QueryTable'
2323
import { Badge } from '~/ui/lib/Badge'
24-
import { Button } from '~/ui/lib/Button'
2524
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
2625
import { Message } from '~/ui/lib/Message'
2726
import { Modal } from '~/ui/lib/Modal'
27+
import { TableControls, TableControlsButton, TableControlsText } from '~/ui/lib/Table'
2828
import { links } from '~/util/links'
2929
import { pb } from '~/util/path-builder'
3030

@@ -144,17 +144,17 @@ export function SiloIpPoolsTab() {
144144

145145
return (
146146
<>
147-
<div className="mb-8 flex items-end justify-between space-x-2">
148-
<p className="mr-8 max-w-2xl text-sans-md text-secondary">
147+
<TableControls>
148+
<TableControlsText>
149149
Users in this silo can allocate external IPs from these pools for their instances.
150150
A silo can have at most one default pool. IPs are allocated from the default pool
151151
when users ask for one without specifying a pool. Read the docs to learn more
152152
about <ExternalLink href={links.ipPoolsDocs}>managing IP pools</ExternalLink>.
153-
</p>
154-
<Button onClick={() => setShowLinkModal(true)} size="sm" className="shrink-0">
153+
</TableControlsText>
154+
<TableControlsButton onClick={() => setShowLinkModal(true)}>
155155
Link pool
156-
</Button>
157-
</div>
156+
</TableControlsButton>
157+
</TableControls>
158158
<Table emptyState={<EmptyState />} makeActions={makeActions}>
159159
<Column accessor="name" cell={linkCell((pool) => pb.ipPool({ pool }))} />
160160
<Column accessor="description" />

app/ui/lib/Button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const buttonStyle = ({
3535
variant = 'primary',
3636
}: ButtonStyleProps = {}) => {
3737
return cn(
38-
'ox-button elevation-1 rounded inline-flex items-center justify-center align-top disabled:cursor-not-allowed',
38+
'ox-button elevation-1 rounded inline-flex items-center justify-center align-top disabled:cursor-not-allowed shrink-0',
3939
`btn-${variant}`,
4040
sizeStyle[size],
4141
variant === 'danger'

app/ui/lib/Table.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
*/
88
import cn from 'classnames'
99
import React, { useRef, type ReactElement } from 'react'
10+
import { Link, type LinkProps } from 'react-router-dom'
1011
import SimpleBar from 'simplebar-react'
1112

1213
import { useIsOverflow } from '~/hooks'
14+
import { Button, buttonStyle, type ButtonProps } from '~/ui/lib/Button'
1315
import { classed } from '~/util/classed'
1416

1517
export type TableProps = JSX.IntrinsicElements['table']
@@ -124,3 +126,17 @@ Table.Cell = ({ height = 'large', className, children, ...props }: TableCellProp
124126
export const TableActions = classed.div`-mt-11 mb-3 flex justify-end space-x-2`
125127

126128
export const TableEmptyBox = classed.div`flex h-full max-h-[480px] items-center justify-center rounded-lg border border-secondary p-4`
129+
130+
/**
131+
* Used _outside_ of the `Table`, this element includes a soon-to-be-removed description of the resource inside the table,
132+
* along with a link to more info, and a button to take action on the resource listed in the table.
133+
*/
134+
export const TableControls = classed.div`mb-4 flex items-end justify-between space-x-8`
135+
export const TableControlsText = classed.p`max-w-2xl text-sans-md text-secondary`
136+
137+
export const TableControlsButton = (props: ButtonProps) => (
138+
<Button size="sm" className="shrink-0" {...props} />
139+
)
140+
export const TableControlsLink = (props: LinkProps) => (
141+
<Link className={buttonStyle({ size: 'sm' })} {...props} />
142+
)

app/util/links.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
export const links: Record<string, string> = {
99
cloudInitFormat: 'https://cloudinit.readthedocs.io/en/latest/explanation/format.html',
1010
cloudInitExamples: 'https://cloudinit.readthedocs.io/en/latest/reference/examples.html',
11+
floatingIpsDocs: 'https://docs.oxide.computer/guides/managing-floating-ips',
1112
ipPoolsDocs: 'https://docs.oxide.computer/guides/operator/ip-pool-management',
1213
}

0 commit comments

Comments
 (0)