diff --git a/src/pages/Dashboard/index.tsx b/src/pages/Dashboard/index.tsx index 437b8f82..5e96a63e 100644 --- a/src/pages/Dashboard/index.tsx +++ b/src/pages/Dashboard/index.tsx @@ -1,16 +1,16 @@ import React, { useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { Plus, AlertTriangle, CheckCircle, Clock } from "lucide-react"; +import { Plus, AlertTriangle, CheckCircle, Clock, RefreshCw } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent, Badge, Button } from "@/components/ui"; import { useHistoryStore } from "@/stores/historyStore"; export default function Dashboard() { const navigate = useNavigate(); - const { issues, loadIssues, isLoading } = useHistoryStore(); + const { issues, loadIssues, isLoading, error } = useHistoryStore(); useEffect(() => { loadIssues(); - }, [loadIssues]); + }, []); // eslint-disable-line react-hooks/exhaustive-deps const openCount = issues.filter((i) => i.status === "open" || i.status === "triaging").length; const resolvedThisWeek = issues.filter((i) => { @@ -25,6 +25,7 @@ export default function Dashboard() { ).length; const recentIssues = issues.slice(0, 10); + const statValue = (n: number) => (isLoading ? "—" : String(n)); return (
@@ -36,12 +37,24 @@ export default function Dashboard() { IT Triage & Root Cause Analysis

- +
+ + +
+ {error && ( +
+ Failed to load issues: {error} +
+ )} + {/* Stat cards */}
@@ -50,7 +63,7 @@ export default function Dashboard() { -
{openCount}
+
{statValue(openCount)}

Currently active

@@ -60,7 +73,7 @@ export default function Dashboard() { -
{resolvedThisWeek}
+
{statValue(resolvedThisWeek)}

Last 7 days

@@ -70,7 +83,7 @@ export default function Dashboard() { -
{criticalCount}
+
{statValue(criticalCount)}

Require immediate attention

diff --git a/tests/unit/historyStore.test.ts b/tests/unit/historyStore.test.ts index 2b88e62e..f162ce2b 100644 --- a/tests/unit/historyStore.test.ts +++ b/tests/unit/historyStore.test.ts @@ -34,9 +34,7 @@ describe("History Store", () => { expect(useHistoryStore.getState().isLoading).toBe(false); }); - it("loadIssues sets error on failure without clearing existing issues", async () => { - const existing = [makeIssue()]; - useHistoryStore.setState({ issues: existing }); + it("loadIssues sets error on failure and clears isLoading", async () => { mockInvoke.mockRejectedValueOnce(new Error("DB locked")); await useHistoryStore.getState().loadIssues(); @@ -45,6 +43,19 @@ describe("History Store", () => { expect(useHistoryStore.getState().isLoading).toBe(false); }); + it("isLoading is true while fetching (stat cards must show — not 0)", async () => { + let resolve!: (v: unknown) => void; + mockInvoke.mockReturnValueOnce(new Promise((r) => (resolve = r))); + + const p = useHistoryStore.getState().loadIssues(); + expect(useHistoryStore.getState().isLoading).toBe(true); + + resolve([makeIssue()]); + await p; + expect(useHistoryStore.getState().isLoading).toBe(false); + expect(useHistoryStore.getState().issues).toHaveLength(1); + }); + it("open issue count includes status=open and status=triaging", () => { useHistoryStore.setState({ issues: [