Adds a CategoryFilterBar with pill-shaped FilterChip components below the
metric health cards. Non-metric categories (Missing_AppID, Aging Vulns,
Missing_DF, etc.) are derived dynamically from device data and displayed
as color-coded filterable chips with device counts.
Unified filter state replaces the old metricFilter array, ensuring mutual
exclusivity between metric card filters and non-metric chip filters.
Includes 4 property-based tests validating derivation, filter predicate,
mutual exclusivity, and color resolution correctness.
Closes#26
The host list on the compliance page showed stale resolution date and
remediation plan values after editing them in the detail sidebar, until
an unrelated refresh (filter, team, or tab change) ran. handleSaveMetadata
re-fetched only the panel's own detail and never notified the parent.
Add an onMetadataSaved callback invoked after a successful metadata PATCH
and wire it to the existing list refresh in CompliancePage, mirroring the
onNoteAdded pattern. The list now reflects saved changes immediately.
Closes#23
Normalize the date in groupByHostname() to handle PostgreSQL Date objects,
and add .slice(0,10) in the frontend render as a safety net. Prevents the
full ISO timestamp (2026-05-15T00:00:00.000Z) from displaying in the table.
Display raw counts alongside percentages in the compliance metric health
cards, e.g. '67% (4/6)' instead of just '67%'. Data was already available
in the summary JSON (compliant, total fields) — just not rendered.
Closes#16
- Add bu_teams column to users table (migration + fresh schema)
- Create shared KNOWN_TEAMS constant and validateTeams helper
- Expose user teams in auth middleware, login, and /me responses
- Add bu_teams CRUD to user management routes with audit logging
- Make Ivanti FINDINGS_FILTERS configurable via IVANTI_BU_FILTER env var
- Add query-time team filtering to GET /findings and /findings/counts
- Update AuthContext with teams helpers and admin scope toggle
- Create AdminScopeToggle component (My Teams / All BUs)
- Scope ReportingPage findings fetch by user teams
- Scope CompliancePage team selector by user teams
- Scope ExportsPage findings exports by user teams
- Add BU teams multi-select to UserManagement create/edit forms
- Display team badges in user list table
Add 6 Recharts charts in a collapsible Historical Trends panel on the
Compliance page, covering all Tier-1 recommendations from the reporting
design doc.
Backend — 5 new API endpoints:
- GET /api/compliance/trends — active totals + per-team counts per upload
- GET /api/compliance/mttr — mean days to resolution per team
- GET /api/compliance/top-recurring — most persistent active findings by seen_count
- GET /api/compliance/category-trend — category breakdown per upload (future use)
- GET /api/archer-tickets/status-trend — ticket pipeline by creation date + status
Frontend — new ComplianceChartsPanel component:
- Active Findings Over Time (multi-line: total + per-team dashed)
- Change per Report Cycle (stacked bar: new/recurring + resolved)
- Team Compliance Health (multi-line per team)
- Mean Time to Resolution (horizontal bar per team)
- Most Persistent Findings (horizontal bar top-10 by seen_count)
- Archer Exception Pipeline (stacked bar by date + status)
All charts degrade gracefully to a no-data placeholder until uploads
accumulate. Panel is collapsible to stay out of the way when not needed.
Adds recharts dependency to frontend.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In ComplianceDetailPanel, active metrics with a metric_id starting with
'2.3' and an Ivanti_Vulnerability_ID in extra_json now surface the ID
prominently alongside a 'View in Reporting →' button. Clicking navigates
directly to the Reporting page. onNavigate prop threaded through
App → CompliancePage → ComplianceDetailPanel → MetricRow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>