import { ArrowRight, ShieldCheck } from "lucide-react"; import type { ActivityEvent } from "@paperclipai/shared"; import { issueAuthorizationReasonLabel, readIssueChangeReceipt, } from "../lib/issue-change-receipt"; import { cn } from "../lib/utils"; /** * Field-level audit receipt under an `issue.updated` row in the activity stream * (the open cross-task write design (audit) — Dotta's hard requirement). * * Opening cross-issue writes means a task's fields can be changed by an agent * that does not own it. The board's answer to "who moved this, and were they * allowed to?" must be visible on the task itself, not only in the audit log — * so every PATCH, agent *and* human, shows what changed, the responsible user * behind it, and the authorization reason that let it through. * * Renders nothing when the event carries no receipt, so pre-receipt activity * rows are unaffected. */ export function IssueFieldChangeReceipt({ event, resolveAgentLabel, resolveUserLabel, className, }: { event: Pick; resolveAgentLabel?: (agentId: string) => string | null | undefined; resolveUserLabel?: (userId: string) => string | null | undefined; className?: string; }) { const rows = readIssueChangeReceipt(event.details, { resolveAgentLabel, resolveUserLabel }); const reason = issueAuthorizationReasonLabel( typeof event.details?.authorizationReason === "string" ? event.details.authorizationReason : null, ); const responsibleUserName = event.responsibleUserId ? resolveUserLabel?.(event.responsibleUserId) ?? null : null; if (rows.length === 0 && !reason) return null; return (
{rows.length > 0 ? (
{rows.map((row) => (
{row.label}
{row.from}
))}
) : null} {reason ? ( // Inline flow, not flex: as separate flex items the icon wraps onto its // own line and orphans above the reason at narrow widths. Inline keeps it // glued to the first word.

) : null}
); }