From e21de70d2f04587d00eaf0344350ce6ce1a011f5 Mon Sep 17 00:00:00 2001 From: Mariusz Banach Date: Wed, 18 Feb 2026 02:53:16 +0100 Subject: [PATCH] MAESTRO: add report search bar --- ...er-analyzer-Phase-06-Interactive-Report.md | 2 +- .../src/components/report/ReportSearchBar.tsx | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/report/ReportSearchBar.tsx diff --git a/Auto Run Docs/SpecKit-web-header-analyzer-Phase-06-Interactive-Report.md b/Auto Run Docs/SpecKit-web-header-analyzer-Phase-06-Interactive-Report.md index f638241..c1f9a19 100644 --- a/Auto Run Docs/SpecKit-web-header-analyzer-Phase-06-Interactive-Report.md +++ b/Auto Run Docs/SpecKit-web-header-analyzer-Phase-06-Interactive-Report.md @@ -41,7 +41,7 @@ ReportContainer - [x] T030 [US4] Write failing tests (TDD Red) in `frontend/src/__tests__/report/TestResultCard.test.tsx` (each severity level, expand/collapse, error indicator), `HopChainVisualisation.test.tsx` (render with sample hops), `ReportSearchBar.test.tsx` (filter simulation), `ReportExport.test.tsx` (export trigger), `SecurityAppliancesSummary.test.tsx` (render with sample appliances, empty state), `ReportContainer.test.tsx` (full report with mixed results) - [x] T031 [P] [US4] Create `frontend/src/components/report/TestResultCard.tsx` — collapsible card per test result. Severity-coloured indicator (red=spam, amber=suspicious, green=clean per FR-09), header name, monospace value, analysis text. Failed tests show error indicator (FR-25). Expand/collapse with animation, keyboard accessible (NFR-02). Verify `TestResultCard.test.tsx` passes (TDD Green) - [x] T032 [P] [US4] Create `frontend/src/components/report/HopChainVisualisation.tsx` — vertical flow diagram of mail server hop chain (FR-08): hostname, IP, timestamp, server version, connecting arrows. FontAwesome server/network icons. Responsive. Verify `HopChainVisualisation.test.tsx` passes (TDD Green) -- [ ] T033 [P] [US4] Create `frontend/src/components/report/ReportSearchBar.tsx` — search/filter bar above report (FR-20). Filters by text match against test name, header name, or analysis text. Highlights matches, shows count. FontAwesome search icon, Escape to clear. Verify `ReportSearchBar.test.tsx` passes (TDD Green) +- [x] T033 [P] [US4] Create `frontend/src/components/report/ReportSearchBar.tsx` — search/filter bar above report (FR-20). Filters by text match against test name, header name, or analysis text. Highlights matches, shows count. FontAwesome search icon, Escape to clear. Verify `ReportSearchBar.test.tsx` passes (TDD Green) - [ ] T034 [P] [US4] Create `frontend/src/components/report/ReportExport.tsx` — export as HTML (styled standalone page) or JSON (raw data) per FR-21. FontAwesome download icons, triggers browser download. Verify `ReportExport.test.tsx` passes (TDD Green) - [ ] T035 [US4] Create `frontend/src/components/report/SecurityAppliancesSummary.tsx` — summary listing detected email security products as badges/tags with FontAwesome shield icons. Handle empty state (no appliances detected). Verify `SecurityAppliancesSummary.test.tsx` passes (TDD Green) - [ ] T036 [US4] Create `frontend/src/components/report/ReportContainer.tsx` — top-level wrapper receiving `AnalysisReport`. Renders: summary stats (total tests, passed, failed, severity breakdown), `TestResultCard` list, `HopChainVisualisation`, `SecurityAppliancesSummary`, `ReportSearchBar`, `ReportExport`. FontAwesome summary icons. Verify `ReportContainer.test.tsx` passes (TDD Green) diff --git a/frontend/src/components/report/ReportSearchBar.tsx b/frontend/src/components/report/ReportSearchBar.tsx new file mode 100644 index 0000000..cbe125e --- /dev/null +++ b/frontend/src/components/report/ReportSearchBar.tsx @@ -0,0 +1,87 @@ +"use client"; + +import type { FormEvent, KeyboardEvent } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faMagnifyingGlass, faXmark } from "@fortawesome/free-solid-svg-icons"; + +type ReportSearchBarProps = { + query: string; + matchCount: number; + totalCount: number; + onQueryChange: (next: string) => void; +}; + +export default function ReportSearchBar({ + query, + matchCount, + totalCount, + onQueryChange, +}: ReportSearchBarProps) { + const handleInput = (event: FormEvent) => { + onQueryChange(event.currentTarget.value); + }; + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + event.preventDefault(); + onQueryChange(""); + } + }; + + const handleClear = () => { + onQueryChange(""); + }; + + const hasQuery = query.trim().length > 0; + + return ( +
+
+ + + {hasQuery ? ( + + ) : null} + + + {matchCount} / {totalCount} + +
+
+ {hasQuery ? "Matches for" : "Showing all results"} + {hasQuery ? ( + + {query} + + ) : null} +
+
+ ); +}