mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
chore(studio): webhooks UI cleanup (#43797)
## What kind of change does this PR introduce? UI updates to platform webhooks. ## What is the new behavior? - `Webhooks` icon on empty state - Better text wrapping/overflow handling on table - Clearer endpoint deletion dialog | After | | --- | | <img width="1024" height="563" alt="Webhooks Toolshed Supabase-A3AF1CE1-B489-450F-9FD7-AE1B1BC0C999" src="https://github.com/user-attachments/assets/6606922d-fd39-400e-bc2d-99806755fc09" /> | | <img width="1024" height="563" alt="Webhooks Toolshed Supabase-00EF8F02-A3F2-477C-ADDB-68996D6C16E3" src="https://github.com/user-attachments/assets/705a1d78-4366-4ea4-b538-99eb368a3997" /> | | <img width="1024" height="563" alt="Webhooks Toolshed Supabase-902AC0EC-D0D2-471A-B241-C90FA8F50883" src="https://github.com/user-attachments/assets/97ff1267-b31b-442f-ad14-62b0bd24ac46" /> |
This commit is contained in:
1 parent
9da28685ec
commit
10e9cdd1f4
4 files changed
+29
-27
No files matched your search
@@ -30,7 +30,7 @@ export const PLATFORM_WEBHOOKS_MOCK_DATA: Record<WebhookScope, PlatformWebhooksM
|
||||
{
|
||||
id: '1a4e8c73-5b29-44af-8c62-9f1d2b3c4d5e',
|
||||
name: 'Slack notifications',
|
||||
url: 'https://hooks.slack.com/services/T000/B000/ORG',
|
||||
url: 'https://hooks.slack.com/services/abc1234/def5678/ghi9012',
|
||||
description: 'Operational alerts for organization-level events',
|
||||
enabled: false,
|
||||
eventTypes: ['organization.updated'],
|
||||
|
||||
+9
-4
@@ -1,5 +1,5 @@
|
||||
import { createNavigationHandler } from 'lib/navigation'
|
||||
import { ChevronRight, Eye, MoreVertical, Plus, Search, Trash2 } from 'lucide-react'
|
||||
import { ChevronRight, Eye, MoreVertical, Plus, Search, Trash2, Webhook } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo, useState } from 'react'
|
||||
import {
|
||||
@@ -93,6 +93,7 @@ export const PlatformWebhooksEndpointList = ({
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h2 className="text-foreground text-xl">Endpoints</h2>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between gap-x-2">
|
||||
<Input
|
||||
placeholder="Search endpoints"
|
||||
@@ -102,6 +103,7 @@ export const PlatformWebhooksEndpointList = ({
|
||||
className="w-full lg:w-52"
|
||||
onChange={(event) => onSearchChange(event.target.value)}
|
||||
/>
|
||||
|
||||
<Button type="primary" icon={<Plus />} onClick={onCreateEndpoint}>
|
||||
New endpoint
|
||||
</Button>
|
||||
@@ -109,6 +111,7 @@ export const PlatformWebhooksEndpointList = ({
|
||||
|
||||
{filteredEndpoints.length === 0 ? (
|
||||
<EmptyStatePresentational
|
||||
icon={Webhook}
|
||||
title="No endpoints yet"
|
||||
description="Create an endpoint to start receiving webhook deliveries."
|
||||
>
|
||||
@@ -171,15 +174,17 @@ export const PlatformWebhooksEndpointList = ({
|
||||
<TableCell className="max-w-[420px]">
|
||||
<p className="truncate">{displayName}</p>
|
||||
{hasName && (
|
||||
<p className="text-xs text-foreground-lighter truncate">{endpoint.url}</p>
|
||||
<p className="text-xs text-foreground-lighter truncate mt-0.5">
|
||||
{endpoint.url}
|
||||
</p>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="max-w-[280px] truncate">
|
||||
{formatEventCount(endpoint.eventTypes)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<TableCell className="max-w-[220px]">
|
||||
<TimestampInfo className="text-sm" utcTimestamp={endpoint.createdAt} />
|
||||
<p className="text-xs text-foreground-lighter mt-0.5">
|
||||
<p className="text-xs text-foreground-lighter mt-0.5 truncate">
|
||||
by {endpoint.createdBy}
|
||||
</p>
|
||||
</TableCell>
|
||||
|
||||
@@ -74,18 +74,7 @@ export const PlatformWebhooksHeader = ({
|
||||
<PageHeaderDescription>{headerDescription}</PageHeaderDescription>
|
||||
</PageHeaderSummary>
|
||||
<PageHeaderAside>
|
||||
{hasSelectedEndpoint ? (
|
||||
endpointActions
|
||||
) : (
|
||||
<>
|
||||
<DocsButton href="https://supabase.com/docs" />
|
||||
<Button asChild type="default">
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://supabase.com">
|
||||
Leave feedback
|
||||
</a>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{hasSelectedEndpoint ? endpointActions : <DocsButton href="https://supabase.com/docs" />}
|
||||
</PageHeaderAside>
|
||||
</PageHeaderMeta>
|
||||
</PageHeader>
|
||||
|
||||
@@ -128,9 +128,18 @@ export const PlatformWebhooksPage = ({ scope, endpointId }: PlatformWebhooksPage
|
||||
() => endpoints.find((endpoint) => endpoint.id === endpointIdPendingDelete) ?? null,
|
||||
[endpoints, endpointIdPendingDelete]
|
||||
)
|
||||
const endpointPendingDeleteHasName = endpointPendingDelete
|
||||
? endpointPendingDelete.name.trim().length > 0
|
||||
: false
|
||||
const endpointPendingDeleteDisplayName = endpointPendingDelete
|
||||
? getWebhookEndpointDisplayName(endpointPendingDelete)
|
||||
: ''
|
||||
let deleteEndpointDescription = 'This action cannot be undone.'
|
||||
if (endpointPendingDelete) {
|
||||
deleteEndpointDescription = endpointPendingDeleteHasName
|
||||
? `Deleting “${endpointPendingDeleteDisplayName}” stops all deliveries to the URL below. This can’t be undone.`
|
||||
: 'Deleting this endpoint stops all deliveries to the URL below. This can’t be undone.'
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!platformWebhooksEnabled) {
|
||||
@@ -233,7 +242,7 @@ export const PlatformWebhooksPage = ({ scope, endpointId }: PlatformWebhooksPage
|
||||
setDeliverySearch('')
|
||||
}
|
||||
setEndpointIdPendingDelete(null)
|
||||
toast.success(`Deleted endpoint "${endpointPendingDeleteDisplayName}"`)
|
||||
toast.success('Endpoint deleted')
|
||||
}
|
||||
|
||||
const handleUpsertEndpoint = (values: EndpointFormValues) => {
|
||||
@@ -333,14 +342,14 @@ export const PlatformWebhooksPage = ({ scope, endpointId }: PlatformWebhooksPage
|
||||
className="gap-x-2"
|
||||
onClick={() => setShowRegenerateSecretConfirm(true)}
|
||||
>
|
||||
<RotateCw size={14} />
|
||||
<RotateCw size={14} className="text-foreground-lighter" />
|
||||
<span>Regenerate secret</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className="gap-x-2"
|
||||
onClick={() => setEndpointIdPendingDelete(selectedEndpoint.id)}
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
<Trash2 size={14} className="text-foreground-lighter" />
|
||||
<span>Delete endpoint</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
@@ -420,14 +429,13 @@ export const PlatformWebhooksPage = ({ scope, endpointId }: PlatformWebhooksPage
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete endpoint</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{endpointPendingDelete
|
||||
? endpointPendingDelete.name.trim().length > 0
|
||||
? `This will delete endpoint "${endpointPendingDeleteDisplayName}" with URL ${endpointPendingDelete.url}. This action cannot be undone.`
|
||||
: `This will delete endpoint ${endpointPendingDelete.url}. This action cannot be undone.`
|
||||
: 'This action cannot be undone.'}
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogDescription>{deleteEndpointDescription}</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
{endpointPendingDelete && (
|
||||
<pre className="mx-5 -mt-1 mb-5 overflow-auto whitespace-nowrap rounded-md border border-muted bg-surface-200 px-4 py-3 font-mono text-xs tracking-tight text-foreground">
|
||||
{endpointPendingDelete.url}
|
||||
</pre>
|
||||
)}
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction variant="danger" onClick={handleDeleteEndpoint}>
|
||||
|
||||
Reference in new issue
Block a user