1import { memo } from "react";
2import { type PendingApproval } from "../../session-logic";
3import { cn } from "~/lib/utils";
4
5interface ComposerPendingApprovalPanelProps {
6 approval: PendingApproval;
7 pendingCount: number;
8 className?: string;
9}
10
11export const ComposerPendingApprovalPanel = memo(function ComposerPendingApprovalPanel({
12 approval,
13 pendingCount,
14 className,
15}: ComposerPendingApprovalPanelProps) {
16 const Detail = approval.requestKind === "mcp-elicitation" ? "span" : "code";
17 const fallbackLabel =
18 approval.requestKind === "mcp-elicitation"
19 ? "App access approval"
20 : approval.requestKind === "command"
21 ? "Command approval"
22 : approval.requestKind === "file-read"
23 ? "File read approval"
24 : approval.requestKind === "permission"
25 ? "App permission approval"
26 : "File change approval";
27 const detailAriaLabel =
28 approval.requestKind === "mcp-elicitation"
29 ? "App access request"
30 : approval.requestKind === "command"
31 ? "Command"
32 : approval.requestKind === "file-read"
33 ? "File to read"
34 : approval.requestKind === "permission"
35 ? "Permission request"
36 : "File change";
37
38 return (
39 <span
40 aria-label={fallbackLabel}
41 className={cn("flex min-w-0 flex-1 flex-col items-start gap-1", className)}
42 role="group"
43 >
44 <span className="flex w-full min-w-0 items-center gap-2 text-2xs text-muted-foreground">
45 <span className="shrink-0 font-medium text-warning">{fallbackLabel}</span>
46 {approval.appName ? <span className="min-w-0 truncate">{approval.appName}</span> : null}
47 {pendingCount > 1 ? (
48 <span className="ml-auto shrink-0 tabular-nums">1/{pendingCount}</span>
49 ) : null}
50 </span>
51 <Detail
52 aria-label={detailAriaLabel}
53 className={cn(
54 "block max-h-20 w-full min-w-0 overflow-auto text-xs text-foreground [scrollbar-width:thin] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70 [&::-webkit-scrollbar]:h-1.5",
55 approval.requestKind === "mcp-elicitation"
56 ? "whitespace-pre-wrap font-sans wrap-break-word"
57 : "whitespace-pre font-mono",
58 )}
59 data-approval-detail="complete"
60 tabIndex={0}
61 >
62 {approval.responseCapability === "not_resumable"
63 ? "Provider process is gone — interrupt or restart the run to respond."
64 : approval.detail || fallbackLabel}
65 </Detail>
66 </span>
67 );
68});