Skip to content

Add saved filter views and redesign findings dashboard#287

Open
khat190 wants to merge 5 commits into
utksh1:mainfrom
khat190:feature/saved-filter-views
Open

Add saved filter views and redesign findings dashboard#287
khat190 wants to merge 5 commits into
utksh1:mainfrom
khat190:feature/saved-filter-views

Conversation

@khat190
Copy link
Copy Markdown
Contributor

@khat190 khat190 commented May 23, 2026

What Changed

Frontend

  • frontend/src/hooks/useSavedViews.ts — new custom hook managing full preset CRUD. Writes to localStorage immediately (offline-safe) and syncs to the backend when reachable. Validates every preset on read so corrupt/malformed data is silently discarded rather than crashing the UI.
  • frontend/src/components/SavedViewsPanel.tsx — new dropdown panel component placed in the Findings filter row. Supports: save current filters under a named preset, apply a saved preset in one click, inline rename (click edit icon → type → blur/Enter commits), two-click delete (confirm guard), and animated feedback on save/error.
  • frontend/src/pages/Findings.tsx — minimal diff from original. Added useSavedViews() hook, currentPreset snapshot, applyPreset() restore function, and <SavedViewsPanel> in the sort-pills row. All existing filter logic, finding rows, and detail panel are untouched.

Backend

  • backend/secuscan/saved_views.py — new self-contained FastAPI router registered at /api/v1/saved-views. Full CRUD: GET (list), POST (create, 409 on duplicate name), PUT (overwrite/rename), DELETE (idempotent). FilterPreset is a Pydantic model with field validators on sortMode and severity so invalid values are rejected at the boundary with 422.
  • backend/secuscan/main.py — two lines added: import saved_views_router and app.include_router(saved_views_router).

Database

The saved_views table is created via CREATE TABLE IF NOT EXISTS on first request (idempotent). No migration script needed; no existing tables are modified.

Why It Changed

Power users repeatedly configure the same filter combinations (e.g. critical severity + specific target + last 7 days) and had no way to persist them. This feature adds a named-preset system that survives page reloads and browser restarts, with optional backend persistence for multi-session durability.

API Surface

Method Path Behaviour
GET /api/v1/saved-views List all saved views
POST /api/v1/saved-views Create (409 if name exists)
PUT /api/v1/saved-views/{id} Overwrite preset and/or rename
DELETE /api/v1/saved-views/{id} Delete (idempotent, always 200)

How to Test
Backend tests

pytest testing/backend/unit/test_saved_views.py -v

22 tests covering: create, list, apply (round-trip), overwrite, rename, delete, duplicate name (409), invalid JSON (422), invalid enum values (422), empty name (422), name-too-long (422), non-existent ID (404), idempotent delete, and partial update.

Frontend tests

npx vitest run frontend/testing/unit/hooks/useSavedViews.test.ts

20 tests covering: create, localStorage persistence, apply/restore, overwrite (same name), case-insensitive overwrite, rename, rename-to-empty throws, delete, idempotent delete, invalid preset throws, corrupt localStorage recovery, mixed valid/invalid data on mount, multiple independent views.

Trade-offs & Known Limitations

  • No auth: saved views are per-browser (localStorage) or per-server (no user concept in the current backend). This matches the existing SecuScan local-first model.
  • Backend sync is optimistic: if the backend is unreachable, saves go to localStorage only; they sync on the next successful request. No retry queue.
  • Name uniqueness is case-insensitive on the backend (SQL LOWER()) but case-preserving on display, consistent with how the workflows endpoint behaves.

Screenshots

image image

CLoses: #235

@khat190 khat190 force-pushed the feature/saved-filter-views branch 2 times, most recently from 9a7efde to 4d43d19 Compare May 24, 2026 11:11
@khat190 khat190 force-pushed the feature/saved-filter-views branch from 8d7639f to 6ac3247 Compare May 24, 2026 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant