ui: small refactoring / auto formatting

This commit is contained in:
henrygd
2026-02-12 18:40:16 -05:00
parent e816ea143a
commit 1f1a448aef
6 changed files with 90 additions and 101 deletions

View File

@@ -54,8 +54,7 @@ export default function ContainersTable({ systemId }: { systemId?: string }) {
fields: "id,name,image,cpu,memory,net,health,status,system,updated", fields: "id,name,image,cpu,memory,net,health,status,system,updated",
filter: systemId ? pb.filter("system={:system}", { system: systemId }) : undefined, filter: systemId ? pb.filter("system={:system}", { system: systemId }) : undefined,
}) })
.then( .then(({ items }) => {
({ items }) => {
if (items.length === 0) { if (items.length === 0) {
setData((curItems) => { setData((curItems) => {
if (systemId) { if (systemId) {
@@ -82,8 +81,7 @@ export default function ContainersTable({ systemId }: { systemId?: string }) {
} }
return newItems return newItems
}) })
} })
)
} }
// initial load // initial load
@@ -285,7 +283,7 @@ async function getInfoHtml(container: ContainerRecord): Promise<string> {
]) ])
try { try {
info = JSON.stringify(JSON.parse(info), null, 2) info = JSON.stringify(JSON.parse(info), null, 2)
} catch (_) { } } catch (_) {}
return info ? highlighter.codeToHtml(info, { lang: "json", theme: syntaxTheme }) : t`No results.` return info ? highlighter.codeToHtml(info, { lang: "json", theme: syntaxTheme }) : t`No results.`
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@@ -342,7 +340,7 @@ function ContainerSheet({
setLogsDisplay("") setLogsDisplay("")
setInfoDisplay("") setInfoDisplay("")
if (!container) return if (!container) return
; (async () => { ;(async () => {
const [logsHtml, infoHtml] = await Promise.all([getLogsHtml(container), getInfoHtml(container)]) const [logsHtml, infoHtml] = await Promise.all([getLogsHtml(container), getInfoHtml(container)])
setLogsDisplay(logsHtml) setLogsDisplay(logsHtml)
setInfoDisplay(infoHtml) setInfoDisplay(infoHtml)
@@ -473,7 +471,7 @@ const ContainerTableRow = memo(function ContainerTableRow({
{row.getVisibleCells().map((cell) => ( {row.getVisibleCells().map((cell) => (
<TableCell <TableCell
key={cell.id} key={cell.id}
className="py-0" className="py-0 ps-4.5"
style={{ style={{
height: virtualRow.size, height: virtualRow.size,
}} }}

View File

@@ -19,7 +19,7 @@ import { FreeBsdIcon, TuxIcon, WebSocketIcon, WindowsIcon } from "@/components/u
import { Separator } from "@/components/ui/separator" import { Separator } from "@/components/ui/separator"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
import { ConnectionType, connectionTypeLabels, Os, SystemStatus } from "@/lib/enums" import { ConnectionType, connectionTypeLabels, Os, SystemStatus } from "@/lib/enums"
import { cn, formatBytes, getHostDisplayValue, secondsToString, toFixedFloat } from "@/lib/utils" import { cn, formatBytes, getHostDisplayValue, secondsToUptimeString, toFixedFloat } from "@/lib/utils"
import type { ChartData, SystemDetailsRecord, SystemRecord } from "@/types" import type { ChartData, SystemDetailsRecord, SystemRecord } from "@/types"
export default function InfoBar({ export default function InfoBar({
@@ -77,14 +77,6 @@ export default function InfoBar({
}, },
} }
let uptime: string
if (system.info.u < 3600) {
uptime = secondsToString(system.info.u, "minute")
} else if (system.info.u < 360000) {
uptime = secondsToString(system.info.u, "hour")
} else {
uptime = secondsToString(system.info.u, "day")
}
const info = [ const info = [
{ value: getHostDisplayValue(system), Icon: GlobeIcon }, { value: getHostDisplayValue(system), Icon: GlobeIcon },
{ {
@@ -94,7 +86,7 @@ export default function InfoBar({
// hide if hostname is same as host or name // hide if hostname is same as host or name
hide: hostname === system.host || hostname === system.name, hide: hostname === system.host || hostname === system.name,
}, },
{ value: uptime, Icon: ClockArrowUp, label: t`Uptime`, hide: !system.info.u }, { value: secondsToUptimeString(system.info.u), Icon: ClockArrowUp, label: t`Uptime`, hide: !system.info.u },
osInfo[os], osInfo[os],
{ {
value: cpuModel, value: cpuModel,

View File

@@ -174,8 +174,8 @@ export const columns: ColumnDef<SmartDeviceRecord>[] = [
<HeaderButton column={column} name={t({ message: "Power On", comment: "Power On Time" })} Icon={Clock} /> <HeaderButton column={column} name={t({ message: "Power On", comment: "Power On Time" })} Icon={Clock} />
), ),
cell: ({ getValue }) => { cell: ({ getValue }) => {
const hours = (getValue() ?? 0) as number const hours = getValue() as number | undefined
if (!hours && hours !== 0) { if (hours == null) {
return <div className="text-sm text-muted-foreground ms-1.5">N/A</div> return <div className="text-sm text-muted-foreground ms-1.5">N/A</div>
} }
const seconds = hours * 3600 const seconds = hours * 3600
@@ -195,7 +195,7 @@ export const columns: ColumnDef<SmartDeviceRecord>[] = [
), ),
cell: ({ getValue }) => { cell: ({ getValue }) => {
const cycles = getValue() as number | undefined const cycles = getValue() as number | undefined
if (!cycles && cycles !== 0) { if (cycles == null) {
return <div className="text-muted-foreground ms-1.5">N/A</div> return <div className="text-muted-foreground ms-1.5">N/A</div>
} }
return <span className="ms-1.5">{cycles.toLocaleString()}</span> return <span className="ms-1.5">{cycles.toLocaleString()}</span>
@@ -206,9 +206,8 @@ export const columns: ColumnDef<SmartDeviceRecord>[] = [
invertSorting: true, invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Temp`} Icon={ThermometerIcon} />, header: ({ column }) => <HeaderButton column={column} name={t`Temp`} Icon={ThermometerIcon} />,
cell: ({ getValue }) => { cell: ({ getValue }) => {
const temp = getValue() as number | undefined | null const temp = getValue() as number | null | undefined
// Most devices won't report a real 0C temperature; treat 0 as "unknown". if (!temp) {
if (temp == null || temp === 0) {
return <div className="text-muted-foreground ms-1.5">N/A</div> return <div className="text-muted-foreground ms-1.5">N/A</div>
} }
const { value, unit } = formatTemperature(temp) const { value, unit } = formatTemperature(temp)
@@ -309,7 +308,7 @@ export default function DisksTable({ systemId }: { systemId?: string }) {
? { fields: SMART_DEVICE_FIELDS, filter: pb.filter("system = {:system}", { system: systemId }) } ? { fields: SMART_DEVICE_FIELDS, filter: pb.filter("system = {:system}", { system: systemId }) }
: { fields: SMART_DEVICE_FIELDS } : { fields: SMART_DEVICE_FIELDS }
; (async () => { ;(async () => {
try { try {
unsubscribe = await pb.collection("smart_devices").subscribe( unsubscribe = await pb.collection("smart_devices").subscribe(
"*", "*",

View File

@@ -35,7 +35,7 @@ import {
formatTemperature, formatTemperature,
getMeterState, getMeterState,
parseSemVer, parseSemVer,
secondsToString, secondsToUptimeString,
} from "@/lib/utils" } from "@/lib/utils"
import { batteryStateTranslations } from "@/lib/i18n" import { batteryStateTranslations } from "@/lib/i18n"
import type { SystemRecord } from "@/types" import type { SystemRecord } from "@/types"
@@ -154,11 +154,7 @@ export function SystemsTableColumns(viewMode: "table" | "grid"): ColumnDef<Syste
{name} {name}
</Link> </Link>
</span> </span>
<Link <Link href={linkUrl} className="inset-0 absolute size-full" aria-label={name}></Link>
href={linkUrl}
className="inset-0 absolute size-full"
aria-label={name}
></Link>
</> </>
) )
}, },
@@ -382,20 +378,13 @@ export function SystemsTableColumns(viewMode: "table" | "grid"): ColumnDef<Syste
size: 50, size: 50,
Icon: ClockArrowUp, Icon: ClockArrowUp,
header: sortableHeader, header: sortableHeader,
hideSort: true,
cell(info) { cell(info) {
const uptime = info.getValue() as number const uptime = info.getValue() as number
if (!uptime) { if (!uptime) {
return null return null
} }
let formatted: string return <span className="tabular-nums whitespace-nowrap">{secondsToUptimeString(uptime)}</span>
if (uptime < 3600) {
formatted = secondsToString(uptime, "minute")
} else if (uptime < 360000) {
formatted = secondsToString(uptime, "hour")
} else {
formatted = secondsToString(uptime, "day")
}
return <span className="tabular-nums whitespace-nowrap">{formatted}</span>
}, },
}, },
{ {

View File

@@ -434,7 +434,7 @@ const SystemTableRow = memo(
width: cell.column.getSize(), width: cell.column.getSize(),
height: virtualRow.size, height: virtualRow.size,
}} }}
className="py-0" className="py-0 ps-4.5"
> >
{flexRender(cell.column.columnDef.cell, cell.getContext())} {flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell> </TableCell>

View File

@@ -466,3 +466,14 @@ export function secondsToString(seconds: number, unit: "hour" | "minute" | "day"
return plural(count, { one: `${countString} day`, other: `${countString} days` }) return plural(count, { one: `${countString} day`, other: `${countString} days` })
} }
} }
/** Format seconds to uptime string - "X minutes", "X hours", "X days" */
export function secondsToUptimeString(seconds: number): string {
if (seconds < 3600) {
return secondsToString(seconds, "minute")
} else if (seconds < 360000) {
return secondsToString(seconds, "hour")
} else {
return secondsToString(seconds, "day")
}
}