diff --git a/src/lib/queryClient.ts b/src/lib/queryClient.ts index 25c0b99e..a2bbb31d 100644 --- a/src/lib/queryClient.ts +++ b/src/lib/queryClient.ts @@ -9,6 +9,14 @@ const API_BASE_URL = (ENV_API_BASE_URL || (IS_LOCALHOST ? "http://localhost:8000 .replace(/\/api$/, ""); const REQUEST_TIMEOUT_MS = 12000; +function truncateText(value: string, maxLength = 180) { + return value.length > maxLength ? `${value.slice(0, maxLength - 3)}...` : value; +} + +function looksLikeHtml(value: string) { + return /]|
]|]/i.test(value); +} + function normalizeApiPath(url: string) { const parsed = new URL(url, "https://frontend.local"); const pathname = parsed.pathname.startsWith("/api") @@ -29,10 +37,60 @@ export function resolveApiUrl(url: string) { return `${API_BASE_URL}${normalizedPath}`; } +async function getResponseErrorMessage(res: Response) { + const contentType = res.headers.get("content-type") || ""; + + if (contentType.includes("application/json")) { + try { + const data = await res.json(); + const detail = + (typeof data?.detail === "string" && data.detail) || + (typeof data?.message === "string" && data.message) || + (typeof data?.error === "string" && data.error); + if (detail) { + return `${res.status}: ${detail}`; + } + } catch { + // Fall back to response text below. + } + } + + const text = ((await res.text()) || res.statusText).trim(); + if (!text) { + return `${res.status}: ${res.statusText}`; + } + if (looksLikeHtml(text)) { + return `${res.status}: Unexpected HTML response from the API. Check backend routing or deployment config.`; + } + + return `${res.status}: ${truncateText(text.replace(/\s+/g, " "))}`; +} + async function throwIfResNotOk(res: Response) { if (!res.ok) { - const text = (await res.text()) || res.statusText; - throw new Error(`${res.status}: ${text}`); + throw new Error(await getResponseErrorMessage(res)); + } +} + +async function throwIfUnexpectedApiPayload(res: Response) { + if (res.status === 204) { + return; + } + + const contentType = (res.headers.get("content-type") || "").toLowerCase(); + if (contentType.includes("application/json")) { + return; + } + + const body = (await res.clone().text()).trim(); + if (!body) { + return; + } + if (body.startsWith("{") || body.startsWith("[")) { + return; + } + if (looksLikeHtml(body)) { + throw new Error("Unexpected HTML response from the API. Check backend routing or deployment config."); } } @@ -62,12 +120,16 @@ export async function apiRequest( ): Promise{key}
- {value} + {String(value)}
))} diff --git a/src/pages/admin/AdminOverview.tsx b/src/pages/admin/AdminOverview.tsx index 23bd5b6e..ed53745a 100644 --- a/src/pages/admin/AdminOverview.tsx +++ b/src/pages/admin/AdminOverview.tsx @@ -21,7 +21,17 @@ export default function AdminOverview() { }); if (overviewQuery.isLoading) { - returnRun Status
-Activity (last 24h)
-Latest Errors
{data.top_errors.length === 0 ? ( -No recent errors.
+No recent errors.
) : (- {err.source} • {err.user_id ?? "unknown"} • {err.run_id ?? "n/a"} + {err.source} | {err.user_id ?? "unknown"} | {err.run_id ?? "n/a"}
{err.message ?? "No message"}
User: {run.user_id}
@@ -38,17 +46,17 @@ export default function AdminRunDetail({ runId }: { runId: string }) {Metadata
Status: {run.status}
-Mode: {run.mode ?? "—"}
-Strategy: {run.strategy ?? "—"}
-Started: {run.started_at ?? "—"}
-Last event: {run.last_event_time ?? "—"}
+Mode: {run.mode ?? "-"}
+Strategy: {run.strategy ?? "-"}
+Started: {run.started_at ?? "-"}
+Last event: {run.last_event_time ?? "-"}
Engine Status
Status: {engine_status?.status ?? "—"}
-Updated: {engine_status?.last_updated ?? "—"}
+Status: {engine_status?.status ?? "-"}
+Updated: {engine_status?.last_updated ?? "-"}
Config
-
+
{JSON.stringify(config, null, 2)}
State Snapshot
-
+
{JSON.stringify(state_snapshot, null, 2)}
Orders
-| ID | @@ -119,7 +125,7 @@ export default function AdminRunDetail({ runId }: { runId: string }) {
|---|
| ID | diff --git a/src/pages/admin/AdminRuns.tsx b/src/pages/admin/AdminRuns.tsx index 7adc2b25..3aeb4d82 100644 --- a/src/pages/admin/AdminRuns.tsx +++ b/src/pages/admin/AdminRuns.tsx @@ -32,7 +32,15 @@ export default function AdminRuns() { }); if (runsQuery.isLoading) { - return{run.user_id} | {run.status} | -{run.mode ?? "—"} | +{run.mode ?? "-"} | {run.order_count} | {run.trade_count} |
|---|