diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 026b2505..b29dfc4d 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -1,4 +1,5 @@ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useId, useMemo, useRef, useState } from "react"; +import { niceCeiling, normalizeStats, windowLabel, type UsageDay } from "./usage-stats.js"; import type { AgentId, @@ -15,7 +16,18 @@ import OPENCLAW_ICON from "./openclaw-x-avatar.jpg"; type Page = "overview" | "models" | "usage" | "wallet" | "settings"; type Theme = "dark" | "light"; type IconName = - "home" | "models" | "usage" | "settings" | "refresh" | "sun" | "moon" | "external" | "wallet"; + | "home" + | "models" + | "usage" + | "settings" + | "refresh" + | "sun" + | "moon" + | "external" + | "wallet" + | "copy" + | "plus" + | "check"; type CatalogModel = ModelInfo & { aliases: string[] }; const CLAWROUTER_REPO = "https://github.com/BlockRunAI/ClawRouter"; @@ -38,12 +50,15 @@ export function App() { const [fundingAmount, setFundingAmount] = useState(50); const [fundingBusy, setFundingBusy] = useState(false); const [notice, setNotice] = useState<{ kind: "ok" | "error"; text: string } | null>(null); + const [refreshSpin, setRefreshSpin] = useState(false); const [theme, setTheme] = useState(() => { const saved = window.localStorage.getItem("clawrouter-theme"); if (saved === "light" || saved === "dark") return saved; return window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"; }); + const reportError = (text: string) => setNotice({ kind: "error", text }); + async function refresh() { await Promise.allSettled([ api.statuses().then(setAgents), @@ -155,6 +170,7 @@ export function App() {