diff --git a/packages/web_ui/src/components/InstanceViewPage.tsx b/packages/web_ui/src/components/InstanceViewPage.tsx index 06cb11b7..e83e206d 100644 --- a/packages/web_ui/src/components/InstanceViewPage.tsx +++ b/packages/web_ui/src/components/InstanceViewPage.tsx @@ -25,11 +25,15 @@ import { useHost } from "../model/host"; import InstanceStatusTag from "./InstanceStatusTag"; import Link from "./Link"; import { instancePublicAddress } from "../util/instance"; +import useLocalStorage from "../util/useLocalStorage"; import { MetricRelativeDate } from "./system_metrics"; type MenuItem = Required["items"][number]; const { Title } = Typography; +// Remembers the console "Chat/Log" toggle across reloads (defaults to on). +const consoleActionsOnlyKey = "instance-console-actions-only"; + type InstanceDescriptionProps = { host?: Readonly; instance: Readonly; @@ -177,7 +181,7 @@ export default function InstanceViewPage() { let params = useParams(); let instanceId = Number(params.id); const [maxLevel, setMaxLevel] = useState("server"); - const [actionsOnly, setActionsOnly] = useState(true); + const [actionsOnly, setActionsOnly] = useLocalStorage(consoleActionsOnlyKey, true); let navigate = useNavigate(); diff --git a/packages/web_ui/src/util/useLocalStorage.ts b/packages/web_ui/src/util/useLocalStorage.ts new file mode 100644 index 00000000..26a59cd9 --- /dev/null +++ b/packages/web_ui/src/util/useLocalStorage.ts @@ -0,0 +1,33 @@ +import { useState } from "react"; + +/** + * Persist a JSON-serialisable value in localStorage. Behaves like useState, but + * seeds the initial value from localStorage and writes changes back. The write + * is deferred to a later task so it never blocks the state update / re-render. + */ +export default function useLocalStorage(key: string, defaultValue: T): [T, (value: T) => void] { + const [value, setValue] = useState(() => { + const stored = localStorage.getItem(key); + if (stored === null) { + return defaultValue; + } + try { + return JSON.parse(stored) as T; + } catch { + return defaultValue; + } + }); + + function set(next: T) { + setValue(next); + setTimeout(() => { + try { + localStorage.setItem(key, JSON.stringify(next)); + } catch { + // Ignore storage errors (e.g. quota exceeded or storage disabled). + } + }, 0); + } + + return [value, set]; +}