diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index a90bc08..b982bc9 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -1,4 +1,4 @@ -import { useQuery } from "@tanstack/react-query"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { Shield, @@ -15,6 +15,7 @@ import { Users, TrendingUp, ArrowRight, + RefreshCw, } from "lucide-react"; import { LineChart, @@ -87,29 +88,48 @@ export default function DashboardPage() { queryFn: getCoverageByTactic, }); - // V2 queries — retry:2 so transient failures don't leave widgets blank - const { data: pipeline, isLoading: pipelineLoading, isError: pipelineError } = useQuery({ + const queryClient = useQueryClient(); + + // Refresh all V2 metric widgets manually + const refreshMetrics = () => { + queryClient.invalidateQueries({ queryKey: ["metrics", "test-pipeline"] }); + queryClient.invalidateQueries({ queryKey: ["metrics", "team-activity"] }); + queryClient.invalidateQueries({ queryKey: ["metrics", "validation-rate"] }); + queryClient.invalidateQueries({ queryKey: ["metrics", "recent-tests"] }); + }; + + // V2 queries — retry:3 + refetchOnMount:'always' so queries re-run even + // when cached in error state (happens if backend was still starting on first load) + const { data: pipeline, isLoading: pipelineLoading, isError: pipelineError, isFetching: pipelineFetching } = useQuery({ queryKey: ["metrics", "test-pipeline"], queryFn: getTestPipeline, - retry: 2, + retry: 3, + refetchOnMount: "always", + gcTime: 0, }); const { data: teamActivity, isLoading: teamLoading, isError: teamError } = useQuery({ queryKey: ["metrics", "team-activity"], queryFn: getTeamActivity, - retry: 2, + retry: 3, + refetchOnMount: "always", + gcTime: 0, }); const { data: validationRates, isLoading: validationLoading, isError: validationError } = useQuery({ queryKey: ["metrics", "validation-rate"], queryFn: getValidationRate, - retry: 2, + retry: 3, + refetchOnMount: "always", + gcTime: 0, }); const { data: recentTests, isLoading: recentLoading, isError: recentError } = useQuery({ queryKey: ["metrics", "recent-tests"], queryFn: getRecentTests, - retry: 2, + retry: 3, + refetchOnMount: "always", + gcTime: 0, }); const { data: coverageEvolution, isLoading: evolutionLoading } = useQuery({ @@ -147,7 +167,18 @@ export default function DashboardPage() { MITRE ATT&CK coverage overview

- {summary && ( +
+ {/* Manual refresh for metric widgets */} + + {summary && (
@@ -155,7 +186,8 @@ export default function DashboardPage() { Coverage
- )} + )} +
{/* Summary Cards */}