File
Blob: src/client/components/webhooks/delivery-list-dialog.tsx
| 1 | import type { WebhookSummary } from "@/contracts"; |
| 2 | import { ExternalLink, GitBranch, GitCommitHorizontal, History } from "lucide-react"; |
| 3 | import { Link } from "react-router-dom"; |
| 4 | import { Badge, Dialog, EmptyState } from "@/client/components/ui"; |
| 5 | import { formatRelativeTime } from "@/client/lib"; |
| 6 | import { DELIVERY_OUTCOME_META } from "@/client/components/webhooks/webhook-presentation"; |
| 7 | import { webhookProviderCatalog } from "@/lib/webhooks"; |
| 8 | |
| 9 | interface DeliveryListDialogProps { |
| 10 | open: boolean; |
| 11 | onClose: () => void; |
| 12 | webhook: WebhookSummary; |
| 13 | } |
| 14 | |
| 15 | export const DeliveryListDialog = ({ open, onClose, webhook }: DeliveryListDialogProps) => { |
| 16 | const catalog = webhookProviderCatalog[webhook.provider]; |
| 17 | const deliveries = webhook.recentDeliveries; |
| 18 | |
| 19 | return ( |
| 20 | <Dialog |
| 21 | open={open} |
| 22 | onClose={onClose} |
| 23 | title={`${catalog.displayName} Deliveries`} |
| 24 | description="Recent webhook deliveries (last 10)" |
| 25 | icon={<History className="h-5 w-5" />} |
| 26 | > |
| 27 | {deliveries.length === 0 ? ( |
| 28 | <EmptyState |
| 29 | icon={<History className="h-6 w-6" />} |
| 30 | title="No deliveries yet" |
| 31 | description="Deliveries will appear here once the provider sends a webhook." |
| 32 | /> |
| 33 | ) : ( |
| 34 | <div className="max-h-[60vh] space-y-2 overflow-y-auto"> |
| 35 | {deliveries.map((delivery) => { |
| 36 | const meta = DELIVERY_OUTCOME_META[delivery.outcome]; |
| 37 | const commitDisplay = delivery.commitSha ? delivery.commitSha.slice(0, 7) : null; |
| 38 | |
| 39 | return ( |
| 40 | <div key={delivery.deliveryId} className="rounded-xl border border-zinc-800/60 bg-zinc-900/50 p-3"> |
| 41 | <div className="flex flex-wrap items-center gap-2"> |
| 42 | <Badge variant={meta.variant}>{meta.label}</Badge> |
| 43 | <span className="text-sm text-zinc-300">{delivery.eventName}</span> |
| 44 | <span className="text-xs text-zinc-500">{formatRelativeTime(delivery.receivedAt)}</span> |
| 45 | </div> |
| 46 | |
| 47 | <div className="mt-1.5 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-zinc-500"> |
| 48 | {delivery.branch ? ( |
| 49 | <span className="inline-flex items-center gap-1"> |
| 50 | <GitBranch className="h-3 w-3" /> |
| 51 | {delivery.branch} |
| 52 | </span> |
| 53 | ) : null} |
| 54 | {commitDisplay ? ( |
| 55 | <span className="inline-flex items-center gap-1 font-mono"> |
| 56 | <GitCommitHorizontal className="h-3 w-3" /> |
| 57 | {commitDisplay} |
| 58 | </span> |
| 59 | ) : null} |
| 60 | {delivery.runId ? ( |
| 61 | <Link |
| 62 | to={`/app/runs/${delivery.runId}`} |
| 63 | className="inline-flex items-center gap-1 text-accent-400 hover:text-accent-300" |
| 64 | onClick={onClose} |
| 65 | > |
| 66 | <ExternalLink className="h-3 w-3" /> |
| 67 | View run |
| 68 | </Link> |
| 69 | ) : null} |
| 70 | </div> |
| 71 | </div> |
| 72 | ); |
| 73 | })} |
| 74 | </div> |
| 75 | )} |
| 76 | </Dialog> |
| 77 | ); |
| 78 | }; |