mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 07:09:07 +03:00
## What
Wires the existing (mocked) Platform Webhooks UI to the real Management
API backend, per FE-3749.
- New `data/platform-webhooks/` query/mutation hooks, calling the real
`/v2/organizations/{slug}/webhooks/...` and
`/v2/projects/{ref}/webhooks/...` endpoints
- Updated `PlatformWebhooks.types.ts` to match the real API contract
(field names, shapes)
- Added a signing secret field to the create-endpoint form (API requires
a user-provided secret, not server-generated like the mock assumed)
- Removed the event-type column from the deliveries table (the real
list-deliveries endpoint doesn't return event type, only the
single-delivery endpoint does)
- Removed `PlatformWebhooks.mock.ts` / `.store.ts` and their tests
## Why
UI was built ~80% against mock data months ago; this closes the gap to a
real, working feature.
## Known open items (not blocking, tracked separately)
- `name` field has no backend storage yet — client-only for now, open
question with Ali/Paweł
- Deliveries table only fetches the backend's default single page — real
server-side pagination not yet wired (see FE-3750)
## Follow-up PR (stacked)
Tests for the new `data/platform-webhooks/` hooks (MSW-based), per the
ticket's own scope split.
## Testing
Manually tested end-to-end against local backend: created/edited/deleted
an endpoint, verified the real signature using webhook.site,
independently recomputed the HMAC and confirmed it matches the
`webhook-signature` header.
Linear: FE-3749
---------
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
import { toast } from 'sonner'
|
|
|
|
import { platformWebhooksKeys } from './keys'
|
|
import { createWebhookEndpoint, type WebhookScopeParams } from './platform-webhooks-fetchers'
|
|
import { toWebhookEndpoint, toWebhookEndpointAttributes } from './platform-webhooks-mappers'
|
|
import type {
|
|
UpsertWebhookEndpointInput,
|
|
WebhookEndpoint,
|
|
} from '@/components/interfaces/Platform/Webhooks/PlatformWebhooks.types'
|
|
import type { ResponseError, UseCustomMutationOptions } from '@/types'
|
|
|
|
export type WebhookEndpointCreateVariables = {
|
|
scope: WebhookScopeParams
|
|
input: UpsertWebhookEndpointInput
|
|
}
|
|
|
|
async function createEndpoint({
|
|
scope,
|
|
input,
|
|
}: WebhookEndpointCreateVariables): Promise<WebhookEndpoint> {
|
|
const attributes = toWebhookEndpointAttributes(input)
|
|
if (!attributes.signing_secret) throw new Error('A signing secret is required')
|
|
|
|
const result = await createWebhookEndpoint(scope, {
|
|
...attributes,
|
|
signing_secret: attributes.signing_secret,
|
|
})
|
|
if (!result?.data) throw new Error('Endpoint was created but no data was returned')
|
|
|
|
// The server never stores `name` (see PlatformWebhooks.types.ts) — carry through
|
|
// what the user typed so it's visible for this session, even though it won't
|
|
// survive a refetch or page reload.
|
|
return { ...toWebhookEndpoint(result.data), name: input.name }
|
|
}
|
|
|
|
type WebhookEndpointCreateData = Awaited<ReturnType<typeof createEndpoint>>
|
|
|
|
export const useWebhookEndpointCreateMutation = ({
|
|
onSuccess,
|
|
onError,
|
|
...options
|
|
}: Omit<
|
|
UseCustomMutationOptions<
|
|
WebhookEndpointCreateData,
|
|
ResponseError,
|
|
WebhookEndpointCreateVariables
|
|
>,
|
|
'mutationFn'
|
|
> = {}) => {
|
|
const queryClient = useQueryClient()
|
|
|
|
return useMutation<WebhookEndpointCreateData, ResponseError, WebhookEndpointCreateVariables>({
|
|
mutationFn: createEndpoint,
|
|
async onSuccess(data, variables, context) {
|
|
await queryClient.invalidateQueries({
|
|
queryKey: platformWebhooksKeys.endpoints(variables.scope),
|
|
})
|
|
|
|
await onSuccess?.(data, variables, context)
|
|
},
|
|
async onError(data, variables, context) {
|
|
if (onError === undefined) {
|
|
toast.error(`Failed to create webhook endpoint: ${data.message}`)
|
|
} else {
|
|
onError(data, variables, context)
|
|
}
|
|
},
|
|
...options,
|
|
})
|
|
}
|