diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8de2a4d..78ef499 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -18,6 +18,7 @@ const TestsPage = React.lazy(() => import("./pages/TestsPage")); const TestCreatePage = React.lazy(() => import("./pages/TestCreatePage")); const TestDetailPage = React.lazy(() => import("./pages/TestDetailPage")); const TestCatalogPage = React.lazy(() => import("./pages/TestCatalogPage")); +const ValidatedTestsPage = React.lazy(() => import("./pages/ValidatedTestsPage")); const ReportsPage = React.lazy(() => import("./pages/ReportsPage")); const SystemPage = React.lazy(() => import("./pages/SystemPage")); const UsersPage = React.lazy(() => import("./pages/UsersPage")); @@ -65,6 +66,7 @@ export default function App() { {/* ── Tests ────────────────────────────────────────────── */} }>} /> }>} /> + }>} /> }>} /> }>} /> }>} /> diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 6e38e7f..499519b 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -10,7 +10,7 @@ import { FileText, ChevronDown, ListChecks, - ClipboardList, + CheckCircle, Database, Crosshair, Zap, @@ -41,7 +41,7 @@ const mainLinks: NavItem[] = [ icon: FlaskConical, children: [ { to: "/tests", label: "All Tests", icon: ListChecks }, - { to: "/tests?view=pending", label: "My Pending Tasks", icon: ClipboardList }, + { to: "/tests/validated", label: "Validated Tests", icon: CheckCircle }, { to: "/test-catalog", label: "Test Catalog", icon: BookOpen }, ], }, diff --git a/frontend/src/pages/TestsPage.tsx b/frontend/src/pages/TestsPage.tsx index 13e2626..805bfbd 100644 --- a/frontend/src/pages/TestsPage.tsx +++ b/frontend/src/pages/TestsPage.tsx @@ -103,9 +103,6 @@ export default function TestsPage() { const [searchText, setSearchText] = useState(""); const [showMyTasks, setShowMyTasks] = useState(false); - // ── Validated section toggle ────────────────────────────────────── - const [showValidated, setShowValidated] = useState(false); - // ── Sort state ──────────────────────────────────────────────────── type SortKey = | "name" @@ -124,7 +121,6 @@ export default function TestsPage() { setSortDir((d) => (d === "asc" ? "desc" : "asc")); } else { setSortKey(key); - // For waiting_time, default to asc (oldest = most urgent first) setSortDir(key === "waiting_time" ? "asc" : "asc"); } }; @@ -169,12 +165,6 @@ export default function TestsPage() { queryFn: () => getTests(filters), }); - // Dedicated query for validated tests (shown in separate section) - const { data: validatedTests } = useQuery({ - queryKey: ["tests", "validated"], - queryFn: () => getTests({ state: "validated", limit: 200 }), - }); - // Client-side filtering const tests = useMemo(() => { if (!allTests) return []; @@ -187,8 +177,7 @@ export default function TestsPage() { ); } - // Exclude validated from the main active-tests table - // (unless the user explicitly chose to filter by validated) + // Exclude validated from this table — they live in /tests/validated if (stateFilter !== "validated") { filtered = filtered.filter((t) => t.state !== "validated"); } @@ -239,14 +228,12 @@ export default function TestsPage() { bv = b.updated_at || ""; break; case "waiting_time": { - // Both blue_evaluating: oldest updated_at = longest wait const aIsBlue = a.state === "blue_evaluating"; const bIsBlue = b.state === "blue_evaluating"; if (aIsBlue && bIsBlue) { av = a.updated_at || ""; bv = b.updated_at || ""; } else { - // Blue_evaluating entries come first when sorting by wait if (aIsBlue && !bIsBlue) return sortDir === "asc" ? -1 : 1; if (!aIsBlue && bIsBlue) return sortDir === "asc" ? 1 : -1; av = a.updated_at || ""; @@ -263,18 +250,6 @@ export default function TestsPage() { }, [allTests, searchText, showMyTasks, user, stateFilter, sortKey, sortDir]); // ── State counters ──────────────────────────────────────────────── - const stateCounts = useMemo(() => { - const counts: Record = {}; - for (const s of ALL_STATES) counts[s] = 0; - if (allTests) { - for (const t of allTests) { - counts[t.state] = (counts[t.state] || 0) + 1; - } - } - return counts; - }, [allTests]); - - // Count from unfiltered query for the top cards const { data: allTestsUnfiltered } = useQuery({ queryKey: ["tests", "unfiltered-counts"], queryFn: () => getTests({ limit: 200 }), @@ -296,7 +271,8 @@ export default function TestsPage() { // ── Formatting helpers ───────────────────────────────────────────── const formatDate = (dateStr: string | null | undefined) => { if (!dateStr) return "-"; - const utc = dateStr.endsWith("Z") || dateStr.includes("+") ? dateStr : dateStr + "Z"; + const utc = + dateStr.endsWith("Z") || dateStr.includes("+") ? dateStr : dateStr + "Z"; return new Date(utc).toLocaleDateString("es-ES", { year: "numeric", month: "short", @@ -321,35 +297,6 @@ export default function TestsPage() { } }, [user]); - // ── Validated sort helpers ───────────────────────────────────────── - const [valSortKey, setValSortKey] = useState<"name" | "technique" | "created_at" | "updated_at">("updated_at"); - const [valSortDir, setValSortDir] = useState<"asc" | "desc">("desc"); - - const sortedValidatedTests = useMemo(() => { - if (!validatedTests) return []; - return [...validatedTests].sort((a, b) => { - let av = ""; - let bv = ""; - switch (valSortKey) { - case "name": av = a.name.toLowerCase(); bv = b.name.toLowerCase(); break; - case "technique": av = (a.technique_mitre_id || "").toLowerCase(); bv = (b.technique_mitre_id || "").toLowerCase(); break; - case "created_at": av = a.created_at || ""; bv = b.created_at || ""; break; - case "updated_at": av = a.updated_at || ""; bv = b.updated_at || ""; break; - } - const cmp = av < bv ? -1 : av > bv ? 1 : 0; - return valSortDir === "asc" ? cmp : -cmp; - }); - }, [validatedTests, valSortKey, valSortDir]); - - const handleValSort = (key: typeof valSortKey) => { - if (valSortKey === key) { - setValSortDir((d) => (d === "asc" ? "desc" : "asc")); - } else { - setValSortKey(key); - setValSortDir("desc"); - } - }; - // ── Render ───────────────────────────────────────────────────────── if (isLoading) { @@ -424,6 +371,10 @@ export default function TestsPage() {