diff --git a/.oxlintrc.json b/.oxlintrc.json index 901a1248cc..f373775e6e 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -54,8 +54,16 @@ "no-restricted-imports": [ "error", { - // prevent confusion due to auto-imports and barrel files - "paths": ["."], + "paths": [ + { + "name": ".", + "message": "Import from the file directly to avoid confusion due to auto-imports and barrel files." + }, + { + "name": "filesize", + "message": "Import formatBytes from ~/util/units instead." + } + ], "patterns": [ // import all CSS except index.css at top level through CSS @import statements // to avoid bad ordering situations. See https://github.com/oxidecomputer/console/pull/2035 diff --git a/app/forms/disk-create.tsx b/app/forms/disk-create.tsx index b1f3b81f6f..2e8f182d43 100644 --- a/app/forms/disk-create.tsx +++ b/app/forms/disk-create.tsx @@ -6,7 +6,6 @@ * Copyright Oxide Computer Company */ import { useQuery } from '@tanstack/react-query' -import { filesize } from 'filesize' import { useMemo } from 'react' import { useController, useForm, type Control } from 'react-hook-form' import { match } from 'ts-pattern' @@ -43,7 +42,7 @@ import { TipIcon } from '~/ui/lib/TipIcon' import { toLocaleDateString } from '~/util/date' import { docLinks } from '~/util/links' import { diskSizeNearest10 } from '~/util/math' -import { bytesToGiB, GiB } from '~/util/units' +import { bytesToGiB, formatBytes, GiB } from '~/util/units' /** * Same as DiskSource but with image and snapshot ID optional, reflecting The @@ -416,7 +415,7 @@ const SnapshotSelectField = ({ control }: { control: Control }) label="Source snapshot" placeholder="Select a snapshot" items={snapshots.map((i) => { - const formattedSize = filesize(i.size, { base: 2, output: 'object' }) + const formattedSize = formatBytes(i.size) return { value: i.id, selectedLabel: i.name, diff --git a/app/forms/image-from-snapshot.tsx b/app/forms/image-from-snapshot.tsx index 7c6f49acb8..b6f7767e88 100644 --- a/app/forms/image-from-snapshot.tsx +++ b/app/forms/image-from-snapshot.tsx @@ -5,7 +5,6 @@ * * Copyright Oxide Computer Company */ -import { filesize } from 'filesize' import { useForm } from 'react-hook-form' import { useNavigate, type LoaderFunctionArgs } from 'react-router' @@ -31,6 +30,7 @@ import { PropertiesTable } from '~/ui/lib/PropertiesTable' import { docLinks } from '~/util/links' import { pb } from '~/util/path-builder' import type * as PP from '~/util/path-params' +import { formatBytes } from '~/util/units' const defaultValues: Omit = { name: '', @@ -94,7 +94,7 @@ export default function CreateImageFromSnapshotSideModalForm() { {data.name} {project} - {filesize(data.size, { base: 2 })} + {formatBytes(data.size).label} diff --git a/app/forms/image-upload.tsx b/app/forms/image-upload.tsx index facc6b28ea..93e92573d6 100644 --- a/app/forms/image-upload.tsx +++ b/app/forms/image-upload.tsx @@ -7,7 +7,6 @@ */ import { skipToken, useQuery } from '@tanstack/react-query' import cn from 'classnames' -import { filesize } from 'filesize' import pMap from 'p-map' import pRetry from 'p-retry' import { useRef, useState } from 'react' @@ -50,10 +49,11 @@ import { invariant } from '~/util/invariant' import { docLinks, links } from '~/util/links' import { pb } from '~/util/path-builder' import { isAllZeros } from '~/util/str' -import { GiB, KiB } from '~/util/units' +import { formatBytes, GiB, KiB } from '~/util/units' -/** Format file size with two decimal points */ -const fsize = (bytes: number) => filesize(bytes, { base: 2, pad: true }) +// Padded because otherwise the numbers jump around a bit, e.g., when it goes +// from 10.55 to 14.7 to 19.23 +const fsize = (bytes: number) => formatBytes(bytes, { pad: true }).label type FormValues = { imageName: string diff --git a/app/pages/project/instances/InstancePage.tsx b/app/pages/project/instances/InstancePage.tsx index 9e337fa344..0a02ccc6ca 100644 --- a/app/pages/project/instances/InstancePage.tsx +++ b/app/pages/project/instances/InstancePage.tsx @@ -6,7 +6,6 @@ * Copyright Oxide Computer Company */ import { useQuery } from '@tanstack/react-query' -import { filesize } from 'filesize' import { useId, useState } from 'react' import { useForm } from 'react-hook-form' import { Link, useNavigate, type LoaderFunctionArgs } from 'react-router' @@ -56,7 +55,7 @@ import { truncate } from '~/ui/lib/Truncate' import { instanceMetricsBase, pb } from '~/util/path-builder' import type * as PP from '~/util/path-params' import { pluralize } from '~/util/str' -import { GiB } from '~/util/units' +import { formatBytes, GiB } from '~/util/units' import { useMakeInstanceActions } from './actions' @@ -168,7 +167,7 @@ export default function InstancePage() { enabled: !!primaryVpcId, }) - const memory = filesize(instance.memory, { output: 'object', base: 2 }) + const memory = formatBytes(instance.memory) return ( <> diff --git a/app/pages/project/instances/InstancesPage.tsx b/app/pages/project/instances/InstancesPage.tsx index 7c44a8ec11..19af2687db 100644 --- a/app/pages/project/instances/InstancesPage.tsx +++ b/app/pages/project/instances/InstancesPage.tsx @@ -7,7 +7,6 @@ */ import { useQuery, type UseQueryOptions } from '@tanstack/react-query' import { createColumnHelper } from '@tanstack/react-table' -import { filesize } from 'filesize' import { useMemo, useRef, useState } from 'react' import { type LoaderFunctionArgs } from 'react-router' @@ -42,6 +41,7 @@ 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' @@ -113,7 +113,7 @@ export default function InstancesPage() { colHelper.accessor('memory', { header: 'Memory', cell: (info) => { - const memory = filesize(info.getValue(), { output: 'object', base: 2 }) + const memory = formatBytes(info.getValue()) return ( <> {memory.value} {memory.unit} diff --git a/app/pages/system/inventory/sled/SledPage.tsx b/app/pages/system/inventory/sled/SledPage.tsx index f60dfc91c2..7947e6c661 100644 --- a/app/pages/system/inventory/sled/SledPage.tsx +++ b/app/pages/system/inventory/sled/SledPage.tsx @@ -5,7 +5,6 @@ * * Copyright Oxide Computer Company */ -import { filesize } from 'filesize' import type { LoaderFunctionArgs } from 'react-router' import { api, q, queryClient, usePrefetchedQuery } from '@oxide/api' @@ -19,6 +18,7 @@ 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' @@ -38,7 +38,7 @@ export default function SledPage() { const { sledId } = useSledParams() const { data: sled } = usePrefetchedQuery(sledView({ sledId })) - const ram = filesize(sled.usablePhysicalRam, { output: 'object', base: 2 }) + const ram = formatBytes(sled.usablePhysicalRam) return ( <> diff --git a/app/table/cells/InstanceResourceCell.tsx b/app/table/cells/InstanceResourceCell.tsx index acc3f1e626..a735f54e14 100644 --- a/app/table/cells/InstanceResourceCell.tsx +++ b/app/table/cells/InstanceResourceCell.tsx @@ -5,14 +5,14 @@ * * Copyright Oxide Computer Company */ -import { filesize } from 'filesize' - import type { Instance } from '@oxide/api' +import { formatBytes } from '~/util/units' + type Props = { value: Pick } export const InstanceResourceCell = ({ value }: Props) => { - const memory = filesize(value.memory, { output: 'object', base: 2 }) + const memory = formatBytes(value.memory) return (
diff --git a/app/table/columns/common.tsx b/app/table/columns/common.tsx index e6cb831039..99f0aa8d57 100644 --- a/app/table/columns/common.tsx +++ b/app/table/columns/common.tsx @@ -6,13 +6,12 @@ * Copyright Oxide Computer Company */ -import { filesize } from 'filesize' - import type { InstanceState } from '~/api' 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' // the full type of the info arg is CellContext from RT, but in these // cells we only care about the return value of getValue @@ -40,7 +39,7 @@ function instanceStateCell(info: Info) { // not using Info so this can also be used for minitables export function sizeCellInner(value: number) { - const size = filesize(value, { base: 2, output: 'object' }) + const size = formatBytes(value) return ( {size.value} {size.unit} diff --git a/app/ui/lib/FileInput.tsx b/app/ui/lib/FileInput.tsx index 11b9c060c7..3728a1d8ed 100644 --- a/app/ui/lib/FileInput.tsx +++ b/app/ui/lib/FileInput.tsx @@ -6,7 +6,6 @@ * Copyright Oxide Computer Company */ import cn from 'classnames' -import { filesize } from 'filesize' import { useRef, useState, @@ -20,6 +19,7 @@ import { mergeRefs } from 'react-merge-refs' import { Document16Icon, Error16Icon } from '@oxide/design-system/icons/react' import { Truncate } from '~/ui/lib/Truncate' +import { formatBytes } from '~/util/units' export type FileInputProps = Omit, 'type' | 'onChange'> & { onChange: (f: File | null) => void @@ -99,9 +99,7 @@ export function FileInput({ {file && !dragOver ? (
- - ({filesize(file.size, { base: 2, pad: true })}) - + ({formatBytes(file.size).label})