Files
model-platform/frontend/app/features/platform/DashboardRoute.tsx
T
tao.chenandtao.chen c6ac886133 feat(scripts): GET /api/v1/scripts/count + DashboardRoute wiring
After #34 the workspace store only holds the root-level scripts plus
whatever subfolders the user has expanded. DashboardRoute's
"全部脚本"/"工作副本" counts derived from scripts.length therefore
underreport the workspace total until the user navigates to /scripts
and expands every folder.

Fix: separate count endpoint + dedicated store field, mounted
independently.

Backend — backend/src/backend/scripts.py
- New endpoint GET /api/v1/scripts/count.
- Route declared BEFORE /api/v1/scripts/{script_id}/... so FastAPI's
  declaration-order matching does not interpret "count" as a script_id.
- Returns { data: { total: number }, meta: {} }; SQL is a single
  COUNT(*) on scripts filtered by workspace_id + status='active'.

Frontend — services/api.ts + context/AuthContext.tsx
- countScripts(workspaceId) client; WorkspaceBoundApi gains the field;
  AuthContext binding forwards workspaceId.

Frontend — state/scriptWorkspaceStore.ts
- scriptCount: number | null, scriptCountLoading: boolean.
- loadScriptCount() action: idempotent (no-op while in-flight), silent
  on failure (dashboard tolerates a stale count).
- Initial state and reset() clear both fields.

Frontend — features/platform/DashboardRoute.tsx
- Subscribes to scriptCount; calls loadScriptCount() on mount.
- Falls back to scripts.length until the count resolves so the
  dashboard never blanks.

Tests — backend/tests/test_count_scripts.py (new)
- 3 unit tests: scalar result handling, NULL coercion, route callable.

Verified: pytest 55 passed (52 + 3 new); pnpm typecheck clean.
2026-09-02 10:10:41 +08:00

32 lines
1.1 KiB
TypeScript

import { useEffect } from "react";
import { useNavigate } from "react-router";
import { DashboardPage } from "../../components/admin/DashboardPage";
import { useScriptWorkspaceStore } from "./state/scriptWorkspaceStore";
export default function DashboardRoute() {
const scripts = useScriptWorkspaceStore((s) => s.scripts);
const scriptCount = useScriptWorkspaceStore((s) => s.scriptCount);
const loadScriptCount = useScriptWorkspaceStore((s) => s.loadScriptCount);
const apiOnline = useScriptWorkspaceStore((s) => s.apiOnline);
const navigate = useNavigate();
// Independent of the lazy-loaded `scripts` array — the count endpoint
// returns the workspace-wide total even when no folders have been
// expanded yet (see #34 + #37).
useEffect(() => {
void loadScriptCount();
}, [loadScriptCount]);
return (
<DashboardPage
scriptCount={scriptCount ?? scripts.length}
online={apiOnline}
onNavigate={(page) => {
if (page === "scripts") navigate("/scripts");
else if (page === "schedules") navigate("/schedules");
else navigate("/system");
}}
/>
);
}