feat: complete catalog sensitivity enhancements

This commit is contained in:
Codex
2026-09-04 15:11:18 +02:00
parent b891246664
commit 7b1d69a65b
72 changed files with 33866 additions and 358 deletions
@@ -20,6 +20,26 @@ interface Props {
onSaved: (columns: CatalogColumn[]) => void;
}
function sensitivityReasonFor(
suggestion: SensitivityReviewItem,
sensitive: boolean,
): string | null {
if (!sensitive) return null;
if (suggestion.assessment !== "sensitive") {
return "Marked sensitive during human review despite a non-sensitive local assessment.";
}
const evidence = suggestion.evidence.map((item) => {
const confidence = item.confidence === undefined
? ""
: `, confidence ${Math.round(item.confidence * 100)}%`;
return item.label
? `${item.label} (${item.ruleId}${confidence})`
: `${item.ruleId}${confidence}`;
}).join(", ");
const coverage = suggestion.coverage.replaceAll("_", " ");
return `Local assessment: sensitive. Evidence: ${evidence || "policy match"}. Coverage: ${coverage}; observed values: ${suggestion.observedValues}.`;
}
export function SensitiveDataReviewDrawer({
open,
databaseId,
@@ -75,17 +95,22 @@ export function SensitiveDataReviewDrawer({
const save = async () => {
if (!databaseId || changed.length === 0) return;
setSaving(true);
const results = await Promise.allSettled(changed.map((suggestion) => (
updateCatalogColumnSensitive(
databaseId,
suggestion.tableId,
suggestion.columnId,
suggestion.version,
drafts[suggestion.columnId]!,
)
)));
const saved = results.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
const failed = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
const saved: CatalogColumn[] = [];
const failed: unknown[] = [];
for (const suggestion of changed) {
try {
saved.push(await updateCatalogColumnSensitive(
databaseId,
suggestion.tableId,
suggestion.columnId,
suggestion.version,
drafts[suggestion.columnId]!,
sensitivityReasonFor(suggestion, drafts[suggestion.columnId]!),
));
} catch (error) {
failed.push(error);
}
}
if (saved.length > 0) onSaved(saved);
if (failed.length > 0) {
toast.error(`${failed.length} sensitive flag${failed.length === 1 ? "" : "s"} could not be saved: ${apiErrorMessage(failed[0])}`);
@@ -115,7 +140,7 @@ export function SensitiveDataReviewDrawer({
<div className="flex gap-2">
<Button type="button" variant="outline" disabled={saving} onClick={close}>Cancel</Button>
<Button type="button" disabled={!canManage || saving || changed.length === 0} onClick={() => void save()}>
<Save />{saving ? "Saving…" : `Save ${changed.length}`}
<Save />{saving ? "Saving…" : `Save all ${changed.length} change${changed.length === 1 ? "" : "s"}`}
</Button>
</div>
</>