diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e1de7d..c3a525b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,29 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this --- +## [2.1.0] — 2026-06-01 + +### Features + +- **Estimated resolution date per metric** — the compliance asset sidebar now shows each noncompliant metric's estimated resolution date at the top of its section, in `YYYY-MM-DD` format, with placeholders for metrics that have no date set or an invalid date (closes #20) +- **CARD Action Modal** with full owner context +- **Granite Loader Sheet generator** with CARD enrichment, plus a Loader Sheet button on the Reporting page queue panel +- **Vendor-specific issue type dropdown** for Jira ticket creation, with all vendor project keys +- **LIVE and LAST REPORT badges** on the VCL compliance page +- **Collapsible sections** on the Ivanti Queue page and side panel + +### Bug Fixes + +- Fix remediation plan and resolution date missing from the compliance table; format `resolution_date` as `YYYY-MM-DD` +- Improve CARD action error messages and default loader columns +- Fix CARD production timeout by forcing IPv4 (`dns.setDefaultResultOrder('ipv4first')`) +- Add IP address validation to CARD confirm/decline/redirect actions +- Auto-resolve bare IP to CARD asset ID with suffix lookup +- Increase CARD API timeout from 15s to 30s +- Rewrite CARD enrich-batch to use the team assets endpoint for full data + +--- + ## [2.0.0] — 2026-05-26 ### Breaking Changes diff --git a/frontend/src/components/pages/ComplianceDetailPanel.js b/frontend/src/components/pages/ComplianceDetailPanel.js index 35413af..5e45f10 100644 --- a/frontend/src/components/pages/ComplianceDetailPanel.js +++ b/frontend/src/components/pages/ComplianceDetailPanel.js @@ -1,6 +1,12 @@ import React, { useState, useEffect, useCallback } from 'react'; import { X, MessageSquare, Send, Loader, AlertCircle, Clock, Shield, Trash2, Calendar, FileText, Save } from 'lucide-react'; import ConfirmModal from '../ConfirmModal'; +import { + formatResolutionDate, + RESOLUTION_DATE_LABEL, + NO_DATE_PLACEHOLDER, + INVALID_DATE_PLACEHOLDER, +} from '../../utils/resolutionDate'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; @@ -796,6 +802,19 @@ function MetricRow({ metric, resolved, onNavigate }) { if (extra['Splunk - Last Seen']) highlights.push({ label: 'Splunk', value: extra['Splunk - Last Seen'] }); if (extra['MFA - Software']) highlights.push({ label: 'MFA SW', value: extra['MFA - Software'] }); + // Read-only estimated resolution date, shown only for active (noncompliant) + // metrics at the top of the section. Derived solely from this metric's own + // resolution_date — no editing, no shared/"Multiple values" collapsing. + const resolutionDisplay = resolved ? null : formatResolutionDate(metric.resolution_date); + const resolutionValueText = resolutionDisplay + ? (resolutionDisplay.state === 'set' + ? resolutionDisplay.value + : resolutionDisplay.state === 'invalid' + ? INVALID_DATE_PLACEHOLDER + : NO_DATE_PLACEHOLDER) + : null; + const resolutionMuted = resolutionDisplay && resolutionDisplay.state !== 'set'; + return (