Skip to content

Commit

Permalink
Show image size on image picker; clean up empty metadata; small color…
Browse files Browse the repository at this point in the history
… fix (#1836)

* Show image size on image picker

* Tweak selected metadata colours

* Refactor JSX for metadata display

---------

Co-authored-by: Benjamin Leonard <[email protected]>
  • Loading branch information
charliepark and benjaminleonard authored Dec 6, 2023
1 parent 6c9420a commit a0bf47a
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 14 deletions.
43 changes: 32 additions & 11 deletions app/components/form/fields/ImageSelectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useController, type Control } from 'react-hook-form'

import type { Image } from '@oxide/api'
import type { ListboxItem } from '@oxide/ui'
import { GiB } from '@oxide/util'
import { bytesToGiB, GiB } from '@oxide/util'

import type { InstanceCreateInput } from 'app/forms/instance-create'

Expand Down Expand Up @@ -41,22 +41,43 @@ export function ImageSelectField({ images, control }: ImageSelectFieldProps) {
)
}

const Slash = () => <span className="mx-0.5 text-quinary">/</span>
const Slash = () => (
<span className="mx-1 text-quinary selected:text-accent-disabled">/</span>
)

export function toListboxItem(i: Image, includeProjectSiloIndicator = false): ListboxItem {
const projectSiloIndicator = includeProjectSiloIndicator ? (
<>
<Slash /> {i.projectId ? 'Project image' : 'Silo image'}
</>
) : null
const { name, os, projectId, size, version } = i
const formattedSize = `${bytesToGiB(size, 1)} GiB`

// filter out any undefined metadata and create a comma-separated list
// for the selected listbox item (shown in labelString)
const condensedImageMetadata = [os, version, formattedSize].filter((i) => !!i).join(', ')
const metadataForLabelString = condensedImageMetadata.length
? ` (${condensedImageMetadata})`
: ''

// for metadata showing in the dropdown's options, include the project / silo indicator if requested
const projectSiloIndicator = includeProjectSiloIndicator
? `${projectId ? 'Project' : 'Silo'} image`
: null
// filter out undefined metadata here, as well, and create a `<Slash />`-separated list
// for the listbox item (shown for each item in the dropdown)
const metadataForLabel = [os, version, formattedSize, projectSiloIndicator]
.filter((i) => !!i)
.map((i, index) => (
<span key={`${i}`}>
{index > 0 ? <Slash /> : ''}
{i}
</span>
))
return {
value: i.id,
labelString: `${i.name} (${i.os}, ${i.version})`,
labelString: `${name}${metadataForLabelString}`,
label: (
<>
<div>{i.name}</div>
<div className="text-secondary">
{i.os} <Slash /> {i.version} {projectSiloIndicator}
<div>{name}</div>
<div className="text-tertiary selected:text-accent-secondary">
{metadataForLabel}
</div>
</>
),
Expand Down
15 changes: 14 additions & 1 deletion libs/util/math.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@
*/
import { expect, it } from 'vitest'

import { splitDecimal } from './math'
import { GiB } from '.'
import { round, splitDecimal } from './math'

it('rounds properly', () => {
expect(round(123.456, 0)).toEqual(123)
expect(round(123.456, 1)).toEqual(123.5)
expect(round(123.456, 2)).toEqual(123.46)
expect(round(123.456, 3)).toEqual(123.456)
expect(round(123.456, 4)).toEqual(123.456) // trailing zeros are culled
expect(round(1.9, 0)).toEqual(2)
expect(round(1.9, 1)).toEqual(1.9)
expect(round(5 / 2, 2)).toEqual(2.5) // math expressions are resolved
expect(round(1879048192 / GiB, 2)).toEqual(1.75) // constants can be evaluated
})

it.each([
[1.23, ['1', '.23']],
Expand Down
4 changes: 2 additions & 2 deletions libs/util/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export const MiB = 1024 * KiB
export const GiB = 1024 * MiB
export const TiB = 1024 * GiB

export const bytesToGiB = (b: number) => round(b / GiB, 2)
export const bytesToTiB = (b: number) => round(b / TiB, 2)
export const bytesToGiB = (b: number, digits = 2) => round(b / GiB, digits)
export const bytesToTiB = (b: number, digits = 2) => round(b / TiB, digits)

0 comments on commit a0bf47a

Please sign in to comment.