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: [