speed up admin ui polling and payloads

This commit is contained in:
2026-06-29 20:20:19 +08:00
parent 2db86643c8
commit ab0572baf6
2 changed files with 89 additions and 29 deletions
+79 -26
View File
@@ -1,4 +1,4 @@
import { FormEvent, useEffect, useState } from "react";
import { FormEvent, startTransition, useEffect, useState } from "react";
type PageKey = "overview" | "requests" | "profiles" | "rules" | "logs";
type Tone = "" | "success" | "error";
@@ -222,6 +222,20 @@ const api = {
restore: "/__codex_retry_gateway/api/restore",
};
const REQUEST_PAGE_SIZE = 40;
const LOG_PAGE_SIZE = 200;
const zhNumberFormatter = new Intl.NumberFormat("zh-CN");
const zhTimestampFormatter = new Intl.DateTimeFormat("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: "h23",
});
type ProfileProbePayload = {
ok: boolean;
profile?: string;
@@ -294,7 +308,7 @@ const defaultProfileForm: ProfileFormState = {
function numberFormat(value: unknown) {
return typeof value === "number" && Number.isFinite(value)
? new Intl.NumberFormat("zh-CN").format(value)
? zhNumberFormatter.format(value)
: "-";
}
@@ -303,7 +317,7 @@ function timestamp(value?: string | null) {
return "-";
}
const date = new Date(value);
return Number.isNaN(date.getTime()) ? value : date.toLocaleString("zh-CN", { hour12: false });
return Number.isNaN(date.getTime()) ? value : zhTimestampFormatter.format(date);
}
function durationSeconds(value?: number | null) {
@@ -482,6 +496,7 @@ export default function App() {
});
const [status, setStatus] = useState<StatusPayload | null>(null);
const [requests, setRequests] = useState<RequestEntry[]>([]);
const [requestsTotal, setRequestsTotal] = useState(0);
const [requestsMeta, setRequestsMeta] = useState("正在读取请求记录...");
const [profiles, setProfiles] = useState<Profile[]>([]);
const [profilesMeta, setProfilesMeta] = useState("正在读取 profiles...");
@@ -490,6 +505,7 @@ export default function App() {
const [latestLogSeq, setLatestLogSeq] = useState(0);
const [requestQuery, setRequestQuery] = useState("");
const [requestFilter, setRequestFilter] = useState("all");
const [requestLimit, setRequestLimit] = useState(REQUEST_PAGE_SIZE);
const [ruleForm, setRuleForm] = useState<RuleFormState>(ruleFormFromStatus(null));
const [profileForm, setProfileForm] = useState<ProfileFormState>(defaultProfileForm);
const [ruleMessage, setRuleMessage] = useState<MessageState>({ text: "", tone: "" });
@@ -513,16 +529,18 @@ export default function App() {
async function loadStatus(refreshRuleForm = false) {
const payload = await fetchJson<StatusPayload>(api.status);
setStatus(payload);
if (refreshRuleForm) {
setRuleForm(ruleFormFromStatus(payload));
setProfileForm(profileFormFromStatus(payload));
}
startTransition(() => {
setStatus(payload);
if (refreshRuleForm) {
setRuleForm(ruleFormFromStatus(payload));
setProfileForm(profileFormFromStatus(payload));
}
});
}
async function loadRequests() {
async function loadRequests(limitOverride = requestLimit) {
const url = new URL(api.requests, window.location.origin);
url.searchParams.set("limit", "100");
url.searchParams.set("limit", String(limitOverride));
if (requestQuery.trim()) {
url.searchParams.set("query", requestQuery.trim());
}
@@ -531,36 +549,47 @@ export default function App() {
}
const payload = await fetchJson<RequestsPayload>(url.toString());
const entries = payload.entries || [];
setRequests(entries);
setRequestsMeta(`查询命中 ${payload.total_entries ?? entries.length} 条,最新序号 ${payload.latest_seq ?? 0}`);
startTransition(() => {
setRequests(entries);
setRequestsTotal(payload.total_entries ?? entries.length);
setRequestsMeta(
`查询命中 ${payload.total_entries ?? entries.length} 条,当前展示最近 ${entries.length} 条,最新序号 ${payload.latest_seq ?? 0}`,
);
});
}
async function loadProfiles() {
const payload = await fetchJson<ProfilesPayload>(api.profiles);
const items = payload.profiles || [];
setProfiles(items);
setProfilesMeta(`目录:${payload.profiles_dir || "-"};当前运行:${payload.active_profile || "-"}`);
startTransition(() => {
setProfiles(items);
setProfilesMeta(`目录:${payload.profiles_dir || "-"};当前运行:${payload.active_profile || "-"}`);
});
}
async function loadLogs(incremental = false) {
const url = new URL(api.logs, window.location.origin);
if (incremental && latestLogSeq > 0) {
url.searchParams.set("since_seq", String(latestLogSeq));
} else {
url.searchParams.set("limit", String(LOG_PAGE_SIZE));
}
const payload = await fetchJson<LogsPayload>(url.toString());
const rendered = (payload.entries || [])
.map((entry) => `${entry.at || "-"} ${entry.message || ""}`)
.join("\n");
setLogs((current) => {
if (!incremental || latestLogSeq === 0) {
return rendered || "当前还没有日志。";
startTransition(() => {
setLogs((current) => {
if (!incremental || latestLogSeq === 0) {
return rendered || "当前还没有日志。";
}
return rendered ? `${current.trim()}\n${rendered}` : current;
});
setLogsMeta(`已载入 ${payload.total_entries ?? payload.entries?.length ?? 0} 条日志,最新序号 ${payload.latest_seq ?? latestLogSeq}`);
if (typeof payload.latest_seq === "number") {
setLatestLogSeq(payload.latest_seq);
}
return rendered ? `${current.trim()}\n${rendered}` : current;
});
setLogsMeta(`已载入 ${payload.total_entries ?? payload.entries?.length ?? 0} 条日志,最新序号 ${payload.latest_seq ?? latestLogSeq}`);
if (typeof payload.latest_seq === "number") {
setLatestLogSeq(payload.latest_seq);
}
}
async function loadPageData(targetPage: PageKey, { incrementalLogs = true } = {}) {
@@ -617,12 +646,24 @@ export default function App() {
useEffect(() => {
const timer = window.setInterval(() => {
refreshLiveData().catch((error) => {
loadStatus(false).catch((error) => {
setRuleMessage({ text: error?.message || String(error), tone: "error" });
});
}, 10000);
return () => window.clearInterval(timer);
}, [restoreRequested, switchingTo]);
useEffect(() => {
if (page !== "requests" && page !== "logs") {
return;
}
const timer = window.setInterval(() => {
loadPageData(page, { incrementalLogs: true }).catch((error) => {
setRuleMessage({ text: error?.message || String(error), tone: "error" });
});
}, 2500);
return () => window.clearInterval(timer);
}, [page, requestQuery, requestFilter, latestLogSeq, restoreRequested, switchingTo]);
}, [page, requestQuery, requestFilter, latestLogSeq, requestLimit]);
useEffect(() => {
if (page === "overview" || page === "rules") {
@@ -676,17 +717,21 @@ export default function App() {
}
}
useEffect(() => {
setRequestLimit(REQUEST_PAGE_SIZE);
}, [requestQuery, requestFilter]);
useEffect(() => {
if (page !== "requests") {
return;
}
const timer = window.setTimeout(() => {
loadRequests().catch((error) => {
loadRequests(requestLimit).catch((error) => {
setRuleMessage({ text: error?.message || String(error), tone: "error" });
});
}, 180);
return () => window.clearTimeout(timer);
}, [page, requestQuery, requestFilter]);
}, [page, requestQuery, requestFilter, requestLimit]);
async function saveProfile(event: FormEvent) {
event.preventDefault();
@@ -987,6 +1032,14 @@ export default function App() {
<button className="secondary" type="button" onClick={() => loadRequests()}>
</button>
<button
className="ghost"
type="button"
disabled={requests.length >= requestsTotal && requestsTotal > 0}
onClick={() => setRequestLimit((current) => current + REQUEST_PAGE_SIZE)}
>
</button>
</div>
}
>