Skip to content
Open
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
4 changes: 2 additions & 2 deletions app/components/form/fields/DisksTableField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import { Badge } from '@oxide/design-system/ui'
import { AttachDiskModalForm } from '~/forms/disk-attach'
import { CreateDiskSideModalForm } from '~/forms/disk-create'
import type { InstanceCreateInput } from '~/forms/instance-create'
import { sizeCellInner } from '~/table/columns/common'
import { Button } from '~/ui/lib/Button'
import { MiniTable } from '~/ui/lib/MiniTable'
import { Truncate } from '~/ui/lib/Truncate'
import { Size } from '~/ui/lib/ValueUnit'

export type DiskTableItem =
| (DiskCreate & { action: 'create' })
Expand Down Expand Up @@ -68,7 +68,7 @@ export function DisksTableField({
},
{
header: 'Size',
cell: (item) => sizeCellInner(item.size),
cell: (item) => <Size bytes={item.size} />,
},
]}
rowKey={(item) => item.name}
Expand Down
11 changes: 4 additions & 7 deletions app/pages/project/instances/InstancePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ import { Modal } from '~/ui/lib/Modal'
import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
import { PropertiesTable } from '~/ui/lib/PropertiesTable'
import { truncate } from '~/ui/lib/Truncate'
import { Size, ValueUnit } from '~/ui/lib/ValueUnit'
import { instanceMetricsBase, pb } from '~/util/path-builder'
import type * as PP from '~/util/path-params'
import { pluralize } from '~/util/str'
import { formatBytes, GiB } from '~/util/units'
import { GiB } from '~/util/units'

import { useMakeInstanceActions } from './actions'

Expand Down Expand Up @@ -167,8 +168,6 @@ export default function InstancePage() {
enabled: !!primaryVpcId,
})

const memory = formatBytes(instance.memory)

return (
<>
<PageHeader>
Expand Down Expand Up @@ -216,12 +215,10 @@ export default function InstancePage() {
</PageHeader>
<PropertiesTable columns={2} className="-mt-8 mb-8">
<PropertiesTable.Row label="cpu">
<span className="text-default">{instance.ncpus}</span>
<span className="text-tertiary ml-1">{pluralize(' vCPU', instance.ncpus)}</span>
<ValueUnit value={instance.ncpus} unit={pluralize('vCPU', instance.ncpus)} />
</PropertiesTable.Row>
<PropertiesTable.Row label="ram">
<span className="text-default">{memory.value}</span>
<span className="text-tertiary ml-1"> {memory.unit}</span>
<Size bytes={instance.memory} />
</PropertiesTable.Row>
<PropertiesTable.Row label="state">
<div className="flex items-center gap-2">
Expand Down
16 changes: 3 additions & 13 deletions app/pages/project/instances/InstancesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ import { EmptyMessage } from '~/ui/lib/EmptyMessage'
import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
import { TableActions } from '~/ui/lib/Table'
import { Tooltip } from '~/ui/lib/Tooltip'
import { Size, ValueUnit } from '~/ui/lib/ValueUnit'
import { setDiff } from '~/util/array'
import { ALL_ISH } from '~/util/consts'
import { toLocaleTimeString } from '~/util/date'
import { pb } from '~/util/path-builder'
import { pluralize } from '~/util/str'
import { formatBytes } from '~/util/units'

import { useMakeInstanceActions } from './actions'
import { ResizeInstanceModal } from './InstancePage'
Expand Down Expand Up @@ -104,22 +104,12 @@ export default function InstancesPage() {
colHelper.accessor('ncpus', {
header: 'CPU',
cell: (info) => (
<>
{info.getValue()}{' '}
<span className="text-tertiary ml-1">{pluralize('vCPU', info.getValue())}</span>
</>
<ValueUnit value={info.getValue()} unit={pluralize('vCPU', info.getValue())} />
),
}),
colHelper.accessor('memory', {
header: 'Memory',
cell: (info) => {
const memory = formatBytes(info.getValue())
return (
<>
{memory.value} <span className="text-tertiary ml-1">{memory.unit}</span>
</>
)
},
cell: (info) => <Size bytes={info.getValue()} />,
}),
colHelper.accessor(
(i) => ({ runState: i.runState, timeRunStateUpdated: i.timeRunStateUpdated }),
Expand Down
11 changes: 4 additions & 7 deletions app/pages/system/inventory/sled/SledPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { PropertiesTable } from '~/ui/lib/PropertiesTable'
import { truncate } from '~/ui/lib/Truncate'
import { pb } from '~/util/path-builder'
import type * as PP from '~/util/path-params'
import { formatBytes } from '~/util/units'

import { ProvisionPolicyBadge, SledKindBadge, SledStateBadge } from './SledBadges'

Expand All @@ -38,8 +37,6 @@ export default function SledPage() {
const { sledId } = useSledParams()
const { data: sled } = usePrefetchedQuery(sledView({ sledId }))

const ram = formatBytes(sled.usablePhysicalRam)

return (
<>
<PageHeader>
Expand Down Expand Up @@ -74,10 +71,10 @@ export default function SledPage() {
<PropertiesTable.Row label="rack id">
<span className="text-default">{sled.rackId}</span>
</PropertiesTable.Row>
<PropertiesTable.Row label="usable physical ram">
<span className="text-default pr-0.5">{ram.value}</span>
<span className="text-tertiary">{ram.unit}</span>
</PropertiesTable.Row>
<PropertiesTable.SizeRow
label="usable physical ram"
bytes={sled.usablePhysicalRam}
/>
</PropertiesTable>

<RouteTabs fullWidth>
Expand Down
23 changes: 10 additions & 13 deletions app/table/cells/InstanceResourceCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,17 @@
*/
import type { Instance } from '@oxide/api'

import { formatBytes } from '~/util/units'
import { Size, ValueUnit } from '~/ui/lib/ValueUnit'

type Props = { value: Pick<Instance, 'ncpus' | 'memory'> }

export const InstanceResourceCell = ({ value }: Props) => {
const memory = formatBytes(value.memory)
return (
<div className="space-y-0.5">
<div>
{value.ncpus} <span className="text-tertiary">vCPU</span>
</div>
<div>
{memory.value} <span className="text-tertiary">{memory.unit}</span>
</div>
export const InstanceResourceCell = ({ value }: Props) => (
<div className="space-y-0.5">
<div>
<ValueUnit value={value.ncpus} unit="vCPU" />
</div>
)
}
<div>
<Size bytes={value.memory} />
</div>
</div>
)
14 changes: 2 additions & 12 deletions app/table/columns/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { InstanceStateBadge } from '~/components/StateBadge'
import { DescriptionCell } from '~/table/cells/DescriptionCell'
import { CopyToClipboard } from '~/ui/lib/CopyToClipboard'
import { DateTime } from '~/ui/lib/DateTime'
import { formatBytes } from '~/util/units'
import { Size } from '~/ui/lib/ValueUnit'

// the full type of the info arg is CellContext<Row, Item> from RT, but in these
// cells we only care about the return value of getValue
Expand All @@ -37,16 +37,6 @@ function instanceStateCell(info: Info<InstanceState>) {
return <InstanceStateBadge state={info.getValue()} />
}

// not using Info<number> so this can also be used for minitables
export function sizeCellInner(value: number) {
const size = formatBytes(value)
return (
<span className="text-default">
{size.value} <span className="text-tertiary">{size.unit}</span>
</span>
)
}

/** Columns used in a bunch of tables */
export const Columns = {
/** Truncates text if too long, full text in tooltip */
Expand All @@ -55,7 +45,7 @@ export const Columns = {
},
id: { header: 'ID', cell: idCell },
instanceState: { header: 'state', cell: instanceStateCell },
size: { cell: (info: Info<number>) => sizeCellInner(info.getValue()) },
size: { cell: (info: Info<number>) => <Size bytes={info.getValue()} /> },
timeCreated: { header: 'created', cell: dateCell },
timeModified: { header: 'modified', cell: dateCell },
}
8 changes: 6 additions & 2 deletions app/ui/lib/PropertiesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import type { ReactNode } from 'react'

import { DescriptionCell } from '~/table/cells/DescriptionCell'
import { EmptyCell } from '~/table/cells/EmptyCell'
import { sizeCellInner } from '~/table/columns/common'
import { isOneOf } from '~/util/children'
import { invariant } from '~/util/invariant'

import { CopyToClipboard } from './CopyToClipboard'
import { DateTime } from './DateTime'
import { Truncate } from './Truncate'
import { Size } from './ValueUnit'

export interface PropertiesTableProps {
className?: string
Expand Down Expand Up @@ -110,7 +110,11 @@ PropertiesTable.SizeRow = ({
}: {
bytes: number
label?: string
}) => <PropertiesTable.Row label={label}>{sizeCellInner(bytes)}</PropertiesTable.Row>
}) => (
<PropertiesTable.Row label={label}>
<Size bytes={bytes} />
</PropertiesTable.Row>
)

PropertiesTable.CopyableRow = ({ label, text }: { label: string; text: string }) => (
<PropertiesTable.Row label={label}>
Expand Down
28 changes: 28 additions & 0 deletions app/ui/lib/ValueUnit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import type { ReactNode } from 'react'

import { formatBytes } from '~/util/units'

/**
* A value with a dimmed unit label, e.g. `4 vCPU` or `16 GiB`: the value renders
* in the default text color, the unit in tertiary, separated by a single space.
*/
export function ValueUnit({ value, unit }: { value: ReactNode; unit: ReactNode }) {
return (
<span className="text-default">
{value} <span className="text-tertiary">{unit}</span>
</span>
)
}

/** Format a byte count with `formatBytes` and render it as a {@link ValueUnit}. */
export function Size({ bytes }: { bytes: number }) {
const { value, unit } = formatBytes(bytes)
return <ValueUnit value={value} unit={unit} />
}
Loading