mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-25 01:37:05 +00:00
fix: differentiate security action links and add suppression editing (#1500)
Security page UX fixes: - Stop the CVSS x EPSS scatter chart from painting a full-plot "white rectangle" cursor on click (cursor disabled), and prevent click-drag selection on charts. - Differentiate the overview action links: "fixable" links (masthead primary action, review-queue blocker, and the Fixable signal tile) now open the Images tab pre-filtered to fixable findings; the Stale and Failed signal tiles link to the History tab where those scans are listed; Secrets and Misconfigs tiles link to their tabs. The Images tab accepts an initialFilter and exposes a Fixable option in the severity dropdown. - Fix the "Secrets / misconfigs" option wrapping and misaligning in the severity dropdown (single-line option labels, wider trigger). - Add Edit for CVE suppressions and misconfig acknowledgements (reason, scope pattern, expiry), reusing the existing dialog and the existing PUT endpoints; the CVE/rule identity stays fixed.
This commit is contained in:
@@ -17,11 +17,13 @@ import { useIsMobile } from '@/hooks/use-is-mobile';
|
||||
import { Masthead, type Tone } from './mobile/mobile-ui';
|
||||
import { SecurityMobileTabs, type SecurityMobileTab } from './security/SecurityMobile';
|
||||
import type { SecurityTab } from '@/lib/events';
|
||||
import type { ImageFilterValue } from '@/lib/severityStyles';
|
||||
import type { SecurityOverview, ScanSummary, ScanDetailTab, SecurityRiskTrendPoint, ExploitIntelFinding, FleetRole } from '@/types/security';
|
||||
import { VulnerabilityScanSheet } from './VulnerabilityScanSheet';
|
||||
import { SuppressionsPanel } from './settings/SuppressionsPanel';
|
||||
import { MisconfigAckPanel } from './settings/MisconfigAckPanel';
|
||||
import { OverviewTab } from './security/OverviewTab';
|
||||
import { reasonImageFilter } from './security/postureNavigation';
|
||||
import { ImagesTab } from './security/ImagesTab';
|
||||
import { FindingsTab } from './security/FindingsTab';
|
||||
import { ScanPolicyManager } from './security/ScanPolicyManager';
|
||||
@@ -85,6 +87,16 @@ export function SecurityView({ activeTab, onTabChange, headerActions }: Security
|
||||
|
||||
const [inspectScanId, setInspectScanId] = useState<number | null>(null);
|
||||
const [inspectInitialTab, setInspectInitialTab] = useState<ScanDetailTab | undefined>(undefined);
|
||||
// Filter to preselect on the Images tab when arriving from an overview link
|
||||
// (e.g. "fixable findings"). Null leaves the Images tab on its own default.
|
||||
const [imagesFilter, setImagesFilter] = useState<ImageFilterValue | null>(null);
|
||||
|
||||
// Navigate between security tabs, optionally preselecting an Images filter so
|
||||
// an overview action link lands on exactly the affected images.
|
||||
const handleNavigate = useCallback((tab: SecurityTab, filter?: ImageFilterValue) => {
|
||||
if (tab === 'images' && filter) setImagesFilter(filter);
|
||||
onTabChange(tab);
|
||||
}, [onTabChange]);
|
||||
|
||||
const onInspect = useCallback((scanId: number, initialTab?: ScanDetailTab) => {
|
||||
setInspectInitialTab(initialTab);
|
||||
@@ -254,7 +266,7 @@ export function SecurityView({ activeTab, onTabChange, headerActions }: Security
|
||||
trend={trend}
|
||||
exploitIntel={exploitIntel}
|
||||
exploitTruncated={exploitTruncated}
|
||||
onNavigate={onTabChange}
|
||||
onNavigate={handleNavigate}
|
||||
onInspect={onInspect}
|
||||
canScan={canScan}
|
||||
onScanComplete={() => setReloadToken((t) => t + 1)}
|
||||
@@ -272,6 +284,7 @@ export function SecurityView({ activeTab, onTabChange, headerActions }: Security
|
||||
canScan={canScan}
|
||||
scanningRef={scanningRef}
|
||||
onScan={scanImage}
|
||||
initialFilter={imagesFilter ?? undefined}
|
||||
/>
|
||||
</CapabilityGate>
|
||||
</TabsContent>
|
||||
@@ -382,7 +395,10 @@ export function SecurityView({ activeTab, onTabChange, headerActions }: Security
|
||||
{overview?.posture === 'Action needed' && overview.primaryAction ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onTabChange(overview.primaryAction!.targetTab)}
|
||||
onClick={() => handleNavigate(
|
||||
overview.primaryAction!.targetTab,
|
||||
reasonImageFilter(overview.primaryAction!.kind),
|
||||
)}
|
||||
className="text-xs font-medium text-brand hover:underline whitespace-nowrap"
|
||||
>
|
||||
{overview.primaryAction.label} →
|
||||
|
||||
Reference in New Issue
Block a user