From 5b0952ffcf0b3cf0a8f975e2fa396db679a0dab7 Mon Sep 17 00:00:00 2001 From: henrygd Date: Wed, 30 Sep 2026 21:25:16 -0400 Subject: [PATCH] ui: persist log timestamp toggle and add tooltips to log buttons --- .../containers-table/containers-table.tsx | 24 ++--- internal/site/src/components/logs-display.tsx | 88 +++++++++++-------- .../systemd-table/systemd-table.tsx | 33 ++----- internal/site/src/lib/stores.ts | 11 +++ 4 files changed, 76 insertions(+), 80 deletions(-) diff --git a/internal/site/src/components/containers-table/containers-table.tsx b/internal/site/src/components/containers-table/containers-table.tsx index 8b3f10132..a8f8b21f8 100644 --- a/internal/site/src/components/containers-table/containers-table.tsx +++ b/internal/site/src/components/containers-table/containers-table.tsx @@ -32,7 +32,7 @@ import { Separator } from "../ui/separator" import { $router, Link } from "../router" import { listenKeys } from "nanostores" import { getPagePath } from "@nanostores/router" -import { LogsDisplay, LogsFullscreenDialog, LogsTimestampToggle } from "@/components/logs-display" +import { LogsDisplay, LogsFullscreenDialog, LogsIconButton, LogsTimestampToggle } from "@/components/logs-display" import { getLogTimestampDecorations } from "@/lib/logs" const syntaxTheme = "github-dark-dimmed" @@ -325,8 +325,6 @@ function ContainerSheet({ activeContainer: RefObject }) { const [logsDisplay, setLogsDisplay] = useState("") - const [showTimestamps, setShowTimestamps] = useState(false) - const toggleTimestamps = () => setShowTimestamps((shown) => !shown) const [infoDisplay, setInfoDisplay] = useState("") const [logsFullscreenOpen, setLogsFullscreenOpen] = useState(false) const [infoFullscreenOpen, setInfoFullscreenOpen] = useState(false) @@ -385,8 +383,6 @@ function ContainerSheet({ name={container.name} onRefresh={refreshLogs} isRefreshing={isRefreshingLogs} - showTimestamps={showTimestamps} - onToggleTimestamps={toggleTimestamps} />

{t`Logs`}

- - - +
- +

{t`Detail`}

+ ) } // Shared by Docker and systemd service sheets so logs behave identically. -export function LogsDisplay({ logsDisplay, containerRef, showTimestamps = true }: LogsDisplayProps) { +export function LogsDisplay({ logsDisplay, containerRef }: LogsDisplayProps) { + const showTimestamps = useStore($showLogTimestamps) return (
void @@ -68,9 +81,8 @@ export function LogsFullscreenDialog({ name: string onRefresh: () => void | Promise isRefreshing: boolean - showTimestamps: boolean - onToggleTimestamps: () => void }) { + const showTimestamps = useStore($showLogTimestamps) const outerContainerRef = useRef(null) useEffect(() => { @@ -97,20 +109,22 @@ export function LogsFullscreenDialog({
- - + + + + + + {t`Refresh`} + ) diff --git a/internal/site/src/components/systemd-table/systemd-table.tsx b/internal/site/src/components/systemd-table/systemd-table.tsx index 6ea4f3b39..6197f5a66 100644 --- a/internal/site/src/components/systemd-table/systemd-table.tsx +++ b/internal/site/src/components/systemd-table/systemd-table.tsx @@ -19,9 +19,8 @@ import { memo, type ReactNode, useEffect, useMemo, useRef, useState } from "reac import { getStatusColor, systemdTableCols } from "@/components/systemd-table/systemd-table-columns" import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import { Card, CardHeader, CardTitle } from "@/components/ui/card" -import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" -import { LogsDisplay, LogsFullscreenDialog, LogsTimestampToggle } from "@/components/logs-display" +import { LogsDisplay, LogsFullscreenDialog, LogsIconButton, LogsTimestampToggle } from "@/components/logs-display" import { getLogTimestampDecorations } from "@/lib/logs" import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet" import { TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" @@ -297,8 +296,6 @@ function SystemdSheet({ const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const [logs, setLogs] = useState("") - const [showTimestamps, setShowTimestamps] = useState(true) - const toggleTimestamps = () => setShowTimestamps((shown) => !shown) const [logsStatus, setLogsStatus] = useState<"loading" | "ready" | "empty" | "error">("loading") const [isLoadingLogs, setIsLoadingLogs] = useState(false) const [logsFullscreenOpen, setLogsFullscreenOpen] = useState(false) @@ -520,8 +517,6 @@ function SystemdSheet({ name={service.name} onRefresh={loadLogs} isRefreshing={isLoadingLogs} - showTimestamps={showTimestamps} - onToggleTimestamps={toggleTimestamps} /> @@ -537,32 +532,18 @@ function SystemdSheet({

Logs

- - - +
{logs ? ( - + ) : logsStatus === "loading" ? ( <>
diff --git a/internal/site/src/lib/stores.ts b/internal/site/src/lib/stores.ts index eb0e304c0..58ba1d607 100644 --- a/internal/site/src/lib/stores.ts +++ b/internal/site/src/lib/stores.ts @@ -40,6 +40,17 @@ export const $chartTime = atom(defaultChartTime) /** Whether to display average or max chart values */ export const $maxValues = atom(false) +const logTimestampsKey = "besz-log-ts" + +/** Whether to show timestamps in Docker and systemd logs */ +export const $showLogTimestamps = atom(JSON.parse(localStorage.getItem(logTimestampsKey) ?? "true")) + +export function toggleLogTimestamps() { + const next = !$showLogTimestamps.get() + $showLogTimestamps.set(next) + localStorage.setItem(logTimestampsKey, JSON.stringify(next)) +} + // export const UserSettingsSchema = v.object({ // chartTime: v.picklist(["1h", "12h", "24h", "1w", "30d"]), // emails: v.optional(v.array(v.pipe(v.string(), v.email())), [pb?.authStore?.record?.email ?? ""]),