Files
cve-dashboard/docs/design-system-redesign/ui_kits/reporting/KitDocs.jsx
root 27192dd69f WIP: Dashboard redesign — design system overhaul and component updates
Frontend redesign in progress: updated styles, layout, and components
across all pages to align with new design system. Includes Jira API
compliance specs, property tests, and load test script.
2026-04-29 14:20:23 +00:00

482 lines
23 KiB
JavaScript

// KitDocs.jsx — browseable docs page for the Reporting kit.
// Sections: Overview · Tokens · Components · Assemblies · Reference page.
const { useState: useDocsState } = React;
const {
COLORS: DC, PageHeader, RptButton, KbCard, PillTab, FilterChip, StatusBanner,
ToolbarLabel, SeverityDot, SlaPill, WorkflowBadge, DonutSample, RptIcon: DI,
} = window.RPT;
const { ReportingPage } = window.RPT_PAGE;
/* ── Layout primitives ─────────────────────────────────────────── */
function Section({ id, eyebrow, title, blurb, children }) {
return (
<section id={id} style={{ paddingTop: 32, scrollMarginTop: 120 }}>
<div style={{ marginBottom: 16 }}>
{eyebrow && (
<div style={{
fontFamily: 'var(--font-mono)', fontSize: 10, fontWeight: 700,
color: DC.sky, textTransform: 'uppercase', letterSpacing: '0.18em',
marginBottom: 6,
}}>{eyebrow}</div>
)}
<h2 style={{
fontFamily: 'var(--font-mono)', fontSize: 22, fontWeight: 700,
color: 'var(--fg-1)', margin: 0, letterSpacing: '0.02em',
}}>{title}</h2>
{blurb && (
<p style={{
fontFamily: 'var(--font-display)', fontSize: 14, lineHeight: 1.6,
color: 'var(--fg-muted)', maxWidth: 640, margin: '8px 0 0 0',
}}>{blurb}</p>
)}
</div>
{children}
</section>
);
}
function Spec({ label, children }) {
return (
<div style={{
display: 'grid', gridTemplateColumns: '160px 1fr', gap: 16,
padding: '10px 0', borderBottom: '1px solid rgba(255,255,255,0.04)',
fontFamily: 'var(--font-mono)', fontSize: 12,
}}>
<div style={{ color: 'var(--fg-disabled)', textTransform: 'uppercase', letterSpacing: '0.06em', fontSize: 10, fontWeight: 600 }}>
{label}
</div>
<div style={{ color: 'var(--fg-2)' }}>{children}</div>
</div>
);
}
function CodeChip({ children }) {
return (
<code style={{
display: 'inline-block', padding: '2px 6px', borderRadius: 3,
background: 'rgba(14,165,233,0.10)', border: '1px solid rgba(14,165,233,0.18)',
fontFamily: 'var(--font-mono)', fontSize: 11, color: DC.skySoft,
}}>{children}</code>
);
}
function SwatchRow({ name, value, role }) {
return (
<div style={{
display: 'grid', gridTemplateColumns: '52px 1fr auto', alignItems: 'center', gap: 14,
padding: '8px 0', borderBottom: '1px solid rgba(255,255,255,0.04)',
}}>
<div style={{
height: 36, borderRadius: 6, background: value,
border: '1px solid rgba(255,255,255,0.08)',
}} />
<div>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--fg-1)', fontWeight: 600 }}>{name}</div>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-disabled)' }}>{role}</div>
</div>
<CodeChip>{value}</CodeChip>
</div>
);
}
/* ── Sticky tab nav ─────────────────────────────────────────────── */
function TabNav({ active, onChange }) {
const items = [
{ id: 'overview', label: 'Overview' },
{ id: 'tokens', label: 'Tokens' },
{ id: 'components', label: 'Components' },
{ id: 'assemblies', label: 'Assemblies' },
{ id: 'reference', label: 'Reference page' },
];
return (
<div style={{
position: 'sticky', top: 0, zIndex: 20,
background: 'rgba(15,23,42,0.92)',
backdropFilter: 'blur(8px)',
borderBottom: '1px solid rgba(14,165,233,0.12)',
padding: '14px 24px',
}}>
<div style={{ maxWidth: 1280, margin: '0 auto', display: 'flex', alignItems: 'center', gap: 16 }}>
<div style={{
fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 700,
color: DC.green, textTransform: 'uppercase', letterSpacing: '0.12em',
textShadow: '0 0 12px rgba(16,185,129,0.25)',
flexShrink: 0,
}}>
Reporting Kit
</div>
<div style={{ width: 1, height: 18, background: 'rgba(255,255,255,0.08)' }} />
<div style={{ display: 'flex', gap: 4 }}>
{items.map((it) => (
<PillTab key={it.id} active={active === it.id} onClick={() => onChange(it.id)}>
{it.label}
</PillTab>
))}
</div>
</div>
</div>
);
}
/* ── Overview ───────────────────────────────────────────────────── */
function OverviewSection() {
return (
<Section
id="overview"
eyebrow="01 · Overview"
title="Reporting page UI kit"
blurb="The visual vocabulary used by /reporting. Aligned to the Knowledge Base pattern: green-glow page identity, sky-blue surface accents, mono uppercase labels, Knowledge-Base card chrome on every panel."
>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 14 }}>
<KbCard label="Page identity" hover={false}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<div style={{
fontFamily: 'var(--font-mono)', fontSize: 18, fontWeight: 700,
color: DC.green, textTransform: 'uppercase', letterSpacing: '0.1em',
textShadow: '0 0 12px rgba(16,185,129,0.25)',
}}>Reporting</div>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-muted)' }}>
Green is reserved for the page title + the lone primary action (Sync). Everything else is sky.
</div>
</div>
</KbCard>
<KbCard label="Surface accent" hover={false}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<div style={{
padding: 10, borderRadius: 6,
background: 'linear-gradient(135deg, rgba(30,41,59,0.95) 0%, rgba(15,23,42,0.98) 100%)',
border: '1.5px solid rgba(14,165,233,0.35)',
fontFamily: 'var(--font-mono)', fontSize: 11, color: DC.skySoft,
}}>
KB card · sky border · 0.12 0.35 on hover
</div>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-muted)' }}>
Same chrome for donuts, trend, and findings panel. No more colored left-rails.
</div>
</div>
</KbCard>
<KbCard label="Type" hover={false}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-disabled)', textTransform: 'uppercase', letterSpacing: '0.1em' }}>
Card label · 11 / 600 / 0.1em
</div>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 14, color: 'var(--fg-1)' }}>JetBrains Mono · everywhere</div>
<div style={{ fontFamily: 'var(--font-display)', fontSize: 13, color: 'var(--fg-muted)' }}>Outfit · prose only (blurbs)</div>
</div>
</KbCard>
</div>
</Section>
);
}
/* ── Tokens ─────────────────────────────────────────────────────── */
function TokensSection() {
return (
<Section
id="tokens"
eyebrow="02 · Tokens"
title="Color roles, type, spacing"
blurb="Reporting uses the dashboard token set. These are the specific roles the page leans on."
>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 14 }}>
<KbCard label="Color roles" hover={false}>
<SwatchRow name="--accent (sky-500)" value="#0EA5E9" role="Surfaces · pills · table headers · neutral btn" />
<SwatchRow name="--intel-success" value="#10B981" role="Page title glow · primary Sync button" />
<SwatchRow name="--intel-warning" value="#F59E0B" role="Filter active · anomaly · At-Risk SLA" />
<SwatchRow name="--intel-danger" value="#EF4444" role="Errors · Critical sev · Overdue SLA" />
<SwatchRow name="--text-disabled" value="#64748B" role="Card labels · meta text" />
<SwatchRow name="--text-faint" value="#475569" role="Subtitle · separator counts" />
</KbCard>
<KbCard label="Card chrome" hover={false}>
<Spec label="Background"><CodeChip>linear-gradient(135deg, rgba(30,41,59,0.95) 0%, rgba(15,23,42,0.98) 100%)</CodeChip></Spec>
<Spec label="Border (rest)"><CodeChip>1.5px solid rgba(14,165,233,0.12)</CodeChip></Spec>
<Spec label="Border (hover)"><CodeChip>1.5px solid rgba(14,165,233,0.35)</CodeChip></Spec>
<Spec label="Radius"><CodeChip>8px</CodeChip></Spec>
<Spec label="Padding"><CodeChip>16px (donuts) / 20px (panels)</CodeChip></Spec>
<Spec label="Label divider"><CodeChip>1px solid rgba(255,255,255,0.04)</CodeChip></Spec>
</KbCard>
<KbCard label="Type scale" hover={false}>
<Spec label="Page title">JetBrains Mono · 24 / 700 · 0.1em · uppercase · green glow</Spec>
<Spec label="Subtitle / meta">Mono · 12 / 400 · slate-muted</Spec>
<Spec label="Card label">Mono · 11 / 600 · 0.1em · uppercase · slate-disabled</Spec>
<Spec label="Toolbar label">Mono · 11 / 700 · 0.1em · uppercase · sky</Spec>
<Spec label="Button">Mono · 12 / 600 · 0.05em · uppercase</Spec>
<Spec label="Pill tab">Mono · 11 / 600 · 0.05em · uppercase</Spec>
<Spec label="Table cell">Mono · 11 / 400</Spec>
</KbCard>
<KbCard label="Spacing & motion" hover={false}>
<Spec label="Page gap"><CodeChip>20px</CodeChip> between major sections</Spec>
<Spec label="Donut grid"><CodeChip>repeat(auto-fill, minmax(220px, 1fr))</CodeChip> · gap 14</Spec>
<Spec label="Toolbar gap">8px between buttons · 6px subtle group</Spec>
<Spec label="Hover transition"><CodeChip>border-color 150ms cubic-bezier(0.4,0,0.2,1)</CodeChip></Spec>
<Spec label="Spinner"><CodeChip>1s linear infinite</CodeChip></Spec>
</KbCard>
</div>
</Section>
);
}
/* ── Components ─────────────────────────────────────────────────── */
function ComponentsSection() {
const [tab, setTab] = useDocsState('ivanti');
return (
<Section
id="components"
eyebrow="03 · Components"
title="Primitives"
blurb="Each component is a thin wrapper around the inline-style pattern used in ReportingPage.js. Drop into other pages that need to inherit the same vocabulary."
>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(360px, 1fr))', gap: 14 }}>
{/* Buttons */}
<KbCard label="Buttons" hover={false}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', padding: '4px 0 12px' }}>
<RptButton variant="primary" icon={<DI.Refresh size={13} />}>Sync</RptButton>
<RptButton variant="neutral" icon={<DI.Atlas size={13} />}>Atlas</RptButton>
<RptButton variant="subtle" icon={<DI.Download size={12} />}>Export</RptButton>
<RptButton variant="danger" icon={<DI.AlertCircle size={12} />}>Reset</RptButton>
<RptButton variant="neutral" disabled icon={<DI.Loader size={13} />}>Disabled</RptButton>
</div>
<Spec label="primary">Green tinted-fill · the only primary on the page (Sync)</Spec>
<Spec label="neutral">Sky outlined · transparent · for Atlas, Prev/Next, etc.</Spec>
<Spec label="subtle">Sky tinted-fill · for in-toolbar actions (Export, Queue, Columns)</Spec>
<Spec label="danger">Red tinted-fill · destructive only</Spec>
</KbCard>
{/* Pill tabs */}
<KbCard label="Pill tabs (metric switcher)" hover={false}>
<div style={{ display: 'flex', gap: 5, alignItems: 'center', padding: '4px 0 12px' }}>
<DI.PieChart size={14} style={{ color: '#334155', marginRight: 4 }} />
<PillTab active={tab === 'ivanti'} onClick={() => setTab('ivanti')}>Ivanti Findings</PillTab>
<PillTab active={tab === 'atlas'} onClick={() => setTab('atlas')}>Atlas Coverage</PillTab>
<PillTab active={tab === 'sla'} onClick={() => setTab('sla')}>SLA</PillTab>
</div>
<Spec label="Active">sky border + sky-15% fill + sky text</Spec>
<Spec label="Hover (inactive)">subtle white-10% border, slate-300 text</Spec>
</KbCard>
{/* Filter chips */}
<KbCard label="Filter chips" hover={false}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', padding: '4px 0 12px' }}>
<FilterChip color={DC.amber}>Severity: Critical</FilterChip>
<FilterChip color={DC.sky}>Action: Patch</FilterChip>
<FilterChip color={DC.red}>SLA: Overdue</FilterChip>
</div>
<Spec label="Color">Tinted to the dimension being filtered</Spec>
<Spec label="Click">Clears the filter</Spec>
</KbCard>
{/* Status banners */}
<KbCard label="Status banners" hover={false}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6, padding: '4px 0 12px' }}>
<StatusBanner tone="error">Atlas: connection refused retry in 30s</StatusBanner>
<StatusBanner tone="warn">Sync stale (last success 4 hours ago)</StatusBanner>
<StatusBanner tone="info">12 findings reassigned to platform-team</StatusBanner>
</div>
<Spec label="Placement">Header-level for system errors; inline above target for action results</Spec>
</KbCard>
{/* Severity / SLA / Workflow badges */}
<KbCard label="Cell badges" hover={false}>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 14, padding: '4px 0 12px' }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<SeverityDot level="Critical" />
<SeverityDot level="High" />
<SeverityDot level="Medium" />
<SeverityDot level="Low" />
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<SlaPill status="OVERDUE" />
<SlaPill status="AT_RISK" />
<SlaPill status="WITHIN_SLA" />
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
<WorkflowBadge state="OPEN" />
<WorkflowBadge state="FP" />
<WorkflowBadge state="EXC" />
<WorkflowBadge state="REMEDIATED" />
</div>
</div>
<Spec label="Severity">Dot + glow + soft-text label · fixed semantic colors</Spec>
<Spec label="SLA">Pill · OVERDUE/AT_RISK/WITHIN_SLA</Spec>
<Spec label="Workflow">Tagged badge · OPEN/FP/EXC/REMEDIATED/ARCHIVED</Spec>
</KbCard>
{/* KB card itself */}
<KbCard label="KB Card" hover={false}>
<KbCard label="Open vs Closed" style={{ marginBottom: 10 }}>
<div style={{ display: 'flex', justifyContent: 'center', padding: '10px 0' }}>
<DonutSample
segments={[
{ label: 'Open', value: 184, color: DC.sky },
{ label: 'Closed', value: 712, color: DC.green },
]}
size={110}
centerLabel="TOTAL" centerValue="896" />
</div>
</KbCard>
<Spec label="Container">KB card chrome + label divider</Spec>
<Spec label="Body">Centered donut · 170 min-height · responsive auto-fill grid</Spec>
</KbCard>
</div>
</Section>
);
}
/* ── Assemblies ─────────────────────────────────────────────────── */
function AssembliesSection() {
return (
<Section
id="assemblies"
eyebrow="04 · Assemblies"
title="Page-level patterns"
blurb="Three combinations the Reporting page is built from. Reuse them as-is on related pages (e.g. dashboards, audit logs)."
>
{/* Header assembly */}
<KbCard label="① Page header + meta + actions" hover={false} style={{ marginBottom: 14 }}>
<div style={{ padding: '8px 0' }}>
<PageHeader
title="Reporting"
meta={
<>
Last sync: 2 minutes ago
<span style={{ marginLeft: 10, color: '#334155' }}>· 184 of 896 findings</span>
<span style={{ marginLeft: 8, color: DC.amber }}>(3 filters active)</span>
</>
}
>
<RptButton variant="neutral" icon={<DI.Atlas size={13} />}>Atlas</RptButton>
<RptButton variant="primary" icon={<DI.Refresh size={13} />}>Sync</RptButton>
</PageHeader>
</div>
<Spec label="Title">Mono uppercase · green glow · 24px</Spec>
<Spec label="Meta line">Sync timestamp record count active filter count (amber)</Spec>
<Spec label="Actions">Right-aligned · neutral secondaries primary on far right</Spec>
</KbCard>
{/* Donut grid assembly */}
<KbCard label="② Metric tabs + donut grid" hover={false} style={{ marginBottom: 14 }}>
<div style={{ padding: '8px 0' }}>
<div style={{ display: 'flex', gap: 5, alignItems: 'center', marginBottom: 12 }}>
<DI.PieChart size={14} style={{ color: '#334155', marginRight: 4 }} />
<PillTab active onClick={() => {}}>Ivanti Findings</PillTab>
<PillTab active={false} onClick={() => {}}>Atlas Coverage</PillTab>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: 12 }}>
{[
{ label: 'Open vs Closed', segs: [{ label: 'Open', value: 184, color: DC.sky }, { label: 'Closed', value: 712, color: DC.green }], cl: 'TOTAL', cv: '896' },
{ label: 'Action Coverage', segs: [{ label: 'Patch', value: 96, color: DC.sky }, { label: 'Mitigate', value: 42, color: DC.green }, { label: 'Accept', value: 28, color: '#A78BFA' }], cl: 'ASSIGNED', cv: '184' },
{ label: 'FP Status', segs: [{ label: 'Pending', value: 14, color: DC.amber }, { label: 'Approved', value: 31, color: DC.green }, { label: 'Rejected', value: 6, color: DC.red }], cl: 'FINDINGS', cv: '51' },
].map((d) => (
<KbCard key={d.label} label={d.label}>
<div style={{ display: 'flex', justifyContent: 'center', minHeight: 150 }}>
<DonutSample size={100} segments={d.segs} centerLabel={d.cl} centerValue={d.cv} />
</div>
</KbCard>
))}
</div>
</div>
<Spec label="Tabs">Pill row sits above grid · scopes which donuts render</Spec>
<Spec label="Grid">Auto-fill, 220px min · each donut is its own KB card</Spec>
</KbCard>
{/* Findings panel chrome */}
<KbCard label="③ Findings panel chrome (toolbar + filters + table)" hover={false}>
<div style={{
background: 'linear-gradient(135deg, rgba(30,41,59,0.95) 0%, rgba(15,23,42,0.98) 100%)',
border: '1.5px solid rgba(14,165,233,0.12)', borderRadius: 8, padding: 16,
marginTop: 8,
}}>
<div style={{
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
paddingBottom: 10, marginBottom: 10,
borderBottom: '1px solid rgba(255,255,255,0.04)',
}}>
<ToolbarLabel count="184 of 896">Host Findings</ToolbarLabel>
<div style={{ display: 'flex', gap: 6 }}>
<RptButton variant="subtle" icon={<DI.Download size={12} />}>Export</RptButton>
<RptButton variant="subtle" icon={<DI.ListTodo size={12} />}>Queue</RptButton>
<RptButton variant="subtle" icon={<DI.Settings size={12} />}>Columns</RptButton>
</div>
</div>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<FilterChip color={DC.amber}>Severity: Critical, High</FilterChip>
<FilterChip color={DC.sky}>Action: Patch</FilterChip>
<FilterChip color={DC.red}>SLA: Overdue</FilterChip>
</div>
</div>
<Spec label="Toolbar">Mono uppercase label + count · subtle action buttons right</Spec>
<Spec label="Filter row">Tinted chips, click-to-clear</Spec>
<Spec label="Header migration">Sync/Atlas no longer live here they're in the page header</Spec>
</KbCard>
</Section>
);
}
/* ── Reference page ─────────────────────────────────────────────── */
function ReferenceSection() {
return (
<Section
id="reference"
eyebrow="05 · Reference page"
title="Full Reporting page"
blurb="Static mock of /reporting using only kit primitives. Use this to verify any change you make to a primitive flows through the page intact."
>
<div style={{
background: 'var(--bg-page)',
border: '1px solid rgba(14,165,233,0.12)',
borderRadius: 12,
overflow: 'hidden',
}}>
<ReportingPage />
</div>
</Section>
);
}
/* ── Top-level docs page ─────────────────────────────────────────── */
function KitDocs() {
const [active, setActive] = useDocsState('overview');
const handle = (id) => {
setActive(id);
const el = document.getElementById(id);
if (el) {
const top = el.getBoundingClientRect().top + window.scrollY - 80;
window.scrollTo({ top, behavior: 'smooth' });
}
};
// observe scroll position to update active tab
React.useEffect(() => {
const sections = ['overview', 'tokens', 'components', 'assemblies', 'reference']
.map((id) => document.getElementById(id))
.filter(Boolean);
const onScroll = () => {
const y = window.scrollY + 160;
let cur = sections[0]?.id;
for (const s of sections) {
if (s.offsetTop <= y) cur = s.id;
}
setActive(cur);
};
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
return () => window.removeEventListener('scroll', onScroll);
}, []);
return (
<div>
<TabNav active={active} onChange={handle} />
<div style={{ maxWidth: 1280, margin: '0 auto', padding: '0 24px 80px' }}>
<OverviewSection />
<TokensSection />
<ComponentsSection />
<AssembliesSection />
<ReferenceSection />
</div>
</div>
);
}
window.RPT_DOCS = { KitDocs };