style: unify workbench typography and prepare isolated visual review

This commit is contained in:
Codex
2026-09-12 22:51:58 +02:00
parent 2d1b714ebe
commit c8d276ddc6
64 changed files with 942 additions and 318 deletions
@@ -371,20 +371,20 @@ export function CatalogSyncDrawer({
key={phase}
aria-current={current ? "step" : undefined}
aria-label={`${label}, ${status}`}
className={`flex items-center gap-2 text-xs ${failedOutcome ? "font-semibold text-destructive" : interruptedOutcome ? "font-semibold text-amber-600" : terminalOutcome || current ? "font-semibold text-foreground" : "text-muted-foreground"}`}
className={`flex items-center gap-2 text-xs ${failedOutcome ? "font-semibold text-destructive" : interruptedOutcome ? "font-semibold text-warning" : terminalOutcome || current ? "font-semibold text-foreground" : "text-muted-foreground"}`}
>
{confirmationSkipped ? (
<Minus aria-hidden="true" className="size-3.5 text-muted-foreground" />
) : failedOutcome ? (
<X aria-hidden="true" className="size-3.5 text-destructive" />
) : interruptedOutcome ? (
<AlertTriangle aria-hidden="true" className="size-3.5 text-amber-600" />
<AlertTriangle aria-hidden="true" className="size-3.5 text-warning" />
) : terminalOutcome ? (
<Minus aria-hidden="true" className="size-3.5 text-muted-foreground" />
) : complete ? (
<CheckCircle2 aria-hidden="true" className="size-3.5 text-[oklch(var(--success))]" />
) : current ? (
<LoaderCircle aria-hidden="true" className="size-3.5 animate-spin text-amber-600" />
<LoaderCircle aria-hidden="true" className="size-3.5 animate-spin text-warning" />
) : (
<Circle aria-hidden="true" className="size-3.5" />
)}
@@ -398,16 +398,16 @@ export function CatalogSyncDrawer({
<div className="mt-5 grid grid-cols-3 gap-2">
{(["tables", "columns", "relationships"] as const).map((name) => (
<div key={name} className="rounded-md border border-border bg-muted/25 px-3 py-2">
<p className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">{name}</p>
<p className="text-xs font-semibold text-muted-foreground">{name}</p>
<p className="mt-1 text-lg font-semibold tabular-nums">{run.counts[name] ?? ""}</p>
</div>
))}
</div>
{run.state === "awaiting_confirmation" && run.plannedDiff ? (
<section className="mt-5 rounded-md border border-amber-500/50 bg-amber-500/8 p-4" aria-label="Destructive changes">
<section className="mt-5 rounded-md border border-warning/50 bg-warning/8 p-4" aria-label="Destructive changes">
<div className="flex gap-3">
<AlertTriangle className="mt-0.5 size-5 shrink-0 text-amber-600" />
<AlertTriangle className="mt-0.5 size-5 shrink-0 text-warning" />
<div>
<h3 className="font-semibold">Confirm {deletionCount} removals</h3>
<p className="mt-1 text-sm text-muted-foreground">The database will be scanned again before anything is removed.</p>
@@ -453,7 +453,7 @@ export function CatalogSyncDrawer({
className="thot-catalog-drawer__event-log max-h-64 overflow-y-auto rounded-md bg-zinc-950 p-3 font-mono text-xs leading-5 text-zinc-200"
>
{events.length === 0 ? <p className="text-zinc-500">Waiting for events…</p> : events.map((event) => (
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-amber-300" : undefined}>
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-warning" : undefined}>
<span className="mr-2 text-zinc-500">{new Date(event.createdAt).toLocaleTimeString()}</span>{event.message}
</p>
))}
@@ -516,8 +516,8 @@ export function DatabaseColumns({
<h3 className="mt-1 font-heading text-2xl font-semibold">{active.name}</h3>
<p className="mt-1 text-sm text-muted-foreground">Physical schema fields are read-only. Review fields can be edited.</p>
{stale ? (
staleBannerOpen ? <div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
staleBannerOpen ? <div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
) : null}
<ColumnMetadataFieldMatrix
column={active}
@@ -652,8 +652,8 @@ export function DatabaseColumns({
<p className="thot-label">{table.name} · column</p>
<h3 className="mt-1 break-words font-heading text-xl font-semibold">{active.name}</h3>
{stale ? (
staleBannerOpen ? <div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
staleBannerOpen ? <div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
) : null}
<ColumnMetadataFieldMatrix
column={active}
@@ -220,7 +220,7 @@ export function DatabaseForm({
{stale ? (
staleBannerOpen ? (
<div className="rounded-md border border-amber-300/70 bg-amber-50 p-4 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-100" role="alert">
<div className="rounded-md border border-warning/70 bg-warning p-4 text-sm text-warning dark:border-warning dark:bg-warning/30 text-warning" role="alert">
<p className="font-semibold">A newer database configuration is available.</p>
<p className="mt-1 leading-5">Reload the latest values before saving, testing, or deleting. Your draft is still intact.</p>
<div className="mt-3 flex flex-wrap gap-2">
@@ -233,14 +233,14 @@ export function DatabaseForm({
</div>
</div>
) : (
<div className="rounded-md border border-amber-300/70 bg-amber-50 px-4 py-3 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-100" role="status">
<div className="rounded-md border border-warning/70 bg-warning px-4 py-3 text-sm text-warning dark:border-warning dark:bg-warning/30 text-warning" role="status">
Reload the latest values before this configuration can be changed.
</div>
)
) : null}
{partialSecretFailure ? (
<div className="rounded-md border border-amber-300/70 bg-amber-50 p-4 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-100" role="alert">
<div className="rounded-md border border-warning/70 bg-warning p-4 text-sm text-warning dark:border-warning dark:bg-warning/30 text-warning" role="alert">
<p className="font-semibold">Database configuration saved; secret update could not be confirmed.</p>
<p className="mt-1 leading-5">{partialSecretFailure} The values you entered are retained in this form.</p>
<Button type="button" size="sm" variant="outline" className="mt-3" disabled={busy || stale} onClick={onRetrySecrets}>
@@ -102,9 +102,9 @@ type StateTone = "neutral" | "info" | "success" | "warning" | "danger";
const stateToneClass: Record<StateTone, string> = {
neutral: "bg-muted-foreground/55",
info: "bg-sky-500",
success: "bg-emerald-500",
warning: "bg-amber-500",
info: "bg-muted-foreground/55",
success: "bg-success",
warning: "bg-warning",
danger: "bg-destructive",
};
@@ -125,7 +125,7 @@ function StateCell({
<span className={`size-1.5 shrink-0 rounded-full ${stateToneClass[tone]}`} aria-hidden="true" />
<span className="truncate">{label}</span>
</span>
<span className={`truncate pl-3 text-[11px] ${detailClassName}`}>{detail}</span>
<span className={`truncate pl-3 text-xs ${detailClassName}`}>{detail}</span>
</div>
);
}
@@ -621,7 +621,7 @@ export function DatabaseGrid({
<p
role="note"
aria-label="Metadata generation source data disclosure"
className="mt-1 text-xs font-medium text-amber-800 dark:text-amber-300"
className="mt-1 text-xs font-medium text-warning"
>
When available, up to five real source rows and five representative values from
columns not marked sensitive are sent to the selected provider.
@@ -586,7 +586,7 @@ export function DatabaseRelationships({
<dt className="thot-label">Column mapping</dt>
<dd className="mt-2 overflow-hidden rounded-md border border-border">
<table className="w-full text-left text-xs">
<thead className="bg-muted/60 font-mono uppercase tracking-wide text-muted-foreground"><tr><th className="px-3 py-2">Source</th><th className="px-3 py-2">Target</th></tr></thead>
<thead className="bg-muted/60 font-sans text-muted-foreground"><tr><th className="px-3 py-2">Source</th><th className="px-3 py-2">Target</th></tr></thead>
<tbody>{activeRelationship.columns.map((pair) => <tr key={`${pair.sourceColumnName}:${pair.targetColumnName}`} className="border-t border-border"><td className="px-3 py-2 font-mono">{pair.sourceColumnName}</td><td className="px-3 py-2 font-mono">{pair.targetColumnName}</td></tr>)}</tbody>
</table>
</dd>
@@ -599,12 +599,12 @@ export function DatabaseTables({
<h3 className="mt-1 break-words font-heading text-xl font-semibold">{activeTable.name}</h3>
{stale ? (
staleBannerOpen ? (
<div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm">
<div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm">
<p className="font-semibold">A newer table description is available.</p>
<p className="mt-1 text-muted-foreground">Your draft is preserved until you reload the current metadata.</p>
<div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div>
</div>
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
) : null}
<div className="mt-5 grid gap-4">
<label className="grid gap-1.5 text-sm font-semibold">Physical table name<input className="h-9 rounded-md border border-input bg-muted/35 px-3 font-mono text-xs" value={activeTable.name} readOnly /></label>
@@ -650,12 +650,12 @@ export function DatabaseTables({
<p className="text-sm text-muted-foreground">Only review metadata can be changed.</p>
{stale ? (
staleBannerOpen ? (
<div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm">
<div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm">
<p className="font-semibold">A newer table description is available.</p>
<p className="mt-1 text-muted-foreground">Your draft is preserved until you reload the current metadata.</p>
<div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div>
</div>
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
) : null}
<div className="mt-5 grid gap-4">
<label className="grid gap-1.5 text-sm font-semibold">Physical table name<input className="h-9 rounded-md border border-input bg-muted/35 px-3 font-mono text-xs" value={activeTable.name} readOnly /></label>
@@ -327,7 +327,7 @@ export function DescriptionGenerationDrawer({
{apparentlyStale ? (
<p
id="description-generation-unlock-help"
className="mb-3 rounded-md border border-amber-500/35 bg-amber-500/8 px-3 py-2 text-xs leading-5 text-muted-foreground"
className="mb-3 rounded-md border border-warning/35 bg-warning/8 px-3 py-2 text-xs leading-5 text-muted-foreground"
>
Unlock interrupts apparently stale work and marks the run interrupted. A live worker will prevent it.
</p>
@@ -411,7 +411,7 @@ export function DescriptionGenerationDrawer({
<thead>
<tr className="border-b border-border bg-muted/45">
{progressCounters.map(([name, label]) => (
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-[10px] font-semibold uppercase tracking-wide text-muted-foreground first:border-l-0">
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground first:border-l-0">
{label}
</th>
))}
@@ -458,7 +458,7 @@ export function DescriptionGenerationDrawer({
className="thot-catalog-drawer__event-log overflow-y-auto rounded-md bg-zinc-950 p-3 font-mono text-xs leading-5 text-zinc-200"
>
{events.length === 0 ? <p className="text-zinc-500">Waiting for events…</p> : events.map((event) => (
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-amber-300" : undefined}>
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-warning" : undefined}>
<span className="mr-2 text-zinc-500">{new Date(event.createdAt).toLocaleTimeString()}</span>{event.message}
</p>
))}
@@ -25,7 +25,7 @@ test("uses operational body text for every available-command list", () => {
}
expect(styles).toMatch(
/\.thot-fleet-action-selector__select\s*\{[^}]*font-size:\s*0\.9375rem;/s,
/\.thot-fleet-action-selector__select\s*\{[^}]*font-size:\s*var\(--text-control\);/s,
);
expect(styles).toMatch(
/\.thot-fleet-action-selector\s*\{[^}]*flex:\s*0 0 auto;/s,
@@ -54,12 +54,12 @@
.thot-fleet-ledger__kpi-label {
margin: 0;
color: oklch(var(--muted-foreground));
font-family: var(--font-mono);
font-size: 0.6875rem;
font-weight: 700;
letter-spacing: 0.08em;
font-family: var(--font-sans);
font-size: var(--text-meta);
font-weight: 600;
letter-spacing: normal;
line-height: 1.35;
text-transform: uppercase;
text-transform: none;
}
.thot-fleet-ledger__title,
@@ -75,7 +75,7 @@
margin: 0;
font-family: var(--font-sans);
font-size: 1rem;
font-weight: 700;
font-weight: 600;
letter-spacing: -0.0125em;
line-height: 1.25;
white-space: nowrap;
@@ -85,7 +85,7 @@
max-width: 68ch;
margin: 0.45rem 0 0;
color: oklch(var(--muted-foreground));
font-size: 0.875rem;
font-size: var(--text-control);
line-height: 1.55;
}
@@ -191,15 +191,15 @@
.thot-fleet-ledger__status-label {
grid-column: 1 / -1;
font-size: 0.625rem;
font-size: var(--text-meta);
}
.thot-fleet-ledger__status-value {
overflow: hidden;
color: oklch(var(--foreground));
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 700;
font-family: var(--font-sans);
font-size: var(--text-meta);
font-weight: 600;
line-height: 1.45;
text-overflow: ellipsis;
white-space: nowrap;
@@ -208,7 +208,7 @@
.thot-fleet-ledger__status-detail {
overflow: hidden;
color: oklch(var(--muted-foreground));
font-size: 0.75rem;
font-size: var(--text-meta);
line-height: 1.45;
text-overflow: ellipsis;
white-space: nowrap;
@@ -224,18 +224,17 @@
.thot-fleet-ledger__kpi-strip {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
grid-template-columns: repeat(auto-fit, minmax(min(100%, 6rem), 1fr));
margin: 0;
}
.thot-fleet-ledger__kpi {
min-width: 0;
padding: 0 1rem 0.75rem 0;
padding: 0 0.75rem 0.75rem 0;
}
.thot-fleet-ledger__kpi + .thot-fleet-ledger__kpi {
padding-left: 1rem;
border-left: 1px solid oklch(var(--border));
padding-left: 0;
}
.thot-fleet-ledger__kpi-value,
@@ -246,18 +245,18 @@
.thot-fleet-ledger__kpi-value {
margin-top: 0.2rem;
color: oklch(var(--foreground));
font-family: var(--font-mono);
font-size: clamp(1.25rem, 2vw, 1.625rem);
font-family: var(--font-sans);
font-size: var(--text-body);
font-variant-numeric: tabular-nums;
font-weight: 700;
letter-spacing: -0.035em;
font-weight: 600;
letter-spacing: normal;
line-height: 1.2;
}
.thot-fleet-ledger__kpi-detail {
margin-top: 0.15rem;
color: oklch(var(--muted-foreground));
font-size: 0.75rem;
font-size: var(--text-meta);
line-height: 1.4;
}
@@ -280,7 +279,7 @@
color: oklch(var(--primary));
background: oklch(var(--primary) / 0.08);
box-shadow: 0 1px 2px oklch(var(--primary) / 0.1);
font-weight: 700;
font-weight: 600;
}
.thot-fleet-back-action:not(:disabled):hover {
@@ -326,7 +325,7 @@
color: oklch(var(--muted-foreground));
background: transparent;
font: inherit;
font-size: 0.8125rem;
font-size: var(--text-control);
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
@@ -346,8 +345,8 @@
max-width: 18rem;
overflow: hidden;
color: oklch(var(--foreground));
font-size: 0.8125rem;
font-weight: 650;
font-size: var(--text-control);
font-weight: 600;
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -392,14 +391,14 @@
display: grid;
min-width: 7.5rem;
color: oklch(var(--foreground));
font-family: var(--font-mono);
font-size: 0.6875rem;
font-family: var(--font-sans);
font-size: var(--text-meta);
line-height: 1.35;
}
.thot-fleet-action-selector__scope span {
color: oklch(var(--muted-foreground));
font-size: 0.625rem;
font-size: var(--text-meta);
}
.thot-fleet-action-selector__select {
@@ -413,7 +412,7 @@
border-radius: var(--radius);
color: oklch(var(--foreground));
background: oklch(var(--background));
font-size: 0.9375rem;
font-size: var(--text-control);
outline: none;
}
@@ -430,7 +429,7 @@
.thot-fleet-action-selector__reason {
flex-basis: 100%;
color: oklch(var(--muted-foreground));
font-size: 0.75rem;
font-size: var(--text-meta);
line-height: 1.4;
}
@@ -438,9 +437,9 @@
min-width: 0;
overflow: hidden;
color: oklch(var(--muted-foreground));
font-family: var(--font-mono);
font-size: 0.6875rem;
letter-spacing: 0.025em;
font-family: var(--font-sans);
font-size: var(--text-meta);
letter-spacing: normal;
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -628,10 +627,10 @@
}
.thot-fleet-ledger-grid .ag-header-cell-text {
font-family: var(--font-mono);
font-size: 0.6875rem;
letter-spacing: 0.055em;
text-transform: uppercase;
font-family: var(--font-sans);
font-size: var(--text-meta);
letter-spacing: normal;
text-transform: none;
}
.thot-fleet-ledger-grid .ag-row {
@@ -647,7 +646,8 @@
.thot-fleet-ledger-grid .ag-row.ag-row-selected .ag-cell,
.thot-fleet-ledger-grid .ag-row.ag-row-selected .ag-grid-pinned-left-cells,
.thot-fleet-ledger-grid .ag-row.ag-row-selected .ag-grid-pinned-right-cells {
background-color: oklch(93% 0.002 17.2) !important;
background-color: oklch(var(--nav-active)) !important;
color: oklch(var(--nav-active-foreground));
}
.thot-fleet-icon-action {
@@ -672,7 +672,7 @@
background: oklch(24% 0.014 258);
box-shadow: 0 8px 20px -10px oklch(12% 0.02 258 / 0.72);
content: attr(data-tooltip);
font-size: 0.6875rem;
font-size: var(--text-meta);
font-weight: 600;
line-height: 1.25;
text-align: center;
@@ -701,8 +701,8 @@
background: oklch(var(--popover));
box-shadow: var(--shadow-sm);
content: attr(data-tooltip);
font-size: 0.6875rem;
font-weight: 650;
font-size: var(--text-meta);
font-weight: 600;
line-height: 1.2;
opacity: 0;
pointer-events: none;
@@ -765,7 +765,7 @@
}
.thot-fleet-ledger__drawer-title {
font-size: 1.35rem;
font-size: var(--text-section);
line-height: 1.18;
}
@@ -949,19 +949,6 @@
min-height: 28rem;
}
.thot-fleet-ledger__kpi-strip {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.thot-fleet-ledger__kpi:nth-child(odd) {
padding-left: 0;
border-left: 0;
}
.thot-fleet-ledger__kpi:nth-child(n + 3) {
padding-top: 0.75rem;
border-top: 1px solid oklch(var(--border));
}
.thot-fleet-ledger__navigation {
flex-wrap: wrap;
@@ -180,7 +180,7 @@ export interface FleetLedgerKpiStripProps extends WithClassName {
}
export function FleetLedgerKpiStrip({
title = "Fleet summary",
title = "Catalog summary",
items,
className,
}: FleetLedgerKpiStripProps) {
@@ -211,7 +211,7 @@ export function SensitiveDataReviewDrawer({
: "no sensitive match"}. Coverage: {suggestion.coverage.replace("_", " ")}. Observed values: {suggestion.observedValues}.
</p>
</div>
<span className={`rounded px-2 py-0.5 text-[11px] font-semibold ${changedFromCurrent ? "bg-amber-500/12 text-amber-800 dark:text-amber-300" : "bg-muted text-muted-foreground"}`}>
<span className={`rounded px-2 py-0.5 text-xs font-semibold ${changedFromCurrent ? "bg-warning/12 text-warning" : "bg-muted text-muted-foreground"}`}>
{changedFromCurrent ? "Change" : "No change"}
</span>
</li>
@@ -268,7 +268,7 @@ export function SensitivityAnalysisHistoryDrawer({
<thead>
<tr className="border-b border-border bg-muted/45">
{progressCounters.map(([name, label]) => (
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-[10px] font-semibold uppercase tracking-wide text-muted-foreground first:border-l-0">
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground first:border-l-0">
{label}
</th>
))}
@@ -320,7 +320,7 @@ export function SensitivityAnalysisHistoryDrawer({
className="thot-catalog-drawer__event-log overflow-y-auto rounded-md bg-zinc-950 p-3 font-mono text-xs leading-5 text-zinc-200"
>
{events.length === 0 ? <p className="text-zinc-500">Waiting for events…</p> : events.map((event) => (
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-amber-300" : undefined}>
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-warning" : undefined}>
<span className="mr-2 text-zinc-500">{new Date(event.createdAt).toLocaleTimeString()}</span>{event.message}
</p>
))}