85 lines
3.4 KiB
TypeScript
85 lines
3.4 KiB
TypeScript
import { useState } from "react";
|
|
import { ChevronDown, ChevronUp, Loader2, Lock } from "lucide-react";
|
|
import type { DataClassification } from "../../types/models";
|
|
|
|
// ── Options ────────────────────────────────────────────────────────
|
|
|
|
const CLASSIFICATION_OPTIONS: { value: DataClassification; label: string; color: string }[] = [
|
|
{ value: "public_release", label: "Public Release", color: "border-gray-500/30 bg-gray-800/50 text-gray-400" },
|
|
{ value: "general_use", label: "General Use", color: "border-blue-500/30 bg-blue-900/30 text-blue-400" },
|
|
{ value: "confidential", label: "Confidential", color: "border-amber-500/30 bg-amber-900/30 text-amber-400" },
|
|
{ value: "restricted", label: "Restricted", color: "border-red-500/30 bg-red-900/30 text-red-400" },
|
|
];
|
|
|
|
// ── Props ──────────────────────────────────────────────────────────
|
|
|
|
interface DataClassificationBadgeProps {
|
|
value: DataClassification;
|
|
canEdit: boolean;
|
|
isSaving: boolean;
|
|
onChange: (value: DataClassification) => void;
|
|
}
|
|
|
|
// ── Component ──────────────────────────────────────────────────────
|
|
|
|
export default function DataClassificationBadge({
|
|
value,
|
|
canEdit,
|
|
isSaving,
|
|
onChange,
|
|
}: DataClassificationBadgeProps) {
|
|
const [expanded, setExpanded] = useState(false);
|
|
const current = CLASSIFICATION_OPTIONS.find((o) => o.value === value) ?? CLASSIFICATION_OPTIONS[1];
|
|
|
|
if (!canEdit) {
|
|
return (
|
|
<span
|
|
className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-medium ${current.color}`}
|
|
>
|
|
<Lock className="h-2.5 w-2.5" />
|
|
{current.label}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="relative inline-block">
|
|
<button
|
|
onClick={() => setExpanded((v) => !v)}
|
|
className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors hover:opacity-80 ${current.color}`}
|
|
>
|
|
<Lock className="h-2.5 w-2.5" />
|
|
{current.label}
|
|
{expanded ? <ChevronUp className="h-2.5 w-2.5" /> : <ChevronDown className="h-2.5 w-2.5" />}
|
|
</button>
|
|
|
|
{expanded && (
|
|
<div className="absolute left-0 top-full z-20 mt-1 w-44 rounded-lg border border-gray-700 bg-gray-900 p-1.5 shadow-xl">
|
|
{isSaving ? (
|
|
<div className="flex items-center justify-center py-2">
|
|
<Loader2 className="h-4 w-4 animate-spin text-gray-500" />
|
|
</div>
|
|
) : (
|
|
CLASSIFICATION_OPTIONS.map((opt) => (
|
|
<button
|
|
key={opt.value}
|
|
onClick={() => {
|
|
onChange(opt.value);
|
|
setExpanded(false);
|
|
}}
|
|
className={`block w-full rounded px-2 py-1.5 text-left text-xs transition-colors ${
|
|
opt.value === value
|
|
? "bg-gray-800 text-white"
|
|
: "text-gray-400 hover:bg-gray-800 hover:text-white"
|
|
}`}
|
|
>
|
|
{opt.label}
|
|
</button>
|
|
))
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|