mirror of
https://github.com/mgeeky/decode-spam-headers.git
synced 2026-02-22 05:23:31 +01:00
MAESTRO: add analysis controls panel
This commit is contained in:
@@ -24,13 +24,13 @@ This phase implements the test selection panel and analysis configuration contro
|
||||
- [x] T021 [US2] Create `backend/app/schemas/tests.py` (response schema) and `backend/app/routers/tests.py` — FastAPI router with `GET /api/tests` returning all available tests (id, name, category) from scanner registry. Register router in `backend/app/main.py`. Verify `test_tests_router.py` passes (TDD Green)
|
||||
- [x] T022 [US2] Write failing tests (TDD Red) in `frontend/src/__tests__/TestSelector.test.tsx` (render with mocked list, select/deselect all, search filtering) and `frontend/src/__tests__/AnalysisControls.test.tsx` (render, toggle states, keyboard accessibility)
|
||||
- [x] T023 [P] [US2] Create `frontend/src/components/TestSelector.tsx` — dropdown with checkboxes per test, fetches list from `GET /api/tests`, "Select All"/"Deselect All" buttons (FR-04), text search/filter (FR-23), grouped by vendor/category (FR-24), FontAwesome icons. Verify `TestSelector.test.tsx` passes (TDD Green)
|
||||
- [ ] T024 [P] [US2] Create `frontend/src/components/AnalysisControls.tsx` — panel containing TestSelector, DNS resolution toggle (off by default, FR-18), decode-all toggle (FR-19), FontAwesome toggle icons, keyboard accessible (NFR-02). Verify `AnalysisControls.test.tsx` passes (TDD Green)
|
||||
- [x] T024 [P] [US2] Create `frontend/src/components/AnalysisControls.tsx` — panel containing TestSelector, DNS resolution toggle (off by default, FR-18), decode-all toggle (FR-19), FontAwesome toggle icons, keyboard accessible (NFR-02). Verify `AnalysisControls.test.tsx` passes (TDD Green)
|
||||
|
||||
## Completion
|
||||
|
||||
- [ ] `pytest backend/tests/api/test_tests_router.py` passes
|
||||
- [ ] `GET /api/tests` returns all 106+ tests with id, name, and category
|
||||
- [ ] All vitest tests pass: `npx vitest run src/__tests__/TestSelector.test.tsx src/__tests__/AnalysisControls.test.tsx`
|
||||
- [x] All vitest tests pass: `npx vitest run src/__tests__/TestSelector.test.tsx src/__tests__/AnalysisControls.test.tsx`
|
||||
- [ ] Test selector renders all 106+ tests with checkboxes
|
||||
- [ ] Select All / Deselect All buttons work correctly
|
||||
- [ ] Search/filter narrows visible tests by name
|
||||
|
||||
104
frontend/src/components/AnalysisControls.tsx
Normal file
104
frontend/src/components/AnalysisControls.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
"use client";
|
||||
|
||||
import type { KeyboardEvent } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faToggleOff,
|
||||
faToggleOn,
|
||||
faGlobe,
|
||||
faCode,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import type { AnalysisConfig } from "../types/analysis";
|
||||
import TestSelector from "./TestSelector";
|
||||
|
||||
type AnalysisControlsProps = {
|
||||
config: AnalysisConfig;
|
||||
onChange: (next: AnalysisConfig) => void;
|
||||
};
|
||||
|
||||
const handleToggleKeyDown = (
|
||||
event: KeyboardEvent<HTMLButtonElement>,
|
||||
onToggle: () => void,
|
||||
): void => {
|
||||
if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
|
||||
event.preventDefault();
|
||||
onToggle();
|
||||
}
|
||||
};
|
||||
|
||||
export default function AnalysisControls({ config, onChange }: AnalysisControlsProps) {
|
||||
const updateTests = (nextTestIds: number[]) => {
|
||||
onChange({ ...config, testIds: nextTestIds });
|
||||
};
|
||||
|
||||
const toggleResolve = () => {
|
||||
onChange({ ...config, resolve: !config.resolve });
|
||||
};
|
||||
|
||||
const toggleDecodeAll = () => {
|
||||
onChange({ ...config, decodeAll: !config.decodeAll });
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="flex flex-col gap-6">
|
||||
<div className="rounded-2xl border border-info/10 bg-surface p-6 shadow-[0_0_40px_rgba(15,23,42,0.25)]">
|
||||
<div className="flex items-center justify-between text-xs uppercase tracking-[0.2em] text-info/90">
|
||||
<span>Analysis Controls</span>
|
||||
<span className="font-mono text-[10px] text-text/50">US2</span>
|
||||
</div>
|
||||
<div className="mt-4 grid gap-3 sm:grid-cols-2">
|
||||
<div className="flex items-center justify-between gap-4 rounded-xl border border-info/10 bg-background/40 p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="mt-1 rounded-full border border-info/20 bg-background/60 p-2 text-xs text-info/80">
|
||||
<FontAwesomeIcon icon={faGlobe} />
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-semibold text-text/80">DNS Resolution</span>
|
||||
<span className="text-xs text-text/50">Resolve hostnames while analyzing.</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={config.resolve}
|
||||
aria-label="Toggle DNS resolution"
|
||||
data-testid="toggle-resolve"
|
||||
className="inline-flex items-center gap-2 rounded-full border border-info/20 bg-background/60 px-3 py-2 text-xs text-text/70 transition hover:border-info/40 hover:text-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-info"
|
||||
onClick={toggleResolve}
|
||||
onKeyDown={(event) => handleToggleKeyDown(event, toggleResolve)}
|
||||
>
|
||||
<FontAwesomeIcon icon={config.resolve ? faToggleOn : faToggleOff} />
|
||||
{config.resolve ? "On" : "Off"}
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-xl border border-info/10 bg-background/40 p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="mt-1 rounded-full border border-info/20 bg-background/60 p-2 text-xs text-info/80">
|
||||
<FontAwesomeIcon icon={faCode} />
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-semibold text-text/80">Decode All</span>
|
||||
<span className="text-xs text-text/50">Decode every encoded header value.</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={config.decodeAll}
|
||||
aria-label="Toggle decode all"
|
||||
data-testid="toggle-decode-all"
|
||||
className="inline-flex items-center gap-2 rounded-full border border-info/20 bg-background/60 px-3 py-2 text-xs text-text/70 transition hover:border-info/40 hover:text-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-info"
|
||||
onClick={toggleDecodeAll}
|
||||
onKeyDown={(event) => handleToggleKeyDown(event, toggleDecodeAll)}
|
||||
>
|
||||
<FontAwesomeIcon icon={config.decodeAll ? faToggleOn : faToggleOff} />
|
||||
{config.decodeAll ? "On" : "Off"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TestSelector selectedTestIds={config.testIds} onSelectionChange={updateTests} />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user