Files
supabase/apps/studio/components/interfaces/Platform/Webhooks/PlatformWebhooksDeliveryDetailsSheet.tsx
Danny White df55c5c327 feat(studio): platform webhooks scaffolding (#43276)
## What kind of change does this PR introduce?

Impending feature addition. Resolves DEPR-340.

## What is the current behavior?

We don’t have any platform webhook support.

## What is the new behavior?

This puts the scaffolding for platform webhooks **behind a feature
flag**. The content is currently UI-only (with mock data and a
[temporary tracking
file](https://github.com/supabase/supabase/blob/8adadc61f57c70b686a0f5f05e9f7f05837e0466/apps/studio/components/interfaces/Platform/Webhooks/DEPR-340-backend-integration-tracker.md)).

Merging this in lets us work incrementally from here on.
2026-03-06 02:56:54 +00:00

188 lines
7.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Copy } from 'lucide-react'
import { getStatusLevel } from 'components/interfaces/UnifiedLogs/UnifiedLogs.utils'
import { DataTableColumnStatusCode } from 'components/ui/DataTable/DataTableColumn/DataTableColumnStatusCode'
import {
AlertDialog,
Badge,
Button,
Card,
CardContent,
Separator,
Sheet,
SheetContent,
SheetHeader,
SheetSection,
SheetTitle,
Tabs_Shadcn_ as Tabs,
TabsContent_Shadcn_ as TabsContent,
TabsList_Shadcn_ as TabsList,
TabsTrigger_Shadcn_ as TabsTrigger,
} from 'ui'
import { TimestampInfo } from 'ui-patterns'
import type { WebhookDelivery } from './PlatformWebhooks.types'
import { formatDeliveryStatus, statusBadgeVariant } from './PlatformWebhooksView.utils'
interface PlatformWebhooksDeliveryDetailsSheetProps {
deliveryAttempt: number | null
deliveryDetailsTab: 'event' | 'response'
deliveryEventPayload: string
deliveryResponsePayload: string
open: boolean
selectedDelivery: WebhookDelivery | null
onCopy: (value: string, label: string) => void
onOpenChange: (open: boolean) => void
onTabChange: (tab: 'event' | 'response') => void
}
export const PlatformWebhooksDeliveryDetailsSheet = ({
deliveryAttempt,
deliveryDetailsTab,
deliveryEventPayload,
deliveryResponsePayload,
open,
selectedDelivery,
onCopy,
onOpenChange,
onTabChange,
}: PlatformWebhooksDeliveryDetailsSheetProps) => {
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent size="default" className="flex flex-col gap-0">
<SheetHeader>
<div className="flex items-center gap-2">
<SheetTitle>Delivery details</SheetTitle>
{selectedDelivery && (
<Badge variant={statusBadgeVariant[selectedDelivery.status]}>
{formatDeliveryStatus(selectedDelivery.status)}
</Badge>
)}
</div>
</SheetHeader>
<Separator />
{selectedDelivery && (
<SheetSection className="overflow-auto flex-grow px-0 py-0">
<div className="space-y-6 p-5">
<Card>
<CardContent className="grid grid-cols-1 gap-4 p-4 @md:grid-cols-2">
<div className="space-y-1">
<p className="text-sm text-foreground-light">Delivery ID</p>
<code className="text-code-inline">{selectedDelivery.id}</code>
</div>
<div className="space-y-1">
<p className="text-sm text-foreground-light">Attempt</p>
<p className="text-sm text-foreground">
{deliveryAttempt ? `#${deliveryAttempt}` : '-'}
</p>
</div>
<div className="space-y-1">
<p className="text-sm text-foreground-light">Timestamp</p>
<TimestampInfo className="text-sm" utcTimestamp={selectedDelivery.attemptAt} />
</div>
<div className="space-y-1">
<p className="text-sm text-foreground-light">Response code</p>
{selectedDelivery.responseCode ? (
<DataTableColumnStatusCode
value={selectedDelivery.responseCode}
level={getStatusLevel(selectedDelivery.responseCode)}
className="text-xs"
/>
) : (
<span className="text-xs text-foreground-muted">–</span>
)}
</div>
</CardContent>
</Card>
<Tabs
value={deliveryDetailsTab}
onValueChange={(value) => onTabChange(value as 'event' | 'response')}
>
<TabsList className="w-full">
<TabsTrigger value="event" className="flex-1">
Event
</TabsTrigger>
<TabsTrigger value="response" className="flex-1">
Response
</TabsTrigger>
</TabsList>
<TabsContent value="event" className="space-y-4 pt-4">
<div className="space-y-1">
<p className="text-sm text-foreground-light">Event type</p>
<code className="text-code-inline">{selectedDelivery.eventType}</code>
</div>
<div className="space-y-1">
<p className="text-sm text-foreground-light">Event ID</p>
<code className="text-code-inline">{selectedDelivery.id}</code>
</div>
<div className="space-y-1">
<p className="text-sm text-foreground-light">Event timestamp</p>
<TimestampInfo className="text-sm" utcTimestamp={selectedDelivery.attemptAt} />
</div>
<div className="space-y-2">
<div className="flex items-center justify-between gap-2">
<p className="text-sm text-foreground-light">Payload</p>
<Button
type="text"
icon={<Copy size={14} />}
onClick={() => onCopy(deliveryEventPayload, 'event payload')}
>
Copy
</Button>
</div>
<div className="rounded-md border border-default bg-surface-200 p-3">
<pre className="whitespace-pre-wrap text-xs text-foreground">
{deliveryEventPayload}
</pre>
</div>
</div>
</TabsContent>
<TabsContent value="response" className="space-y-4 pt-4">
<div className="space-y-1">
<p className="text-sm text-foreground-light">Status</p>
<Badge variant={statusBadgeVariant[selectedDelivery.status]}>
{formatDeliveryStatus(selectedDelivery.status)}
</Badge>
</div>
<div className="space-y-1">
<p className="text-sm text-foreground-light">Response code</p>
{selectedDelivery.responseCode ? (
<DataTableColumnStatusCode
value={selectedDelivery.responseCode}
level={getStatusLevel(selectedDelivery.responseCode)}
className="text-xs"
/>
) : (
<span className="text-xs text-foreground-muted">–</span>
)}
</div>
<div className="space-y-2">
<div className="flex items-center justify-between gap-2">
<p className="text-sm text-foreground-light">Response payload</p>
<Button
type="text"
icon={<Copy size={14} />}
onClick={() => onCopy(deliveryResponsePayload, 'response payload')}
>
Copy
</Button>
</div>
<div className="rounded-md border border-default bg-surface-200 p-3">
<pre className="whitespace-pre-wrap text-xs text-foreground">
{deliveryResponsePayload}
</pre>
</div>
</div>
</TabsContent>
</Tabs>
</div>
</SheetSection>
)}
</SheetContent>
</Sheet>
)
}