feat(awooop): show source flow in approvals
This commit is contained in:
@@ -208,6 +208,65 @@ function RemediationEvidenceCell({ summary }: { summary?: RemediationSummary | n
|
||||
);
|
||||
}
|
||||
|
||||
type ApprovalSourceFlowStatus = "verified" | "applied" | "evidence" | "provider" | "waiting";
|
||||
|
||||
function approvalSourceFlowStatus(chain?: AwoooPStatusChain | null): ApprovalSourceFlowStatus {
|
||||
const correlation = chain?.source_refs?.correlation;
|
||||
if (!correlation) return "waiting";
|
||||
|
||||
const verificationStatus = String(correlation.verification_status ?? correlation.status ?? "missing");
|
||||
if (verificationStatus === "applied_link_verified" || verificationStatus === "direct_ref_verified") {
|
||||
return "verified";
|
||||
}
|
||||
if ((correlation.applied_link_total ?? 0) > 0) return "applied";
|
||||
if ((correlation.direct_ref_total ?? 0) > 0 || (correlation.candidate_total ?? 0) > 0) {
|
||||
return "evidence";
|
||||
}
|
||||
if ((correlation.provider_event_total ?? 0) > 0) return "provider";
|
||||
return "waiting";
|
||||
}
|
||||
|
||||
function approvalSourceFlowClass(status: ApprovalSourceFlowStatus) {
|
||||
if (status === "verified") return "border-[#9bc7a4] bg-[#f0faf2] text-[#17602a]";
|
||||
if (status === "applied" || status === "evidence") return "border-[#9bb6d9] bg-[#eef5ff] text-[#1f5b9b]";
|
||||
if (status === "provider") return "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]";
|
||||
return "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]";
|
||||
}
|
||||
|
||||
function ApprovalSourceFlowCell({ chain }: { chain?: AwoooPStatusChain | null }) {
|
||||
const t = useTranslations("awooop.listEvidence.sourceFlow");
|
||||
const status = approvalSourceFlowStatus(chain);
|
||||
const correlation = chain?.source_refs?.correlation;
|
||||
const detail = t("detail", {
|
||||
providers: correlation?.provider_event_total ?? 0,
|
||||
direct: correlation?.direct_ref_total ?? 0,
|
||||
candidate: correlation?.candidate_total ?? 0,
|
||||
applied: correlation?.applied_link_total ?? 0,
|
||||
});
|
||||
const Icon = status === "verified" || status === "applied"
|
||||
? ShieldCheck
|
||||
: status === "waiting"
|
||||
? AlertCircle
|
||||
: SearchCheck;
|
||||
|
||||
return (
|
||||
<div className="min-w-[190px]">
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1.5 border px-2 py-1 text-xs font-semibold",
|
||||
approvalSourceFlowClass(status)
|
||||
)}
|
||||
>
|
||||
<Icon className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
{t(`statuses.${status}`)}
|
||||
</span>
|
||||
<p className="mt-1 truncate font-mono text-xs text-[#77736a]" title={detail}>
|
||||
{detail}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TimeoutCell({ timeoutAt }: { timeoutAt: string | null }) {
|
||||
const [remaining, setRemaining] = useState<number | null>(
|
||||
getRemainingMs(timeoutAt)
|
||||
@@ -299,6 +358,9 @@ function ApprovalRow({ approval }: { approval: Approval }) {
|
||||
<td className="px-4 py-3">
|
||||
<RemediationEvidenceCell summary={approval.remediation_summary} />
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<ApprovalSourceFlowCell chain={approval.awooop_status_chain} />
|
||||
</td>
|
||||
<td className="min-w-[280px] px-4 py-3">
|
||||
<AwoooPStatusChainPanel chain={approval.awooop_status_chain} compact />
|
||||
</td>
|
||||
@@ -563,6 +625,9 @@ export default function ApprovalsPage() {
|
||||
<th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
{tEvidence("column")}
|
||||
</th>
|
||||
<th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
{tEvidence("sourceFlow.column")}
|
||||
</th>
|
||||
<th className="text-left px-4 py-3 text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
||||
{tStatusChain("title")}
|
||||
</th>
|
||||
@@ -578,7 +643,7 @@ export default function ApprovalsPage() {
|
||||
{loading ? (
|
||||
Array.from({ length: 5 }).map((_, i) => (
|
||||
<tr key={i} className="border-b border-border">
|
||||
{Array.from({ length: 8 }).map((_, j) => (
|
||||
{Array.from({ length: 9 }).map((_, j) => (
|
||||
<td key={j} className="px-4 py-3">
|
||||
<div className="h-5 bg-muted animate-pulse rounded w-20" />
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user