mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-24 08:57:25 +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:
@@ -9,6 +9,8 @@ export interface SignalTile {
|
||||
tone?: SignalTone;
|
||||
/** Optional series for a 64x20 sparkline stroked in brand cyan. */
|
||||
spark?: number[];
|
||||
/** When set, the tile renders as a button that navigates on click. */
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
interface SignalRailProps {
|
||||
@@ -33,39 +35,49 @@ export function SignalRail({ tiles, className }: SignalRailProps) {
|
||||
)}
|
||||
style={{ gridTemplateColumns: `repeat(${tiles.length}, minmax(0, 1fr))` }}
|
||||
>
|
||||
{tiles.map((tile, idx) => (
|
||||
<div
|
||||
key={tile.kicker}
|
||||
className={cn(
|
||||
'flex items-center justify-between gap-4 px-5 py-[var(--density-tile-y)]',
|
||||
idx > 0 && 'border-l border-card-border',
|
||||
)}
|
||||
>
|
||||
<div className="flex min-w-0 flex-col gap-1">
|
||||
<span className="font-mono text-[10px] uppercase tracking-[0.22em] text-stat-subtitle">
|
||||
{tile.kicker}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
'font-mono tabular-nums tracking-tight text-2xl leading-none',
|
||||
toneClass[tile.tone ?? 'value'],
|
||||
)}
|
||||
>
|
||||
{tile.value}
|
||||
</span>
|
||||
</div>
|
||||
{tile.spark && tile.spark.length > 1 ? (
|
||||
<div className="h-5 w-16 shrink-0 opacity-90">
|
||||
<Sparkline
|
||||
points={tile.spark}
|
||||
stroke="var(--brand)"
|
||||
fill="var(--brand)"
|
||||
strokeWidth={1.25}
|
||||
/>
|
||||
{tiles.map((tile, idx) => {
|
||||
const inner = (
|
||||
<>
|
||||
<div className="flex min-w-0 flex-col gap-1">
|
||||
<span className="font-mono text-[10px] uppercase tracking-[0.22em] text-stat-subtitle">
|
||||
{tile.kicker}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
'font-mono tabular-nums tracking-tight text-2xl leading-none',
|
||||
toneClass[tile.tone ?? 'value'],
|
||||
)}
|
||||
>
|
||||
{tile.value}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
{tile.spark && tile.spark.length > 1 ? (
|
||||
<div className="h-5 w-16 shrink-0 opacity-90">
|
||||
<Sparkline
|
||||
points={tile.spark}
|
||||
stroke="var(--brand)"
|
||||
fill="var(--brand)"
|
||||
strokeWidth={1.25}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
const cellClass = cn(
|
||||
'flex items-center justify-between gap-4 px-5 py-[var(--density-tile-y)] text-left',
|
||||
idx > 0 && 'border-l border-card-border',
|
||||
tile.onClick && 'cursor-pointer transition-colors hover:bg-accent/5',
|
||||
);
|
||||
return tile.onClick ? (
|
||||
<button key={tile.kicker} type="button" onClick={tile.onClick} className={cellClass}>
|
||||
{inner}
|
||||
</button>
|
||||
) : (
|
||||
<div key={tile.kicker} className={cellClass}>
|
||||
{inner}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ const ChartContainer = React.forwardRef<
|
||||
data-chart={chartId}
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||
"flex select-none justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -176,7 +176,7 @@ export function Combobox({
|
||||
type="button"
|
||||
onClick={() => handleSelect(option)}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground",
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-left text-sm outline-none hover:bg-accent hover:text-accent-foreground",
|
||||
value === option.value && "bg-accent/50"
|
||||
)}
|
||||
>
|
||||
@@ -187,7 +187,7 @@ export function Combobox({
|
||||
)}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
{option.label}
|
||||
<span className="min-w-0 truncate">{option.label}</span>
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user