(disks[0].name)
@@ -86,9 +81,6 @@ function DiskMetrics({ disks }: { disks: Disk[] }) {
return (
<>
- {/* TODO: using a Formik field here feels like overkill, but we've built
- ListboxField to require that, i.e., there's no way to get the nice worked-out
- layout from ListboxField without using Formik. Something to think about. */}
-
+ {dateTimeRangePicker}
{/* TODO: separate "Reads" from "(count)" so we can
diff --git a/app/pages/system/CapacityUtilizationPage.tsx b/app/pages/system/CapacityUtilizationPage.tsx
index c8396a6c53..ea71b40732 100644
--- a/app/pages/system/CapacityUtilizationPage.tsx
+++ b/app/pages/system/CapacityUtilizationPage.tsx
@@ -5,7 +5,7 @@ import { Divider, Listbox, PageHeader, PageTitle, Snapshots24Icon } from '@oxide
import { bytesToGiB } from '@oxide/util'
import { SystemMetric } from 'app/components/SystemMetric'
-import { DateTimeRangePicker, useDateTimeRangePickerState } from 'app/components/form'
+import { useDateTimeRangePicker } from 'app/components/form'
const FLEET_ID = '001de000-1334-4000-8000-000000000000'
const DEFAULT_SILO_ID = '001de000-5110-4000-8000-000000000000'
@@ -20,11 +20,7 @@ export function CapacityUtilizationPage() {
const { data: silos } = useApiQuery('siloList', {})
const initialPreset = 'lastHour'
- const {
- startTime,
- endTime,
- onChange: onTimeChange,
- } = useDateTimeRangePickerState(initialPreset)
+ const { startTime, endTime, dateTimeRangePicker } = useDateTimeRangePicker(initialPreset)
const siloItems = useMemo(() => {
const items = silos?.items.map((silo) => ({ label: silo.name, value: silo.id })) || []
@@ -66,13 +62,7 @@ export function CapacityUtilizationPage() {
{/* TODO: need a button to clear the silo */}
-
+ {dateTimeRangePicker}
{/* TODO: this divider is supposed to go all the way across */}
diff --git a/libs/ui/lib/hooks/use-interval.ts b/libs/ui/lib/hooks/use-interval.ts
index d7550c73cc..e4efd61c32 100644
--- a/libs/ui/lib/hooks/use-interval.ts
+++ b/libs/ui/lib/hooks/use-interval.ts
@@ -1,16 +1,29 @@
import { useEffect, useRef } from 'react'
-// use null delay to prevent the interval from firing
-export default function useInterval(callback: () => void, delay: number | null) {
+interface UseIntervalProps {
+ fn: () => void
+ delay: number | null
+ /** Use to force a render because changes to the callback won't */
+ key?: string
+}
+
+/**
+ * Fire `fn` on an interval. Does not fire immediately, only after `delay`.
+ *
+ * Use null `delay` to prevent the interval from firing at all. Change `key` to
+ * force a render, which cleans up the currently set interval and possibly sets
+ * a new one..
+ */
+export default function useInterval({ fn, delay, key }: UseIntervalProps) {
const callbackRef = useRef<() => void>()
useEffect(() => {
- callbackRef.current = callback
- }, [callback])
+ callbackRef.current = fn
+ }, [fn])
useEffect(() => {
if (delay === null) return
const intervalId = setInterval(() => callbackRef.current?.(), delay)
return () => clearInterval(intervalId)
- }, [delay])
+ }, [delay, key])
}
diff --git a/libs/ui/lib/listbox/Listbox.tsx b/libs/ui/lib/listbox/Listbox.tsx
index 0a20c17090..6cf77860ae 100644
--- a/libs/ui/lib/listbox/Listbox.tsx
+++ b/libs/ui/lib/listbox/Listbox.tsx
@@ -58,7 +58,7 @@ export const Listbox = ({
>
{select.selectedItem ? itemToString(select.selectedItem) : placeholder}
-