@open-mercato/webhooks 0.5.1-develop.2860.07af3a6a9d → 0.5.1-develop.2874.77704bccbd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/webhooks/backend/webhooks/[id]/page.js +6 -6
- package/dist/modules/webhooks/backend/webhooks/[id]/page.js.map +2 -2
- package/dist/modules/webhooks/backend/webhooks/page.js +1 -1
- package/dist/modules/webhooks/backend/webhooks/page.js.map +2 -2
- package/dist/modules/webhooks/widgets/injection/integration-deliveries/widget.client.js +1 -1
- package/dist/modules/webhooks/widgets/injection/integration-deliveries/widget.client.js.map +1 -1
- package/dist/modules/webhooks/widgets/injection/integration-setup/widget.client.js +2 -2
- package/dist/modules/webhooks/widgets/injection/integration-setup/widget.client.js.map +1 -1
- package/package.json +6 -6
- package/src/modules/webhooks/backend/webhooks/[id]/page.tsx +7 -7
- package/src/modules/webhooks/backend/webhooks/page.tsx +1 -1
- package/src/modules/webhooks/widgets/injection/integration-deliveries/widget.client.tsx +1 -1
- package/src/modules/webhooks/widgets/injection/integration-setup/widget.client.tsx +2 -2
|
@@ -405,7 +405,7 @@ function WebhookDetailPage() {
|
|
|
405
405
|
statusBadge: /* @__PURE__ */ jsx(
|
|
406
406
|
Badge,
|
|
407
407
|
{
|
|
408
|
-
className: webhook.isActive ? "border-transparent bg-
|
|
408
|
+
className: webhook.isActive ? "border-transparent bg-status-success-bg text-status-success-text" : "border-transparent bg-status-neutral-bg text-status-neutral-text",
|
|
409
409
|
children: webhook.isActive ? t("webhooks.list.status.active") : t("webhooks.list.status.inactive")
|
|
410
410
|
}
|
|
411
411
|
),
|
|
@@ -513,7 +513,7 @@ function WebhookDetailPage() {
|
|
|
513
513
|
t("webhooks.form.customHeaders"),
|
|
514
514
|
":"
|
|
515
515
|
] }),
|
|
516
|
-
/* @__PURE__ */ jsx("pre", { className: "mt-2 rounded border bg-muted/
|
|
516
|
+
/* @__PURE__ */ jsx("pre", { className: "mt-2 rounded border bg-muted/50 p-3 text-xs", children: webhook.customHeaders ? JSON.stringify(webhook.customHeaders, null, 2) : "\u2014" })
|
|
517
517
|
] })
|
|
518
518
|
] })
|
|
519
519
|
] }),
|
|
@@ -535,7 +535,7 @@ function WebhookDetailPage() {
|
|
|
535
535
|
": ",
|
|
536
536
|
testDelivery.durationMs != null ? `${testDelivery.durationMs}ms` : "\u2014"
|
|
537
537
|
] }),
|
|
538
|
-
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/
|
|
538
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/50 p-3 text-xs", children: JSON.stringify(testDelivery.payload, null, 2) })
|
|
539
539
|
] })
|
|
540
540
|
] }) : null,
|
|
541
541
|
/* @__PURE__ */ jsx("div", { className: "mt-8", children: /* @__PURE__ */ jsx(
|
|
@@ -615,15 +615,15 @@ function WebhookDetailPage() {
|
|
|
615
615
|
] }),
|
|
616
616
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
617
617
|
/* @__PURE__ */ jsx("div", { className: "mb-2 font-medium", children: t("webhooks.deliveries.requestBody") }),
|
|
618
|
-
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/
|
|
618
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/50 p-3 text-xs", children: JSON.stringify(selectedDelivery.payload, null, 2) })
|
|
619
619
|
] }),
|
|
620
620
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
621
621
|
/* @__PURE__ */ jsx("div", { className: "mb-2 font-medium", children: t("webhooks.deliveries.responseBody") }),
|
|
622
|
-
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/
|
|
622
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/50 p-3 text-xs", children: selectedDelivery.responseBody ?? "\u2014" })
|
|
623
623
|
] }),
|
|
624
624
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
625
625
|
/* @__PURE__ */ jsx("div", { className: "mb-2 font-medium", children: t("webhooks.deliveries.responseHeaders") }),
|
|
626
|
-
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/
|
|
626
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-auto rounded border bg-muted/50 p-3 text-xs", children: selectedDelivery.responseHeaders ? JSON.stringify(selectedDelivery.responseHeaders, null, 2) : "\u2014" })
|
|
627
627
|
] })
|
|
628
628
|
] })
|
|
629
629
|
] }) : null
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/webhooks/backend/webhooks/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useParams, usePathname, useRouter } from 'next/navigation'\nimport { RotateCw } from 'lucide-react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport {\n buildWebhookFormContentHeader,\n buildWebhookFormFields,\n buildWebhookFormGroups,\n createWebhookInitialValues,\n normalizeWebhookFormPayload,\n type WebhookFormValues,\n} from '../../../components/webhook-form-config'\nimport { useWebhookFeatureAccess } from '../useWebhookFeatureAccess'\nimport { WebhookSecretPanel } from '../../../components/WebhookSecretPanel'\n\ntype Webhook = {\n id: string\n name: string\n description: string | null\n url: string\n subscribedEvents: string[]\n httpMethod: 'POST' | 'PUT' | 'PATCH'\n isActive: boolean\n maxRetries: number\n timeoutMs: number\n rateLimitPerMinute: number\n autoDisableThreshold: number\n consecutiveFailures: number\n lastSuccessAt: string | null\n lastFailureAt: string | null\n customHeaders: Record<string, string> | null\n createdAt: string\n updatedAt: string\n maskedSecret: string\n previousSecretSetAt: string | null\n}\n\ntype DeliveryRow = {\n id: string\n webhookId: string\n eventType: string\n messageId: string\n status: string\n responseStatus: number | null\n errorMessage: string | null\n attemptNumber: number\n maxAttempts: number\n durationMs: number | null\n targetUrl: string\n enqueuedAt: string\n lastAttemptAt: string | null\n deliveredAt: string | null\n createdAt: string\n}\n\ntype DeliveryResponse = {\n items: DeliveryRow[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ntype DeliveryDetail = DeliveryRow & {\n payload: Record<string, unknown>\n responseBody: string | null\n responseHeaders: Record<string, string> | null\n nextRetryAt: string | null\n updatedAt: string\n}\n\nconst statusVariantMap: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n delivered: 'default',\n pending: 'secondary',\n sending: 'outline',\n failed: 'destructive',\n expired: 'destructive',\n}\nconst DELIVERY_AUTO_REFRESH_INTERVAL_MS = 30000\n\nexport default function WebhookDetailPage() {\n const params = useParams()\n const pathname = usePathname()\n const router = useRouter()\n const t = useT()\n const webhookId = React.useMemo(() => resolveWebhookId(params?.id, pathname), [params?.id, pathname])\n\n const [webhook, setWebhook] = React.useState<Webhook | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isEditing, setIsEditing] = React.useState(false)\n\n const [deliveries, setDeliveries] = React.useState<DeliveryRow[]>([])\n const [deliveryPage, setDeliveryPage] = React.useState(1)\n const [deliveryTotal, setDeliveryTotal] = React.useState(0)\n const [deliveryTotalPages, setDeliveryTotalPages] = React.useState(1)\n const [deliveriesLoading, setDeliveriesLoading] = React.useState(false)\n const [isRefreshingDeliveries, setIsRefreshingDeliveries] = React.useState(false)\n const [testDelivery, setTestDelivery] = React.useState<DeliveryDetail | null>(null)\n const [selectedDelivery, setSelectedDelivery] = React.useState<DeliveryDetail | null>(null)\n const [selectedDeliveryLoading, setSelectedDeliveryLoading] = React.useState(false)\n const [revealedSecret, setRevealedSecret] = React.useState<string | null>(null)\n const refreshInFlightRef = React.useRef(false)\n const access = useWebhookFeatureAccess()\n\n const fetchWebhook = React.useCallback(async (options?: { silent?: boolean }) => {\n if (!webhookId) {\n setError(t('webhooks.errors.notFound'))\n setIsLoading(false)\n return\n }\n\n const silent = options?.silent === true\n if (!silent) {\n setIsLoading(true)\n }\n\n setError(null)\n\n try {\n const call = await apiCall<Webhook>(\n `/api/webhooks/${encodeURIComponent(webhookId)}`,\n undefined,\n { fallback: null },\n )\n\n if (call.ok && call.result) {\n setWebhook(call.result)\n return\n }\n\n setError(t('webhooks.errors.notFound'))\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError.message : t('webhooks.detail.loadError'))\n } finally {\n if (!silent) {\n setIsLoading(false)\n }\n }\n }, [t, webhookId])\n\n const fetchDeliveries = React.useCallback(async (options?: { silent?: boolean }) => {\n if (!webhookId) return\n\n const silent = options?.silent === true\n if (!silent) {\n setDeliveriesLoading(true)\n }\n\n try {\n const params = new URLSearchParams()\n params.set('webhookId', webhookId)\n params.set('page', String(deliveryPage))\n params.set('pageSize', '20')\n\n const fallback: DeliveryResponse = { items: [], total: 0, page: deliveryPage, pageSize: 20, totalPages: 1 }\n const call = await apiCall<DeliveryResponse>(\n `/api/webhooks/deliveries?${params.toString()}`,\n undefined,\n { fallback },\n )\n\n if (call.ok && call.result) {\n setDeliveries(call.result.items)\n setDeliveryTotal(call.result.total)\n setDeliveryTotalPages(call.result.totalPages)\n }\n } finally {\n if (!silent) {\n setDeliveriesLoading(false)\n }\n }\n }, [deliveryPage, webhookId])\n\n const fetchDeliveryDetail = React.useCallback(async (deliveryId: string): Promise<DeliveryDetail | null> => {\n const call = await apiCall<DeliveryDetail>(\n `/api/webhooks/deliveries/${encodeURIComponent(deliveryId)}`,\n undefined,\n { fallback: null },\n )\n\n if (!call.ok || !call.result) {\n return null\n }\n\n return call.result\n }, [])\n\n const refreshDeliveryState = React.useCallback(async () => {\n if (!webhookId || refreshInFlightRef.current) return\n\n refreshInFlightRef.current = true\n setIsRefreshingDeliveries(true)\n\n try {\n await Promise.all([\n fetchWebhook({ silent: true }),\n fetchDeliveries({ silent: true }),\n ])\n\n const detailIds = [selectedDelivery?.id, testDelivery?.id].filter(\n (value): value is string => typeof value === 'string' && value.length > 0,\n )\n\n if (detailIds.length > 0) {\n const details = await Promise.all(detailIds.map((deliveryId) => fetchDeliveryDetail(deliveryId)))\n const detailMap = new Map<string, DeliveryDetail>()\n\n for (const detail of details) {\n if (detail) {\n detailMap.set(detail.id, detail)\n }\n }\n\n if (selectedDelivery?.id) {\n setSelectedDelivery((current) => current?.id ? (detailMap.get(current.id) ?? current) : current)\n }\n\n if (testDelivery?.id) {\n setTestDelivery((current) => current?.id ? (detailMap.get(current.id) ?? current) : current)\n }\n }\n } finally {\n refreshInFlightRef.current = false\n setIsRefreshingDeliveries(false)\n }\n }, [fetchDeliveries, fetchDeliveryDetail, fetchWebhook, selectedDelivery?.id, testDelivery?.id, webhookId])\n\n React.useEffect(() => {\n void fetchWebhook()\n }, [fetchWebhook])\n\n React.useEffect(() => {\n if (!webhookId) return\n void fetchDeliveries()\n }, [fetchDeliveries, webhookId])\n\n useAppEvent('webhooks.delivery.*', (event) => {\n const eventWebhookId = typeof event.payload?.webhookId === 'string' ? event.payload.webhookId : null\n if (eventWebhookId !== webhookId) return\n void refreshDeliveryState()\n }, [refreshDeliveryState, webhookId])\n\n React.useEffect(() => {\n if (!webhookId || isEditing) return\n\n const intervalId = window.setInterval(() => {\n if (document.visibilityState !== 'visible') return\n void refreshDeliveryState()\n }, DELIVERY_AUTO_REFRESH_INTERVAL_MS)\n\n return () => {\n window.clearInterval(intervalId)\n }\n }, [isEditing, refreshDeliveryState, webhookId])\n\n const handleToggleActive = React.useCallback(async () => {\n if (!webhook) return\n try {\n const call = await apiCall<Webhook>(\n `/api/webhooks/${encodeURIComponent(webhook.id)}`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ isActive: !webhook.isActive }),\n },\n { fallback: null },\n )\n if (call.ok) {\n setWebhook((prev) => prev ? { ...prev, isActive: !prev.isActive } : prev)\n flash(t('webhooks.form.updateSuccess'), 'success')\n void refreshDeliveryState()\n }\n } catch {\n flash(t('webhooks.form.updateError'), 'error')\n }\n }, [refreshDeliveryState, webhook, t])\n\n const handleRotateSecret = React.useCallback(async () => {\n if (!webhook) return\n try {\n const call = await apiCall<{ secret: string }>(\n `/api/webhooks/${encodeURIComponent(webhook.id)}/rotate-secret`,\n { method: 'POST' },\n { fallback: null },\n )\n if (!call.ok || !call.result) {\n flash(t('webhooks.detail.rotateError'), 'error')\n return\n }\n setRevealedSecret(call.result.secret)\n flash(t('webhooks.detail.rotateSuccess'), 'success')\n void refreshDeliveryState()\n } catch {\n flash(t('webhooks.detail.rotateError'), 'error')\n }\n }, [refreshDeliveryState, t, webhook])\n\n const handleTest = React.useCallback(async () => {\n if (!webhook) return\n try {\n const call = await apiCall<{ delivery: DeliveryDetail }>(\n `/api/webhooks/${encodeURIComponent(webhook.id)}/test`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({}) },\n { fallback: null },\n )\n if (!call.ok || !call.result) {\n flash(t('webhooks.detail.testError'), 'error')\n return\n }\n const deliveryStatus = call.result.delivery.status\n setTestDelivery(call.result.delivery)\n flash(\n deliveryStatus === 'delivered' ? t('webhooks.detail.testSuccess') : t('webhooks.detail.testQueued'),\n deliveryStatus === 'delivered' ? 'success' : 'error',\n )\n void refreshDeliveryState()\n } catch {\n flash(t('webhooks.detail.testError'), 'error')\n }\n }, [refreshDeliveryState, t, webhook])\n\n const handleRetryDelivery = React.useCallback(async (deliveryId: string) => {\n try {\n const call = await apiCall(\n `/api/webhooks/deliveries/${encodeURIComponent(deliveryId)}/retry`,\n { method: 'POST' },\n { fallback: null },\n )\n if (!call.ok) {\n flash(t('webhooks.deliveries.retryError'), 'error')\n return\n }\n flash(t('webhooks.deliveries.retrySuccess'), 'success')\n void refreshDeliveryState()\n } catch {\n flash(t('webhooks.deliveries.retryError'), 'error')\n }\n }, [refreshDeliveryState, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!webhook) return\n try {\n await deleteCrud(`webhooks/${encodeURIComponent(webhook.id)}`, { fallbackResult: null })\n flash(t('webhooks.list.deleteSuccess'), 'success')\n router.push('/backend/webhooks')\n } catch {\n flash(t('webhooks.list.deleteError'), 'error')\n }\n }, [router, t, webhook])\n\n const handleDeliveryOpen = React.useCallback(async (deliveryId: string) => {\n setSelectedDeliveryLoading(true)\n try {\n const detail = await fetchDeliveryDetail(deliveryId)\n if (!detail) {\n flash(t('webhooks.deliveries.loadError'), 'error')\n return\n }\n setSelectedDelivery(detail)\n } catch {\n flash(t('webhooks.deliveries.loadError'), 'error')\n } finally {\n setSelectedDeliveryLoading(false)\n }\n }, [fetchDeliveryDetail, t])\n\n const deliveryColumns = React.useMemo<ColumnDef<DeliveryRow>[]>(() => [\n { accessorKey: 'eventType', header: t('webhooks.deliveries.columns.event') },\n {\n accessorKey: 'status',\n header: t('webhooks.deliveries.columns.status'),\n cell: ({ row }) => (\n <Badge variant={statusVariantMap[row.original.status] ?? 'secondary'}>\n {t(`webhooks.deliveries.status.${row.original.status}` as Parameters<typeof t>[0])}\n </Badge>\n ),\n },\n {\n accessorKey: 'responseStatus',\n header: t('webhooks.deliveries.columns.responseStatus'),\n cell: ({ row }) => row.original.responseStatus ?? '\u2014',\n },\n {\n accessorKey: 'attemptNumber',\n header: t('webhooks.deliveries.columns.attempts'),\n cell: ({ row }) => `${row.original.attemptNumber}/${row.original.maxAttempts}`,\n },\n {\n accessorKey: 'durationMs',\n header: t('webhooks.deliveries.columns.duration'),\n cell: ({ row }) => row.original.durationMs != null ? `${row.original.durationMs}ms` : '\u2014',\n },\n {\n accessorKey: 'createdAt',\n header: t('webhooks.deliveries.columns.enqueuedAt'),\n cell: ({ row }) => {\n try { return new Date(row.original.enqueuedAt).toLocaleString() }\n catch { return '\u2014' }\n },\n },\n ], [t])\n\n const fields = React.useMemo(() => buildWebhookFormFields(t), [t])\n const groups = React.useMemo(() => buildWebhookFormGroups(t), [t])\n const contentHeader = React.useMemo(() => buildWebhookFormContentHeader(t), [t])\n const menuActions = React.useMemo(() => {\n const items: Array<{ id: string; label: string; onSelect: () => void }> = []\n const isActive = webhook?.isActive ?? false\n\n if (access.canManage) {\n items.push(\n {\n id: 'edit',\n label: t('webhooks.list.actions.edit'),\n onSelect: () => setIsEditing(true),\n },\n {\n id: 'toggle-active',\n label: isActive ? t('webhooks.detail.actions.deactivate') : t('webhooks.detail.actions.activate'),\n onSelect: () => { void handleToggleActive() },\n },\n )\n }\n\n if (access.canSecrets) {\n items.push({\n id: 'rotate-secret',\n label: t('webhooks.detail.actions.rotateSecret'),\n onSelect: () => { void handleRotateSecret() },\n })\n }\n\n if (access.canTest) {\n items.push({\n id: 'test',\n label: t('webhooks.detail.actions.test'),\n onSelect: () => { void handleTest() },\n })\n }\n\n if (access.canManage) {\n items.push({\n id: 'delete',\n label: t('webhooks.list.actions.delete'),\n onSelect: () => { void handleDelete() },\n })\n }\n\n return items\n }, [access.canManage, access.canSecrets, access.canTest, handleDelete, handleRotateSecret, handleTest, handleToggleActive, t, webhook?.isActive])\n\n if (isLoading) return <Page><PageBody><LoadingMessage label={t('webhooks.detail.loading')} /></PageBody></Page>\n if (error || !webhook) return <Page><PageBody><ErrorMessage label={error ?? t('webhooks.errors.notFound')} /></PageBody></Page>\n\n if (isEditing) {\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('webhooks.form.title.edit')}\n backHref={`/backend/webhooks/${webhook.id}`}\n fields={fields}\n groups={groups}\n initialValues={createWebhookInitialValues(webhook)}\n submitLabel={t('common.save')}\n cancelHref={`/backend/webhooks/${webhook.id}`}\n contentHeader={contentHeader}\n onDelete={access.canManage ? handleDelete : undefined}\n onSubmit={async (values) => {\n const payload = normalizeWebhookFormPayload(values as WebhookFormValues, t)\n await updateCrud(`webhooks/${encodeURIComponent(webhook.id)}`, payload)\n flash(t('webhooks.form.updateSuccess'), 'success')\n setIsEditing(false)\n await refreshDeliveryState()\n }}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n {revealedSecret ? (\n <WebhookSecretPanel secret={revealedSecret} onClose={() => setRevealedSecret(null)} />\n ) : null}\n <FormHeader\n mode=\"detail\"\n title={webhook.name}\n entityTypeLabel={t('webhooks.nav.title')}\n statusBadge={\n <Badge\n className={webhook.isActive\n ? 'border-transparent bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'\n : 'border-transparent bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400'}\n >\n {webhook.isActive ? t('webhooks.list.status.active') : t('webhooks.list.status.inactive')}\n </Badge>\n }\n backHref=\"/backend/webhooks\"\n menuActions={menuActions}\n />\n\n <div className=\"mt-6 space-y-4\">\n {!access.isLoading && !access.canManage && !access.canSecrets && !access.canTest ? (\n <Alert variant=\"info\">\n <AlertDescription>{t('webhooks.detail.readOnlyTip')}</AlertDescription>\n </Alert>\n ) : null}\n <div className=\"grid gap-3 lg:grid-cols-2\">\n <Alert variant=\"info\">\n <AlertDescription>{t('webhooks.detail.deliveryTip')}</AlertDescription>\n </Alert>\n <Alert variant=\"info\">\n <AlertDescription>{t('webhooks.detail.signatureTip')}</AlertDescription>\n </Alert>\n </div>\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.url')}:</span>\n <code className=\"ml-2 text-xs break-all\">{webhook.url}</code>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.httpMethod')}:</span>\n <span className=\"ml-2\">{webhook.httpMethod}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.subscribedEvents')}:</span>\n <span className=\"ml-2 text-xs\">{webhook.subscribedEvents.join(', ')}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.maxRetries')}:</span>\n <span className=\"ml-2\">{webhook.maxRetries}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.rateLimitPerMinute')}:</span>\n <span className=\"ml-2\">{webhook.rateLimitPerMinute}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.autoDisableThreshold')}:</span>\n <span className=\"ml-2\">{webhook.autoDisableThreshold}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.detail.consecutiveFailures')}:</span>\n <span className=\"ml-2\">{webhook.consecutiveFailures}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.secret')}:</span>\n <span className=\"ml-2 inline-flex items-center gap-2\">\n <span className=\"font-mono text-xs\">{webhook.maskedSecret}</span>\n {access.canSecrets ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 px-2 text-xs\"\n onClick={() => { void handleRotateSecret() }}\n >\n <RotateCw className=\"mr-1.5 size-3.5\" />\n {t('webhooks.detail.actions.rotateSecret')}\n </Button>\n ) : null}\n </span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.list.columns.lastDelivery')}:</span>\n <span className=\"ml-2\">{webhook.lastSuccessAt ?? webhook.lastFailureAt ?? '\u2014'}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.detail.previousSecretSetAt')}:</span>\n <span className=\"ml-2\">{webhook.previousSecretSetAt ?? '\u2014'}</span>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-muted-foreground\">{t('webhooks.form.customHeaders')}:</span>\n <pre className=\"mt-2 rounded border bg-muted/40 p-3 text-xs\">\n {webhook.customHeaders ? JSON.stringify(webhook.customHeaders, null, 2) : '\u2014'}\n </pre>\n </div>\n </div>\n </div>\n\n {testDelivery ? (\n <div className=\"mt-8 rounded-lg border bg-card p-4\">\n <h2 className=\"text-sm font-semibold\">{t('webhooks.detail.testResult')}</h2>\n <div className=\"mt-3 grid gap-2 text-sm\">\n <div>{t('webhooks.deliveries.columns.status')}: {testDelivery.status}</div>\n <div>{t('webhooks.deliveries.columns.responseStatus')}: {testDelivery.responseStatus ?? '\u2014'}</div>\n <div>{t('webhooks.deliveries.columns.duration')}: {testDelivery.durationMs != null ? `${testDelivery.durationMs}ms` : '\u2014'}</div>\n <pre className=\"overflow-auto rounded border bg-muted/40 p-3 text-xs\">\n {JSON.stringify(testDelivery.payload, null, 2)}\n </pre>\n </div>\n </div>\n ) : null}\n\n <div className=\"mt-8\">\n <DataTable\n title={t('webhooks.deliveries.title')}\n actions={(\n <div className=\"flex items-center gap-2\">\n <span className=\"hidden text-xs text-muted-foreground md:inline\">\n {t('webhooks.deliveries.autoRefreshHint')}\n </span>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => { void refreshDeliveryState() }}\n disabled={isRefreshingDeliveries}\n >\n {isRefreshingDeliveries\n ? t('webhooks.deliveries.refreshing')\n : t('webhooks.deliveries.refresh')}\n </Button>\n </div>\n )}\n columns={deliveryColumns}\n data={deliveries}\n onRowClick={(row) => { void handleDeliveryOpen(row.id) }}\n rowActions={(row) => {\n const items: Array<{ id: string; label: string; onSelect: () => void }> = [\n {\n id: 'view-details',\n label: t('webhooks.deliveries.actions.viewDetails'),\n onSelect: () => { void handleDeliveryOpen(row.id) },\n },\n ]\n\n if (access.canManage && (row.status === 'failed' || row.status === 'expired')) {\n items.push({\n id: 'retry',\n label: t('webhooks.deliveries.actions.retry'),\n onSelect: () => { void handleRetryDelivery(row.id) },\n })\n }\n\n return <RowActions items={items} />\n }}\n perspective={{ tableId: 'webhooks.deliveries' }}\n pagination={{\n page: deliveryPage,\n pageSize: 20,\n total: deliveryTotal,\n totalPages: deliveryTotalPages,\n onPageChange: setDeliveryPage,\n }}\n isLoading={deliveriesLoading || isRefreshingDeliveries}\n />\n </div>\n\n {selectedDelivery || selectedDeliveryLoading ? (\n <div className=\"mt-6 rounded-lg border bg-card p-4\">\n <h2 className=\"text-sm font-semibold\">{t('webhooks.deliveries.detailTitle')}</h2>\n {selectedDeliveryLoading || !selectedDelivery ? (\n <div className=\"mt-3 text-sm text-muted-foreground\">{t('common.loading')}</div>\n ) : (\n <div className=\"mt-3 space-y-4 text-sm\">\n <div>{t('webhooks.deliveries.columns.status')}: {selectedDelivery.status}</div>\n <div>{t('webhooks.deliveries.columns.responseStatus')}: {selectedDelivery.responseStatus ?? '\u2014'}</div>\n <div>{t('webhooks.deliveries.columns.duration')}: {selectedDelivery.durationMs != null ? `${selectedDelivery.durationMs}ms` : '\u2014'}</div>\n <div>\n <div className=\"mb-2 font-medium\">{t('webhooks.deliveries.requestBody')}</div>\n <pre className=\"overflow-auto rounded border bg-muted/40 p-3 text-xs\">\n {JSON.stringify(selectedDelivery.payload, null, 2)}\n </pre>\n </div>\n <div>\n <div className=\"mb-2 font-medium\">{t('webhooks.deliveries.responseBody')}</div>\n <pre className=\"overflow-auto rounded border bg-muted/40 p-3 text-xs\">\n {selectedDelivery.responseBody ?? '\u2014'}\n </pre>\n </div>\n <div>\n <div className=\"mb-2 font-medium\">{t('webhooks.deliveries.responseHeaders')}</div>\n <pre className=\"overflow-auto rounded border bg-muted/40 p-3 text-xs\">\n {selectedDelivery.responseHeaders ? JSON.stringify(selectedDelivery.responseHeaders, null, 2) : '\u2014'}\n </pre>\n </div>\n </div>\n )}\n </div>\n ) : null}\n </PageBody>\n </Page>\n )\n}\n\nfunction resolveWebhookId(paramValue: string | string[] | undefined, pathname: string | null): string | null {\n if (typeof paramValue === 'string' && paramValue.trim().length > 0) {\n return paramValue\n }\n\n if (Array.isArray(paramValue)) {\n const first = paramValue.find((value) => typeof value === 'string' && value.trim().length > 0)\n if (first) return first\n }\n\n if (typeof pathname === 'string') {\n const match = pathname.match(/\\/backend\\/webhooks\\/([^/?#]+)/)\n if (match?.[1]) {\n return decodeURIComponent(match[1])\n }\n }\n\n return null\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useParams, usePathname, useRouter } from 'next/navigation'\nimport { RotateCw } from 'lucide-react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport {\n buildWebhookFormContentHeader,\n buildWebhookFormFields,\n buildWebhookFormGroups,\n createWebhookInitialValues,\n normalizeWebhookFormPayload,\n type WebhookFormValues,\n} from '../../../components/webhook-form-config'\nimport { useWebhookFeatureAccess } from '../useWebhookFeatureAccess'\nimport { WebhookSecretPanel } from '../../../components/WebhookSecretPanel'\n\ntype Webhook = {\n id: string\n name: string\n description: string | null\n url: string\n subscribedEvents: string[]\n httpMethod: 'POST' | 'PUT' | 'PATCH'\n isActive: boolean\n maxRetries: number\n timeoutMs: number\n rateLimitPerMinute: number\n autoDisableThreshold: number\n consecutiveFailures: number\n lastSuccessAt: string | null\n lastFailureAt: string | null\n customHeaders: Record<string, string> | null\n createdAt: string\n updatedAt: string\n maskedSecret: string\n previousSecretSetAt: string | null\n}\n\ntype DeliveryRow = {\n id: string\n webhookId: string\n eventType: string\n messageId: string\n status: string\n responseStatus: number | null\n errorMessage: string | null\n attemptNumber: number\n maxAttempts: number\n durationMs: number | null\n targetUrl: string\n enqueuedAt: string\n lastAttemptAt: string | null\n deliveredAt: string | null\n createdAt: string\n}\n\ntype DeliveryResponse = {\n items: DeliveryRow[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ntype DeliveryDetail = DeliveryRow & {\n payload: Record<string, unknown>\n responseBody: string | null\n responseHeaders: Record<string, string> | null\n nextRetryAt: string | null\n updatedAt: string\n}\n\nconst statusVariantMap: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n delivered: 'default',\n pending: 'secondary',\n sending: 'outline',\n failed: 'destructive',\n expired: 'destructive',\n}\nconst DELIVERY_AUTO_REFRESH_INTERVAL_MS = 30000\n\nexport default function WebhookDetailPage() {\n const params = useParams()\n const pathname = usePathname()\n const router = useRouter()\n const t = useT()\n const webhookId = React.useMemo(() => resolveWebhookId(params?.id, pathname), [params?.id, pathname])\n\n const [webhook, setWebhook] = React.useState<Webhook | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isEditing, setIsEditing] = React.useState(false)\n\n const [deliveries, setDeliveries] = React.useState<DeliveryRow[]>([])\n const [deliveryPage, setDeliveryPage] = React.useState(1)\n const [deliveryTotal, setDeliveryTotal] = React.useState(0)\n const [deliveryTotalPages, setDeliveryTotalPages] = React.useState(1)\n const [deliveriesLoading, setDeliveriesLoading] = React.useState(false)\n const [isRefreshingDeliveries, setIsRefreshingDeliveries] = React.useState(false)\n const [testDelivery, setTestDelivery] = React.useState<DeliveryDetail | null>(null)\n const [selectedDelivery, setSelectedDelivery] = React.useState<DeliveryDetail | null>(null)\n const [selectedDeliveryLoading, setSelectedDeliveryLoading] = React.useState(false)\n const [revealedSecret, setRevealedSecret] = React.useState<string | null>(null)\n const refreshInFlightRef = React.useRef(false)\n const access = useWebhookFeatureAccess()\n\n const fetchWebhook = React.useCallback(async (options?: { silent?: boolean }) => {\n if (!webhookId) {\n setError(t('webhooks.errors.notFound'))\n setIsLoading(false)\n return\n }\n\n const silent = options?.silent === true\n if (!silent) {\n setIsLoading(true)\n }\n\n setError(null)\n\n try {\n const call = await apiCall<Webhook>(\n `/api/webhooks/${encodeURIComponent(webhookId)}`,\n undefined,\n { fallback: null },\n )\n\n if (call.ok && call.result) {\n setWebhook(call.result)\n return\n }\n\n setError(t('webhooks.errors.notFound'))\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError.message : t('webhooks.detail.loadError'))\n } finally {\n if (!silent) {\n setIsLoading(false)\n }\n }\n }, [t, webhookId])\n\n const fetchDeliveries = React.useCallback(async (options?: { silent?: boolean }) => {\n if (!webhookId) return\n\n const silent = options?.silent === true\n if (!silent) {\n setDeliveriesLoading(true)\n }\n\n try {\n const params = new URLSearchParams()\n params.set('webhookId', webhookId)\n params.set('page', String(deliveryPage))\n params.set('pageSize', '20')\n\n const fallback: DeliveryResponse = { items: [], total: 0, page: deliveryPage, pageSize: 20, totalPages: 1 }\n const call = await apiCall<DeliveryResponse>(\n `/api/webhooks/deliveries?${params.toString()}`,\n undefined,\n { fallback },\n )\n\n if (call.ok && call.result) {\n setDeliveries(call.result.items)\n setDeliveryTotal(call.result.total)\n setDeliveryTotalPages(call.result.totalPages)\n }\n } finally {\n if (!silent) {\n setDeliveriesLoading(false)\n }\n }\n }, [deliveryPage, webhookId])\n\n const fetchDeliveryDetail = React.useCallback(async (deliveryId: string): Promise<DeliveryDetail | null> => {\n const call = await apiCall<DeliveryDetail>(\n `/api/webhooks/deliveries/${encodeURIComponent(deliveryId)}`,\n undefined,\n { fallback: null },\n )\n\n if (!call.ok || !call.result) {\n return null\n }\n\n return call.result\n }, [])\n\n const refreshDeliveryState = React.useCallback(async () => {\n if (!webhookId || refreshInFlightRef.current) return\n\n refreshInFlightRef.current = true\n setIsRefreshingDeliveries(true)\n\n try {\n await Promise.all([\n fetchWebhook({ silent: true }),\n fetchDeliveries({ silent: true }),\n ])\n\n const detailIds = [selectedDelivery?.id, testDelivery?.id].filter(\n (value): value is string => typeof value === 'string' && value.length > 0,\n )\n\n if (detailIds.length > 0) {\n const details = await Promise.all(detailIds.map((deliveryId) => fetchDeliveryDetail(deliveryId)))\n const detailMap = new Map<string, DeliveryDetail>()\n\n for (const detail of details) {\n if (detail) {\n detailMap.set(detail.id, detail)\n }\n }\n\n if (selectedDelivery?.id) {\n setSelectedDelivery((current) => current?.id ? (detailMap.get(current.id) ?? current) : current)\n }\n\n if (testDelivery?.id) {\n setTestDelivery((current) => current?.id ? (detailMap.get(current.id) ?? current) : current)\n }\n }\n } finally {\n refreshInFlightRef.current = false\n setIsRefreshingDeliveries(false)\n }\n }, [fetchDeliveries, fetchDeliveryDetail, fetchWebhook, selectedDelivery?.id, testDelivery?.id, webhookId])\n\n React.useEffect(() => {\n void fetchWebhook()\n }, [fetchWebhook])\n\n React.useEffect(() => {\n if (!webhookId) return\n void fetchDeliveries()\n }, [fetchDeliveries, webhookId])\n\n useAppEvent('webhooks.delivery.*', (event) => {\n const eventWebhookId = typeof event.payload?.webhookId === 'string' ? event.payload.webhookId : null\n if (eventWebhookId !== webhookId) return\n void refreshDeliveryState()\n }, [refreshDeliveryState, webhookId])\n\n React.useEffect(() => {\n if (!webhookId || isEditing) return\n\n const intervalId = window.setInterval(() => {\n if (document.visibilityState !== 'visible') return\n void refreshDeliveryState()\n }, DELIVERY_AUTO_REFRESH_INTERVAL_MS)\n\n return () => {\n window.clearInterval(intervalId)\n }\n }, [isEditing, refreshDeliveryState, webhookId])\n\n const handleToggleActive = React.useCallback(async () => {\n if (!webhook) return\n try {\n const call = await apiCall<Webhook>(\n `/api/webhooks/${encodeURIComponent(webhook.id)}`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ isActive: !webhook.isActive }),\n },\n { fallback: null },\n )\n if (call.ok) {\n setWebhook((prev) => prev ? { ...prev, isActive: !prev.isActive } : prev)\n flash(t('webhooks.form.updateSuccess'), 'success')\n void refreshDeliveryState()\n }\n } catch {\n flash(t('webhooks.form.updateError'), 'error')\n }\n }, [refreshDeliveryState, webhook, t])\n\n const handleRotateSecret = React.useCallback(async () => {\n if (!webhook) return\n try {\n const call = await apiCall<{ secret: string }>(\n `/api/webhooks/${encodeURIComponent(webhook.id)}/rotate-secret`,\n { method: 'POST' },\n { fallback: null },\n )\n if (!call.ok || !call.result) {\n flash(t('webhooks.detail.rotateError'), 'error')\n return\n }\n setRevealedSecret(call.result.secret)\n flash(t('webhooks.detail.rotateSuccess'), 'success')\n void refreshDeliveryState()\n } catch {\n flash(t('webhooks.detail.rotateError'), 'error')\n }\n }, [refreshDeliveryState, t, webhook])\n\n const handleTest = React.useCallback(async () => {\n if (!webhook) return\n try {\n const call = await apiCall<{ delivery: DeliveryDetail }>(\n `/api/webhooks/${encodeURIComponent(webhook.id)}/test`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({}) },\n { fallback: null },\n )\n if (!call.ok || !call.result) {\n flash(t('webhooks.detail.testError'), 'error')\n return\n }\n const deliveryStatus = call.result.delivery.status\n setTestDelivery(call.result.delivery)\n flash(\n deliveryStatus === 'delivered' ? t('webhooks.detail.testSuccess') : t('webhooks.detail.testQueued'),\n deliveryStatus === 'delivered' ? 'success' : 'error',\n )\n void refreshDeliveryState()\n } catch {\n flash(t('webhooks.detail.testError'), 'error')\n }\n }, [refreshDeliveryState, t, webhook])\n\n const handleRetryDelivery = React.useCallback(async (deliveryId: string) => {\n try {\n const call = await apiCall(\n `/api/webhooks/deliveries/${encodeURIComponent(deliveryId)}/retry`,\n { method: 'POST' },\n { fallback: null },\n )\n if (!call.ok) {\n flash(t('webhooks.deliveries.retryError'), 'error')\n return\n }\n flash(t('webhooks.deliveries.retrySuccess'), 'success')\n void refreshDeliveryState()\n } catch {\n flash(t('webhooks.deliveries.retryError'), 'error')\n }\n }, [refreshDeliveryState, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!webhook) return\n try {\n await deleteCrud(`webhooks/${encodeURIComponent(webhook.id)}`, { fallbackResult: null })\n flash(t('webhooks.list.deleteSuccess'), 'success')\n router.push('/backend/webhooks')\n } catch {\n flash(t('webhooks.list.deleteError'), 'error')\n }\n }, [router, t, webhook])\n\n const handleDeliveryOpen = React.useCallback(async (deliveryId: string) => {\n setSelectedDeliveryLoading(true)\n try {\n const detail = await fetchDeliveryDetail(deliveryId)\n if (!detail) {\n flash(t('webhooks.deliveries.loadError'), 'error')\n return\n }\n setSelectedDelivery(detail)\n } catch {\n flash(t('webhooks.deliveries.loadError'), 'error')\n } finally {\n setSelectedDeliveryLoading(false)\n }\n }, [fetchDeliveryDetail, t])\n\n const deliveryColumns = React.useMemo<ColumnDef<DeliveryRow>[]>(() => [\n { accessorKey: 'eventType', header: t('webhooks.deliveries.columns.event') },\n {\n accessorKey: 'status',\n header: t('webhooks.deliveries.columns.status'),\n cell: ({ row }) => (\n <Badge variant={statusVariantMap[row.original.status] ?? 'secondary'}>\n {t(`webhooks.deliveries.status.${row.original.status}` as Parameters<typeof t>[0])}\n </Badge>\n ),\n },\n {\n accessorKey: 'responseStatus',\n header: t('webhooks.deliveries.columns.responseStatus'),\n cell: ({ row }) => row.original.responseStatus ?? '\u2014',\n },\n {\n accessorKey: 'attemptNumber',\n header: t('webhooks.deliveries.columns.attempts'),\n cell: ({ row }) => `${row.original.attemptNumber}/${row.original.maxAttempts}`,\n },\n {\n accessorKey: 'durationMs',\n header: t('webhooks.deliveries.columns.duration'),\n cell: ({ row }) => row.original.durationMs != null ? `${row.original.durationMs}ms` : '\u2014',\n },\n {\n accessorKey: 'createdAt',\n header: t('webhooks.deliveries.columns.enqueuedAt'),\n cell: ({ row }) => {\n try { return new Date(row.original.enqueuedAt).toLocaleString() }\n catch { return '\u2014' }\n },\n },\n ], [t])\n\n const fields = React.useMemo(() => buildWebhookFormFields(t), [t])\n const groups = React.useMemo(() => buildWebhookFormGroups(t), [t])\n const contentHeader = React.useMemo(() => buildWebhookFormContentHeader(t), [t])\n const menuActions = React.useMemo(() => {\n const items: Array<{ id: string; label: string; onSelect: () => void }> = []\n const isActive = webhook?.isActive ?? false\n\n if (access.canManage) {\n items.push(\n {\n id: 'edit',\n label: t('webhooks.list.actions.edit'),\n onSelect: () => setIsEditing(true),\n },\n {\n id: 'toggle-active',\n label: isActive ? t('webhooks.detail.actions.deactivate') : t('webhooks.detail.actions.activate'),\n onSelect: () => { void handleToggleActive() },\n },\n )\n }\n\n if (access.canSecrets) {\n items.push({\n id: 'rotate-secret',\n label: t('webhooks.detail.actions.rotateSecret'),\n onSelect: () => { void handleRotateSecret() },\n })\n }\n\n if (access.canTest) {\n items.push({\n id: 'test',\n label: t('webhooks.detail.actions.test'),\n onSelect: () => { void handleTest() },\n })\n }\n\n if (access.canManage) {\n items.push({\n id: 'delete',\n label: t('webhooks.list.actions.delete'),\n onSelect: () => { void handleDelete() },\n })\n }\n\n return items\n }, [access.canManage, access.canSecrets, access.canTest, handleDelete, handleRotateSecret, handleTest, handleToggleActive, t, webhook?.isActive])\n\n if (isLoading) return <Page><PageBody><LoadingMessage label={t('webhooks.detail.loading')} /></PageBody></Page>\n if (error || !webhook) return <Page><PageBody><ErrorMessage label={error ?? t('webhooks.errors.notFound')} /></PageBody></Page>\n\n if (isEditing) {\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('webhooks.form.title.edit')}\n backHref={`/backend/webhooks/${webhook.id}`}\n fields={fields}\n groups={groups}\n initialValues={createWebhookInitialValues(webhook)}\n submitLabel={t('common.save')}\n cancelHref={`/backend/webhooks/${webhook.id}`}\n contentHeader={contentHeader}\n onDelete={access.canManage ? handleDelete : undefined}\n onSubmit={async (values) => {\n const payload = normalizeWebhookFormPayload(values as WebhookFormValues, t)\n await updateCrud(`webhooks/${encodeURIComponent(webhook.id)}`, payload)\n flash(t('webhooks.form.updateSuccess'), 'success')\n setIsEditing(false)\n await refreshDeliveryState()\n }}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n {revealedSecret ? (\n <WebhookSecretPanel secret={revealedSecret} onClose={() => setRevealedSecret(null)} />\n ) : null}\n <FormHeader\n mode=\"detail\"\n title={webhook.name}\n entityTypeLabel={t('webhooks.nav.title')}\n statusBadge={\n <Badge\n className={webhook.isActive\n ? 'border-transparent bg-status-success-bg text-status-success-text'\n : 'border-transparent bg-status-neutral-bg text-status-neutral-text'}\n >\n {webhook.isActive ? t('webhooks.list.status.active') : t('webhooks.list.status.inactive')}\n </Badge>\n }\n backHref=\"/backend/webhooks\"\n menuActions={menuActions}\n />\n\n <div className=\"mt-6 space-y-4\">\n {!access.isLoading && !access.canManage && !access.canSecrets && !access.canTest ? (\n <Alert variant=\"info\">\n <AlertDescription>{t('webhooks.detail.readOnlyTip')}</AlertDescription>\n </Alert>\n ) : null}\n <div className=\"grid gap-3 lg:grid-cols-2\">\n <Alert variant=\"info\">\n <AlertDescription>{t('webhooks.detail.deliveryTip')}</AlertDescription>\n </Alert>\n <Alert variant=\"info\">\n <AlertDescription>{t('webhooks.detail.signatureTip')}</AlertDescription>\n </Alert>\n </div>\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.url')}:</span>\n <code className=\"ml-2 text-xs break-all\">{webhook.url}</code>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.httpMethod')}:</span>\n <span className=\"ml-2\">{webhook.httpMethod}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.subscribedEvents')}:</span>\n <span className=\"ml-2 text-xs\">{webhook.subscribedEvents.join(', ')}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.maxRetries')}:</span>\n <span className=\"ml-2\">{webhook.maxRetries}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.rateLimitPerMinute')}:</span>\n <span className=\"ml-2\">{webhook.rateLimitPerMinute}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.autoDisableThreshold')}:</span>\n <span className=\"ml-2\">{webhook.autoDisableThreshold}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.detail.consecutiveFailures')}:</span>\n <span className=\"ml-2\">{webhook.consecutiveFailures}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.form.secret')}:</span>\n <span className=\"ml-2 inline-flex items-center gap-2\">\n <span className=\"font-mono text-xs\">{webhook.maskedSecret}</span>\n {access.canSecrets ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-7 px-2 text-xs\"\n onClick={() => { void handleRotateSecret() }}\n >\n <RotateCw className=\"mr-1.5 size-3.5\" />\n {t('webhooks.detail.actions.rotateSecret')}\n </Button>\n ) : null}\n </span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.list.columns.lastDelivery')}:</span>\n <span className=\"ml-2\">{webhook.lastSuccessAt ?? webhook.lastFailureAt ?? '\u2014'}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.detail.previousSecretSetAt')}:</span>\n <span className=\"ml-2\">{webhook.previousSecretSetAt ?? '\u2014'}</span>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-muted-foreground\">{t('webhooks.form.customHeaders')}:</span>\n <pre className=\"mt-2 rounded border bg-muted/50 p-3 text-xs\">\n {webhook.customHeaders ? JSON.stringify(webhook.customHeaders, null, 2) : '\u2014'}\n </pre>\n </div>\n </div>\n </div>\n\n {testDelivery ? (\n <div className=\"mt-8 rounded-lg border bg-card p-4\">\n <h2 className=\"text-sm font-semibold\">{t('webhooks.detail.testResult')}</h2>\n <div className=\"mt-3 grid gap-2 text-sm\">\n <div>{t('webhooks.deliveries.columns.status')}: {testDelivery.status}</div>\n <div>{t('webhooks.deliveries.columns.responseStatus')}: {testDelivery.responseStatus ?? '\u2014'}</div>\n <div>{t('webhooks.deliveries.columns.duration')}: {testDelivery.durationMs != null ? `${testDelivery.durationMs}ms` : '\u2014'}</div>\n <pre className=\"overflow-auto rounded border bg-muted/50 p-3 text-xs\">\n {JSON.stringify(testDelivery.payload, null, 2)}\n </pre>\n </div>\n </div>\n ) : null}\n\n <div className=\"mt-8\">\n <DataTable\n title={t('webhooks.deliveries.title')}\n actions={(\n <div className=\"flex items-center gap-2\">\n <span className=\"hidden text-xs text-muted-foreground md:inline\">\n {t('webhooks.deliveries.autoRefreshHint')}\n </span>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => { void refreshDeliveryState() }}\n disabled={isRefreshingDeliveries}\n >\n {isRefreshingDeliveries\n ? t('webhooks.deliveries.refreshing')\n : t('webhooks.deliveries.refresh')}\n </Button>\n </div>\n )}\n columns={deliveryColumns}\n data={deliveries}\n onRowClick={(row) => { void handleDeliveryOpen(row.id) }}\n rowActions={(row) => {\n const items: Array<{ id: string; label: string; onSelect: () => void }> = [\n {\n id: 'view-details',\n label: t('webhooks.deliveries.actions.viewDetails'),\n onSelect: () => { void handleDeliveryOpen(row.id) },\n },\n ]\n\n if (access.canManage && (row.status === 'failed' || row.status === 'expired')) {\n items.push({\n id: 'retry',\n label: t('webhooks.deliveries.actions.retry'),\n onSelect: () => { void handleRetryDelivery(row.id) },\n })\n }\n\n return <RowActions items={items} />\n }}\n perspective={{ tableId: 'webhooks.deliveries' }}\n pagination={{\n page: deliveryPage,\n pageSize: 20,\n total: deliveryTotal,\n totalPages: deliveryTotalPages,\n onPageChange: setDeliveryPage,\n }}\n isLoading={deliveriesLoading || isRefreshingDeliveries}\n />\n </div>\n\n {selectedDelivery || selectedDeliveryLoading ? (\n <div className=\"mt-6 rounded-lg border bg-card p-4\">\n <h2 className=\"text-sm font-semibold\">{t('webhooks.deliveries.detailTitle')}</h2>\n {selectedDeliveryLoading || !selectedDelivery ? (\n <div className=\"mt-3 text-sm text-muted-foreground\">{t('common.loading')}</div>\n ) : (\n <div className=\"mt-3 space-y-4 text-sm\">\n <div>{t('webhooks.deliveries.columns.status')}: {selectedDelivery.status}</div>\n <div>{t('webhooks.deliveries.columns.responseStatus')}: {selectedDelivery.responseStatus ?? '\u2014'}</div>\n <div>{t('webhooks.deliveries.columns.duration')}: {selectedDelivery.durationMs != null ? `${selectedDelivery.durationMs}ms` : '\u2014'}</div>\n <div>\n <div className=\"mb-2 font-medium\">{t('webhooks.deliveries.requestBody')}</div>\n <pre className=\"overflow-auto rounded border bg-muted/50 p-3 text-xs\">\n {JSON.stringify(selectedDelivery.payload, null, 2)}\n </pre>\n </div>\n <div>\n <div className=\"mb-2 font-medium\">{t('webhooks.deliveries.responseBody')}</div>\n <pre className=\"overflow-auto rounded border bg-muted/50 p-3 text-xs\">\n {selectedDelivery.responseBody ?? '\u2014'}\n </pre>\n </div>\n <div>\n <div className=\"mb-2 font-medium\">{t('webhooks.deliveries.responseHeaders')}</div>\n <pre className=\"overflow-auto rounded border bg-muted/50 p-3 text-xs\">\n {selectedDelivery.responseHeaders ? JSON.stringify(selectedDelivery.responseHeaders, null, 2) : '\u2014'}\n </pre>\n </div>\n </div>\n )}\n </div>\n ) : null}\n </PageBody>\n </Page>\n )\n}\n\nfunction resolveWebhookId(paramValue: string | string[] | undefined, pathname: string | null): string | null {\n if (typeof paramValue === 'string' && paramValue.trim().length > 0) {\n return paramValue\n }\n\n if (Array.isArray(paramValue)) {\n const first = paramValue.find((value) => typeof value === 'string' && value.trim().length > 0)\n if (first) return first\n }\n\n if (typeof pathname === 'string') {\n const match = pathname.match(/\\/backend\\/webhooks\\/([^/?#]+)/)\n if (match?.[1]) {\n return decodeURIComponent(match[1])\n }\n }\n\n return null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["params"]
|
|
7
7
|
}
|
|
@@ -158,7 +158,7 @@ function WebhooksListPage() {
|
|
|
158
158
|
{
|
|
159
159
|
accessorKey: "isActive",
|
|
160
160
|
header: t("webhooks.list.columns.status"),
|
|
161
|
-
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.original.isActive ? "bg-
|
|
161
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.original.isActive ? "bg-status-success-bg text-status-success-text" : "bg-status-neutral-bg text-status-neutral-text"}`, children: row.original.isActive ? t("webhooks.list.status.active") : t("webhooks.list.status.inactive") })
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
164
|
accessorKey: "lastSuccessAt",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/webhooks/backend/webhooks/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { useWebhookFeatureAccess } from './useWebhookFeatureAccess'\n\ntype Row = {\n id: string\n name: string\n description: string | null\n url: string\n subscribedEvents: string[]\n httpMethod: string\n isActive: boolean\n deliveryStrategy: string\n maxRetries: number\n consecutiveFailures: number\n lastSuccessAt: string | null\n lastFailureAt: string | null\n createdAt: string\n updatedAt: string\n}\n\ntype ResponsePayload = {\n items: Row[]\n total: number\n page: number\n totalPages: number\n}\n\nexport default function WebhooksListPage() {\n const [rows, setRows] = React.useState<Row[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n const scopeVersion = useOrganizationScopeVersion()\n const t = useT()\n const router = useRouter()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const access = useWebhookFeatureAccess()\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n try {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', '20')\n if (search) params.set('search', search)\n if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('isActive', filterValues.status)\n }\n const fallback: ResponsePayload = { items: [], total: 0, page, totalPages: 1 }\n const call = await apiCall<ResponsePayload>(\n `/api/webhooks?${params.toString()}`,\n undefined,\n { fallback },\n )\n if (!call.ok) {\n const errorPayload = call.result as { error?: string } | undefined\n const message = typeof errorPayload?.error === 'string' ? errorPayload.error : t('webhooks.list.loadError')\n flash(message, 'error')\n return\n }\n const payload = call.result ?? fallback\n if (!cancelled) {\n setRows(Array.isArray(payload.items) ? payload.items : [])\n setTotal(payload.total || 0)\n setTotalPages(payload.totalPages || 1)\n }\n } catch (error) {\n if (!cancelled) {\n const message = error instanceof Error ? error.message : t('webhooks.list.loadError')\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [filterValues.status, page, search, reloadToken, scopeVersion, t])\n\n const handleDelete = React.useCallback(async (row: Row) => {\n const confirmed = await confirm({\n title: t('webhooks.list.confirmDelete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n const call = await apiCall<{ error?: string }>(\n `/api/webhooks/${encodeURIComponent(row.id)}`,\n { method: 'DELETE' },\n { fallback: null },\n )\n if (!call.ok) {\n const errorPayload = call.result as { error?: string } | undefined\n const message = typeof errorPayload?.error === 'string' ? errorPayload.error : t('webhooks.list.deleteError')\n flash(message, 'error')\n return\n }\n flash(t('webhooks.list.deleteSuccess'), 'success')\n setReloadToken((token) => token + 1)\n } catch (error) {\n const message = error instanceof Error ? error.message : t('webhooks.list.deleteError')\n flash(message, 'error')\n }\n }, [confirm, t])\n\n const handleToggleActive = React.useCallback(async (row: Row) => {\n try {\n const call = await apiCall<Row>(\n `/api/webhooks/${encodeURIComponent(row.id)}`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ isActive: !row.isActive }),\n },\n { fallback: null },\n )\n if (!call.ok) {\n flash(t('webhooks.form.updateError'), 'error')\n return\n }\n flash(t('webhooks.form.updateSuccess'), 'success')\n setReloadToken((token) => token + 1)\n } catch (error) {\n flash(error instanceof Error ? error.message : t('webhooks.form.updateError'), 'error')\n }\n }, [t])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'status',\n label: t('webhooks.list.filters.status'),\n type: 'select',\n options: [\n { value: 'true', label: t('webhooks.list.status.active') },\n { value: 'false', label: t('webhooks.list.status.inactive') },\n ],\n },\n ], [t])\n\n const columns = React.useMemo<ColumnDef<Row>[]>(() => [\n {\n accessorKey: 'name',\n header: t('webhooks.list.columns.name'),\n cell: ({ row }) => (\n <Link href={`/backend/webhooks/${row.original.id}`} className=\"font-medium text-primary hover:underline\">\n {row.original.name}\n </Link>\n ),\n },\n {\n accessorKey: 'url',\n header: t('webhooks.list.columns.url'),\n cell: ({ row }) => (\n <code className=\"text-xs truncate max-w-[200px] block\" title={row.original.url}>{row.original.url}</code>\n ),\n meta: { truncate: true, maxWidth: 250 },\n },\n {\n accessorKey: 'subscribedEvents',\n header: t('webhooks.list.columns.events'),\n cell: ({ row }) => {\n const events = row.original.subscribedEvents\n if (events.length === 0) return <span className=\"text-muted-foreground text-xs\">\u2014</span>\n if (events.length <= 2) return <span className=\"text-xs\">{events.join(', ')}</span>\n return <span className=\"text-xs\">{events.slice(0, 2).join(', ')} +{events.length - 2}</span>\n },\n },\n {\n accessorKey: 'isActive',\n header: t('webhooks.list.columns.status'),\n cell: ({ row }) => (\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.original.isActive ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' : 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400'}`}>\n {row.original.isActive ? t('webhooks.list.status.active') : t('webhooks.list.status.inactive')}\n </span>\n ),\n },\n {\n accessorKey: 'lastSuccessAt',\n header: t('webhooks.list.columns.lastDelivery'),\n cell: ({ row }) => {\n const lastSuccessAt = row.original.lastSuccessAt ? new Date(row.original.lastSuccessAt).getTime() : null\n const lastFailureAt = row.original.lastFailureAt ? new Date(row.original.lastFailureAt).getTime() : null\n const lastTimestamp = Math.max(lastSuccessAt ?? 0, lastFailureAt ?? 0)\n if (!lastTimestamp) return <span className=\"text-muted-foreground\">\u2014</span>\n const isFailure = lastFailureAt !== null && lastFailureAt >= (lastSuccessAt ?? 0)\n return (\n <span className={isFailure ? 'text-destructive' : 'text-muted-foreground'}>\n {new Date(lastTimestamp).toLocaleString()}\n </span>\n )\n },\n },\n {\n accessorKey: 'createdAt',\n header: t('webhooks.list.columns.createdAt'),\n cell: ({ row }) => {\n try {\n return new Date(row.original.createdAt).toLocaleDateString()\n } catch {\n return '\u2014'\n }\n },\n },\n ], [t])\n\n return (\n <Page>\n <PageBody className=\"space-y-4\">\n <Alert variant=\"info\">\n <AlertTitle>{t('webhooks.list.description')}</AlertTitle>\n <AlertDescription>{t('webhooks.list.operatorTip')}</AlertDescription>\n </Alert>\n <DataTable\n title={t('webhooks.list.title')}\n actions={access.canManage ? (\n <Button asChild>\n <Link href=\"/backend/webhooks/create\">{t('webhooks.nav.create')}</Link>\n </Button>\n ) : undefined}\n columns={columns}\n data={rows}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(next) => {\n setFilterValues(next)\n setPage(1)\n }}\n onFiltersClear={() => {\n setFilterValues({})\n setPage(1)\n }}\n perspective={{ tableId: 'webhooks.list' }}\n rowActions={(row) => {\n const items = [\n {\n id: 'view-deliveries',\n label: t('webhooks.list.actions.viewDeliveries'),\n onSelect: () => { router.push(`/backend/webhooks/${row.id}`) },\n },\n ]\n\n if (access.canManage) {\n items.unshift(\n { id: 'edit', label: t('webhooks.list.actions.edit'), onSelect: () => { router.push(`/backend/webhooks/${row.id}`) } },\n {\n id: 'toggle-active',\n label: row.isActive ? t('webhooks.detail.actions.deactivate') : t('webhooks.detail.actions.activate'),\n onSelect: () => { void handleToggleActive(row) },\n },\n )\n items.push({ id: 'delete', label: t('webhooks.list.actions.delete'), onSelect: () => { void handleDelete(row) } })\n }\n\n return <RowActions items={items} />\n }}\n pagination={{ page, pageSize: 20, total, totalPages, onPageChange: setPage }}\n isLoading={isLoading}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { useWebhookFeatureAccess } from './useWebhookFeatureAccess'\n\ntype Row = {\n id: string\n name: string\n description: string | null\n url: string\n subscribedEvents: string[]\n httpMethod: string\n isActive: boolean\n deliveryStrategy: string\n maxRetries: number\n consecutiveFailures: number\n lastSuccessAt: string | null\n lastFailureAt: string | null\n createdAt: string\n updatedAt: string\n}\n\ntype ResponsePayload = {\n items: Row[]\n total: number\n page: number\n totalPages: number\n}\n\nexport default function WebhooksListPage() {\n const [rows, setRows] = React.useState<Row[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n const scopeVersion = useOrganizationScopeVersion()\n const t = useT()\n const router = useRouter()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const access = useWebhookFeatureAccess()\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n try {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', '20')\n if (search) params.set('search', search)\n if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('isActive', filterValues.status)\n }\n const fallback: ResponsePayload = { items: [], total: 0, page, totalPages: 1 }\n const call = await apiCall<ResponsePayload>(\n `/api/webhooks?${params.toString()}`,\n undefined,\n { fallback },\n )\n if (!call.ok) {\n const errorPayload = call.result as { error?: string } | undefined\n const message = typeof errorPayload?.error === 'string' ? errorPayload.error : t('webhooks.list.loadError')\n flash(message, 'error')\n return\n }\n const payload = call.result ?? fallback\n if (!cancelled) {\n setRows(Array.isArray(payload.items) ? payload.items : [])\n setTotal(payload.total || 0)\n setTotalPages(payload.totalPages || 1)\n }\n } catch (error) {\n if (!cancelled) {\n const message = error instanceof Error ? error.message : t('webhooks.list.loadError')\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [filterValues.status, page, search, reloadToken, scopeVersion, t])\n\n const handleDelete = React.useCallback(async (row: Row) => {\n const confirmed = await confirm({\n title: t('webhooks.list.confirmDelete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n const call = await apiCall<{ error?: string }>(\n `/api/webhooks/${encodeURIComponent(row.id)}`,\n { method: 'DELETE' },\n { fallback: null },\n )\n if (!call.ok) {\n const errorPayload = call.result as { error?: string } | undefined\n const message = typeof errorPayload?.error === 'string' ? errorPayload.error : t('webhooks.list.deleteError')\n flash(message, 'error')\n return\n }\n flash(t('webhooks.list.deleteSuccess'), 'success')\n setReloadToken((token) => token + 1)\n } catch (error) {\n const message = error instanceof Error ? error.message : t('webhooks.list.deleteError')\n flash(message, 'error')\n }\n }, [confirm, t])\n\n const handleToggleActive = React.useCallback(async (row: Row) => {\n try {\n const call = await apiCall<Row>(\n `/api/webhooks/${encodeURIComponent(row.id)}`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ isActive: !row.isActive }),\n },\n { fallback: null },\n )\n if (!call.ok) {\n flash(t('webhooks.form.updateError'), 'error')\n return\n }\n flash(t('webhooks.form.updateSuccess'), 'success')\n setReloadToken((token) => token + 1)\n } catch (error) {\n flash(error instanceof Error ? error.message : t('webhooks.form.updateError'), 'error')\n }\n }, [t])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'status',\n label: t('webhooks.list.filters.status'),\n type: 'select',\n options: [\n { value: 'true', label: t('webhooks.list.status.active') },\n { value: 'false', label: t('webhooks.list.status.inactive') },\n ],\n },\n ], [t])\n\n const columns = React.useMemo<ColumnDef<Row>[]>(() => [\n {\n accessorKey: 'name',\n header: t('webhooks.list.columns.name'),\n cell: ({ row }) => (\n <Link href={`/backend/webhooks/${row.original.id}`} className=\"font-medium text-primary hover:underline\">\n {row.original.name}\n </Link>\n ),\n },\n {\n accessorKey: 'url',\n header: t('webhooks.list.columns.url'),\n cell: ({ row }) => (\n <code className=\"text-xs truncate max-w-[200px] block\" title={row.original.url}>{row.original.url}</code>\n ),\n meta: { truncate: true, maxWidth: 250 },\n },\n {\n accessorKey: 'subscribedEvents',\n header: t('webhooks.list.columns.events'),\n cell: ({ row }) => {\n const events = row.original.subscribedEvents\n if (events.length === 0) return <span className=\"text-muted-foreground text-xs\">\u2014</span>\n if (events.length <= 2) return <span className=\"text-xs\">{events.join(', ')}</span>\n return <span className=\"text-xs\">{events.slice(0, 2).join(', ')} +{events.length - 2}</span>\n },\n },\n {\n accessorKey: 'isActive',\n header: t('webhooks.list.columns.status'),\n cell: ({ row }) => (\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.original.isActive ? 'bg-status-success-bg text-status-success-text' : 'bg-status-neutral-bg text-status-neutral-text'}`}>\n {row.original.isActive ? t('webhooks.list.status.active') : t('webhooks.list.status.inactive')}\n </span>\n ),\n },\n {\n accessorKey: 'lastSuccessAt',\n header: t('webhooks.list.columns.lastDelivery'),\n cell: ({ row }) => {\n const lastSuccessAt = row.original.lastSuccessAt ? new Date(row.original.lastSuccessAt).getTime() : null\n const lastFailureAt = row.original.lastFailureAt ? new Date(row.original.lastFailureAt).getTime() : null\n const lastTimestamp = Math.max(lastSuccessAt ?? 0, lastFailureAt ?? 0)\n if (!lastTimestamp) return <span className=\"text-muted-foreground\">\u2014</span>\n const isFailure = lastFailureAt !== null && lastFailureAt >= (lastSuccessAt ?? 0)\n return (\n <span className={isFailure ? 'text-destructive' : 'text-muted-foreground'}>\n {new Date(lastTimestamp).toLocaleString()}\n </span>\n )\n },\n },\n {\n accessorKey: 'createdAt',\n header: t('webhooks.list.columns.createdAt'),\n cell: ({ row }) => {\n try {\n return new Date(row.original.createdAt).toLocaleDateString()\n } catch {\n return '\u2014'\n }\n },\n },\n ], [t])\n\n return (\n <Page>\n <PageBody className=\"space-y-4\">\n <Alert variant=\"info\">\n <AlertTitle>{t('webhooks.list.description')}</AlertTitle>\n <AlertDescription>{t('webhooks.list.operatorTip')}</AlertDescription>\n </Alert>\n <DataTable\n title={t('webhooks.list.title')}\n actions={access.canManage ? (\n <Button asChild>\n <Link href=\"/backend/webhooks/create\">{t('webhooks.nav.create')}</Link>\n </Button>\n ) : undefined}\n columns={columns}\n data={rows}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(next) => {\n setFilterValues(next)\n setPage(1)\n }}\n onFiltersClear={() => {\n setFilterValues({})\n setPage(1)\n }}\n perspective={{ tableId: 'webhooks.list' }}\n rowActions={(row) => {\n const items = [\n {\n id: 'view-deliveries',\n label: t('webhooks.list.actions.viewDeliveries'),\n onSelect: () => { router.push(`/backend/webhooks/${row.id}`) },\n },\n ]\n\n if (access.canManage) {\n items.unshift(\n { id: 'edit', label: t('webhooks.list.actions.edit'), onSelect: () => { router.push(`/backend/webhooks/${row.id}`) } },\n {\n id: 'toggle-active',\n label: row.isActive ? t('webhooks.detail.actions.deactivate') : t('webhooks.detail.actions.activate'),\n onSelect: () => { void handleToggleActive(row) },\n },\n )\n items.push({ id: 'delete', label: t('webhooks.list.actions.delete'), onSelect: () => { void handleDelete(row) } })\n }\n\n return <RowActions items={items} />\n }}\n pagination={{ page, pageSize: 20, total, totalPages, onPageChange: setPage }}\n isLoading={isLoading}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -234,7 +234,7 @@ function IntegrationDeliveriesWidget(_props) {
|
|
|
234
234
|
className: "p-4"
|
|
235
235
|
}
|
|
236
236
|
),
|
|
237
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-muted/
|
|
237
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-muted/30 p-4", children: [
|
|
238
238
|
/* @__PURE__ */ jsx("div", { className: "mb-2 text-sm font-medium", children: t("webhooks.deliveries.responseBody") }),
|
|
239
239
|
/* @__PURE__ */ jsx("pre", { className: "overflow-auto whitespace-pre-wrap break-words text-xs", children: selectedDelivery.responseBody ?? "\u2014" })
|
|
240
240
|
] }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/webhooks/widgets/injection/integration-deliveries/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { JsonDisplay } from '@open-mercato/ui/backend/JsonDisplay'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\ntype DeliveryRow = {\n id: string\n webhookId: string\n webhookName: string | null\n eventType: string\n messageId: string\n status: string\n responseStatus: number | null\n errorMessage: string | null\n attemptNumber: number\n maxAttempts: number\n durationMs: number | null\n targetUrl: string\n enqueuedAt: string\n lastAttemptAt: string | null\n deliveredAt: string | null\n createdAt: string\n}\n\ntype DeliveryResponse = {\n items: DeliveryRow[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ntype DeliveryDetail = DeliveryRow & {\n payload: Record<string, unknown>\n responseBody: string | null\n responseHeaders: Record<string, string> | null\n nextRetryAt: string | null\n updatedAt: string\n}\n\nconst statusVariantMap: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n delivered: 'default',\n pending: 'secondary',\n sending: 'outline',\n failed: 'destructive',\n expired: 'destructive',\n}\n\nexport default function IntegrationDeliveriesWidget(_props: InjectionWidgetComponentProps) {\n const t = useT()\n const [items, setItems] = React.useState<DeliveryRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [status, setStatus] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [selectedRow, setSelectedRow] = React.useState<DeliveryRow | null>(null)\n const [selectedDelivery, setSelectedDelivery] = React.useState<DeliveryDetail | null>(null)\n const [selectedDeliveryLoading, setSelectedDeliveryLoading] = React.useState(false)\n const [refreshToken, setRefreshToken] = React.useState(0)\n\n const reload = React.useCallback(() => {\n setRefreshToken((current) => current + 1)\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n\n async function loadDeliveries() {\n setIsLoading(true)\n\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '20',\n })\n if (status) params.set('status', status)\n\n const call = await apiCall<DeliveryResponse>(\n `/api/webhooks/deliveries?${params.toString()}`,\n undefined,\n {\n fallback: {\n items: [],\n total: 0,\n page,\n pageSize: 20,\n totalPages: 1,\n },\n },\n )\n\n if (!cancelled && call.ok && call.result) {\n setItems(call.result.items)\n setTotal(call.result.total)\n setTotalPages(call.result.totalPages)\n }\n } catch {\n if (!cancelled) {\n flash(t('webhooks.integrationDeliveries.loadError', 'Failed to load webhook deliveries.'), 'error')\n }\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n\n void loadDeliveries()\n\n return () => {\n cancelled = true\n }\n }, [page, refreshToken, status, t])\n\n const handleDeliveryOpen = React.useCallback(async (row: DeliveryRow) => {\n setSelectedRow(row)\n setSelectedDeliveryLoading(true)\n\n try {\n const call = await apiCall<DeliveryDetail>(\n `/api/webhooks/deliveries/${encodeURIComponent(row.id)}`,\n undefined,\n { fallback: null },\n )\n\n if (!call.ok || !call.result) {\n flash(t('webhooks.deliveries.loadError'), 'error')\n return\n }\n\n setSelectedDelivery(call.result)\n } catch {\n flash(t('webhooks.deliveries.loadError'), 'error')\n } finally {\n setSelectedDeliveryLoading(false)\n }\n }, [t])\n\n const columns = React.useMemo<ColumnDef<DeliveryRow>[]>(() => [\n {\n accessorKey: 'webhookName',\n header: t('webhooks.integrationDeliveries.columns.webhook', 'Webhook'),\n cell: ({ row }) => (\n <Link href={`/backend/webhooks/${row.original.webhookId}`} className=\"font-medium hover:underline\">\n {row.original.webhookName ?? row.original.webhookId}\n </Link>\n ),\n },\n {\n accessorKey: 'eventType',\n header: t('webhooks.deliveries.columns.event'),\n },\n {\n accessorKey: 'status',\n header: t('webhooks.deliveries.columns.status'),\n cell: ({ row }) => (\n <Badge variant={statusVariantMap[row.original.status] ?? 'secondary'}>\n {t(`webhooks.deliveries.status.${row.original.status}` as Parameters<typeof t>[0])}\n </Badge>\n ),\n },\n {\n accessorKey: 'responseStatus',\n header: t('webhooks.deliveries.columns.responseStatus'),\n cell: ({ row }) => row.original.responseStatus ?? '\u2014',\n },\n {\n accessorKey: 'attemptNumber',\n header: t('webhooks.deliveries.columns.attempts'),\n cell: ({ row }) => `${row.original.attemptNumber}/${row.original.maxAttempts}`,\n },\n {\n accessorKey: 'enqueuedAt',\n header: t('webhooks.deliveries.columns.enqueuedAt'),\n cell: ({ row }) => {\n try {\n return new Date(row.original.enqueuedAt).toLocaleString()\n } catch {\n return '\u2014'\n }\n },\n },\n ], [t])\n\n return (\n <div className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'webhooks.integrationDeliveries.summary',\n 'Review delivery attempts across every configured webhook endpoint. Open a row to inspect the request and response payloads.',\n )}\n </p>\n\n <DataTable\n title={t('webhooks.deliveries.title')}\n columns={columns}\n data={items}\n onRowClick={(row) => { void handleDeliveryOpen(row) }}\n toolbar={(\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n className=\"h-10 rounded-md border border-input bg-background px-3 text-sm\"\n value={status}\n onChange={(event) => {\n setPage(1)\n setStatus(event.target.value)\n }}\n >\n <option value=\"\">{t('webhooks.integrationDeliveries.filters.allStatuses', 'All statuses')}</option>\n <option value=\"pending\">{t('webhooks.deliveries.status.pending')}</option>\n <option value=\"sending\">{t('webhooks.deliveries.status.sending')}</option>\n <option value=\"delivered\">{t('webhooks.deliveries.status.delivered')}</option>\n <option value=\"failed\">{t('webhooks.deliveries.status.failed')}</option>\n <option value=\"expired\">{t('webhooks.deliveries.status.expired')}</option>\n </select>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => reload()}>\n {t('common.refresh', 'Refresh')}\n </Button>\n </div>\n )}\n perspective={{ tableId: 'webhooks.integration-deliveries' }}\n pagination={{\n page,\n pageSize: 20,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n />\n\n {selectedRow || selectedDeliveryLoading ? (\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h2 className=\"text-sm font-semibold\">{t('webhooks.deliveries.detailTitle')}</h2>\n {selectedRow ? (\n <Button asChild type=\"button\" variant=\"outline\" size=\"sm\">\n <Link href={`/backend/webhooks/${selectedRow.webhookId}`}>\n {t('webhooks.integrationDeliveries.actions.openWebhook', 'Open webhook')}\n </Link>\n </Button>\n ) : null}\n </div>\n {selectedDeliveryLoading || !selectedDelivery ? (\n <div className=\"mt-3 flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n <span>{t('common.loading')}</span>\n </div>\n ) : (\n <div className=\"mt-3 space-y-4 text-sm\">\n <div className=\"grid gap-2 md:grid-cols-2\">\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.integrationDeliveries.columns.webhook', 'Webhook')}:</span>\n <span className=\"ml-2\">{selectedRow?.webhookName ?? selectedDelivery.webhookId}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.deliveries.columns.status')}:</span>\n <span className=\"ml-2\">{selectedDelivery.status}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.deliveries.columns.responseStatus')}:</span>\n <span className=\"ml-2\">{selectedDelivery.responseStatus ?? '\u2014'}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.deliveries.columns.duration')}:</span>\n <span className=\"ml-2\">{selectedDelivery.durationMs != null ? `${selectedDelivery.durationMs}ms` : '\u2014'}</span>\n </div>\n <div className=\"md:col-span-2\">\n <span className=\"text-muted-foreground\">{t('webhooks.integrationDeliveries.errorMessage', 'Error message')}:</span>\n <span className=\"ml-2\">{selectedDelivery.errorMessage ?? '\u2014'}</span>\n </div>\n </div>\n\n <JsonDisplay\n data={selectedDelivery.payload}\n title={t('webhooks.deliveries.requestBody')}\n defaultExpanded\n maxInitialDepth={2}\n theme=\"dark\"\n className=\"p-4\"\n />\n\n <div className=\"rounded-lg border bg-muted/20 p-4\">\n <div className=\"mb-2 text-sm font-medium\">{t('webhooks.deliveries.responseBody')}</div>\n <pre className=\"overflow-auto whitespace-pre-wrap break-words text-xs\">\n {selectedDelivery.responseBody ?? '\u2014'}\n </pre>\n </div>\n\n <JsonDisplay\n data={selectedDelivery.responseHeaders ?? {}}\n title={t('webhooks.deliveries.responseHeaders')}\n defaultExpanded\n maxInitialDepth={1}\n theme=\"dark\"\n className=\"p-4\"\n />\n </div>\n )}\n </div>\n ) : null}\n </div>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { JsonDisplay } from '@open-mercato/ui/backend/JsonDisplay'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\ntype DeliveryRow = {\n id: string\n webhookId: string\n webhookName: string | null\n eventType: string\n messageId: string\n status: string\n responseStatus: number | null\n errorMessage: string | null\n attemptNumber: number\n maxAttempts: number\n durationMs: number | null\n targetUrl: string\n enqueuedAt: string\n lastAttemptAt: string | null\n deliveredAt: string | null\n createdAt: string\n}\n\ntype DeliveryResponse = {\n items: DeliveryRow[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ntype DeliveryDetail = DeliveryRow & {\n payload: Record<string, unknown>\n responseBody: string | null\n responseHeaders: Record<string, string> | null\n nextRetryAt: string | null\n updatedAt: string\n}\n\nconst statusVariantMap: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n delivered: 'default',\n pending: 'secondary',\n sending: 'outline',\n failed: 'destructive',\n expired: 'destructive',\n}\n\nexport default function IntegrationDeliveriesWidget(_props: InjectionWidgetComponentProps) {\n const t = useT()\n const [items, setItems] = React.useState<DeliveryRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [status, setStatus] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [selectedRow, setSelectedRow] = React.useState<DeliveryRow | null>(null)\n const [selectedDelivery, setSelectedDelivery] = React.useState<DeliveryDetail | null>(null)\n const [selectedDeliveryLoading, setSelectedDeliveryLoading] = React.useState(false)\n const [refreshToken, setRefreshToken] = React.useState(0)\n\n const reload = React.useCallback(() => {\n setRefreshToken((current) => current + 1)\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n\n async function loadDeliveries() {\n setIsLoading(true)\n\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '20',\n })\n if (status) params.set('status', status)\n\n const call = await apiCall<DeliveryResponse>(\n `/api/webhooks/deliveries?${params.toString()}`,\n undefined,\n {\n fallback: {\n items: [],\n total: 0,\n page,\n pageSize: 20,\n totalPages: 1,\n },\n },\n )\n\n if (!cancelled && call.ok && call.result) {\n setItems(call.result.items)\n setTotal(call.result.total)\n setTotalPages(call.result.totalPages)\n }\n } catch {\n if (!cancelled) {\n flash(t('webhooks.integrationDeliveries.loadError', 'Failed to load webhook deliveries.'), 'error')\n }\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n\n void loadDeliveries()\n\n return () => {\n cancelled = true\n }\n }, [page, refreshToken, status, t])\n\n const handleDeliveryOpen = React.useCallback(async (row: DeliveryRow) => {\n setSelectedRow(row)\n setSelectedDeliveryLoading(true)\n\n try {\n const call = await apiCall<DeliveryDetail>(\n `/api/webhooks/deliveries/${encodeURIComponent(row.id)}`,\n undefined,\n { fallback: null },\n )\n\n if (!call.ok || !call.result) {\n flash(t('webhooks.deliveries.loadError'), 'error')\n return\n }\n\n setSelectedDelivery(call.result)\n } catch {\n flash(t('webhooks.deliveries.loadError'), 'error')\n } finally {\n setSelectedDeliveryLoading(false)\n }\n }, [t])\n\n const columns = React.useMemo<ColumnDef<DeliveryRow>[]>(() => [\n {\n accessorKey: 'webhookName',\n header: t('webhooks.integrationDeliveries.columns.webhook', 'Webhook'),\n cell: ({ row }) => (\n <Link href={`/backend/webhooks/${row.original.webhookId}`} className=\"font-medium hover:underline\">\n {row.original.webhookName ?? row.original.webhookId}\n </Link>\n ),\n },\n {\n accessorKey: 'eventType',\n header: t('webhooks.deliveries.columns.event'),\n },\n {\n accessorKey: 'status',\n header: t('webhooks.deliveries.columns.status'),\n cell: ({ row }) => (\n <Badge variant={statusVariantMap[row.original.status] ?? 'secondary'}>\n {t(`webhooks.deliveries.status.${row.original.status}` as Parameters<typeof t>[0])}\n </Badge>\n ),\n },\n {\n accessorKey: 'responseStatus',\n header: t('webhooks.deliveries.columns.responseStatus'),\n cell: ({ row }) => row.original.responseStatus ?? '\u2014',\n },\n {\n accessorKey: 'attemptNumber',\n header: t('webhooks.deliveries.columns.attempts'),\n cell: ({ row }) => `${row.original.attemptNumber}/${row.original.maxAttempts}`,\n },\n {\n accessorKey: 'enqueuedAt',\n header: t('webhooks.deliveries.columns.enqueuedAt'),\n cell: ({ row }) => {\n try {\n return new Date(row.original.enqueuedAt).toLocaleString()\n } catch {\n return '\u2014'\n }\n },\n },\n ], [t])\n\n return (\n <div className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'webhooks.integrationDeliveries.summary',\n 'Review delivery attempts across every configured webhook endpoint. Open a row to inspect the request and response payloads.',\n )}\n </p>\n\n <DataTable\n title={t('webhooks.deliveries.title')}\n columns={columns}\n data={items}\n onRowClick={(row) => { void handleDeliveryOpen(row) }}\n toolbar={(\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n className=\"h-10 rounded-md border border-input bg-background px-3 text-sm\"\n value={status}\n onChange={(event) => {\n setPage(1)\n setStatus(event.target.value)\n }}\n >\n <option value=\"\">{t('webhooks.integrationDeliveries.filters.allStatuses', 'All statuses')}</option>\n <option value=\"pending\">{t('webhooks.deliveries.status.pending')}</option>\n <option value=\"sending\">{t('webhooks.deliveries.status.sending')}</option>\n <option value=\"delivered\">{t('webhooks.deliveries.status.delivered')}</option>\n <option value=\"failed\">{t('webhooks.deliveries.status.failed')}</option>\n <option value=\"expired\">{t('webhooks.deliveries.status.expired')}</option>\n </select>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => reload()}>\n {t('common.refresh', 'Refresh')}\n </Button>\n </div>\n )}\n perspective={{ tableId: 'webhooks.integration-deliveries' }}\n pagination={{\n page,\n pageSize: 20,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n />\n\n {selectedRow || selectedDeliveryLoading ? (\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h2 className=\"text-sm font-semibold\">{t('webhooks.deliveries.detailTitle')}</h2>\n {selectedRow ? (\n <Button asChild type=\"button\" variant=\"outline\" size=\"sm\">\n <Link href={`/backend/webhooks/${selectedRow.webhookId}`}>\n {t('webhooks.integrationDeliveries.actions.openWebhook', 'Open webhook')}\n </Link>\n </Button>\n ) : null}\n </div>\n {selectedDeliveryLoading || !selectedDelivery ? (\n <div className=\"mt-3 flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n <span>{t('common.loading')}</span>\n </div>\n ) : (\n <div className=\"mt-3 space-y-4 text-sm\">\n <div className=\"grid gap-2 md:grid-cols-2\">\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.integrationDeliveries.columns.webhook', 'Webhook')}:</span>\n <span className=\"ml-2\">{selectedRow?.webhookName ?? selectedDelivery.webhookId}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.deliveries.columns.status')}:</span>\n <span className=\"ml-2\">{selectedDelivery.status}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.deliveries.columns.responseStatus')}:</span>\n <span className=\"ml-2\">{selectedDelivery.responseStatus ?? '\u2014'}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground\">{t('webhooks.deliveries.columns.duration')}:</span>\n <span className=\"ml-2\">{selectedDelivery.durationMs != null ? `${selectedDelivery.durationMs}ms` : '\u2014'}</span>\n </div>\n <div className=\"md:col-span-2\">\n <span className=\"text-muted-foreground\">{t('webhooks.integrationDeliveries.errorMessage', 'Error message')}:</span>\n <span className=\"ml-2\">{selectedDelivery.errorMessage ?? '\u2014'}</span>\n </div>\n </div>\n\n <JsonDisplay\n data={selectedDelivery.payload}\n title={t('webhooks.deliveries.requestBody')}\n defaultExpanded\n maxInitialDepth={2}\n theme=\"dark\"\n className=\"p-4\"\n />\n\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"mb-2 text-sm font-medium\">{t('webhooks.deliveries.responseBody')}</div>\n <pre className=\"overflow-auto whitespace-pre-wrap break-words text-xs\">\n {selectedDelivery.responseBody ?? '\u2014'}\n </pre>\n </div>\n\n <JsonDisplay\n data={selectedDelivery.responseHeaders ?? {}}\n title={t('webhooks.deliveries.responseHeaders')}\n defaultExpanded\n maxInitialDepth={1}\n theme=\"dark\"\n className=\"p-4\"\n />\n </div>\n )}\n </div>\n ) : null}\n </div>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -125,7 +125,7 @@ function IntegrationSetupWidget({ context }) {
|
|
|
125
125
|
t("webhooks.integrationSetup.actions.create", "Create webhook")
|
|
126
126
|
] }) })
|
|
127
127
|
] }),
|
|
128
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-muted/
|
|
128
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-muted/30 p-4", children: [
|
|
129
129
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between", children: [
|
|
130
130
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
131
131
|
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: t("webhooks.integrationSetup.notificationsTitle", "Failed delivery notifications") }),
|
|
@@ -167,7 +167,7 @@ function IntegrationSetupWidget({ context }) {
|
|
|
167
167
|
!isLoading && !error && items.length > 0 ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
168
168
|
"div",
|
|
169
169
|
{
|
|
170
|
-
className: "flex flex-col gap-3 rounded-lg border bg-muted/
|
|
170
|
+
className: "flex flex-col gap-3 rounded-lg border bg-muted/30 px-3 py-3 lg:flex-row lg:items-center lg:justify-between",
|
|
171
171
|
children: [
|
|
172
172
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
|
|
173
173
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/webhooks/widgets/injection/integration-setup/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { ExternalLink, PencilLine, Plus, Webhook } from 'lucide-react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { webhookCustomIntegrationId } from '../../../integration'\n\ntype WebhookIntegrationContext = {\n state?: {\n isEnabled?: boolean\n } | null\n}\n\ntype WebhookListItem = {\n id: string\n name: string\n url: string\n isActive: boolean\n subscribedEvents: string[]\n}\n\ntype WebhookListResponse = {\n items: WebhookListItem[]\n total: number\n}\n\ntype WebhookIntegrationCredentials = Record<string, string | number | boolean | null> & {\n notifyOnFailedDelivery?: boolean\n}\n\ntype WebhookCredentialsResponse = {\n credentials: WebhookIntegrationCredentials\n}\n\nexport default function IntegrationSetupWidget({ context }: InjectionWidgetComponentProps) {\n const t = useT()\n const typedContext = context as WebhookIntegrationContext | undefined\n const [items, setItems] = React.useState<WebhookListItem[]>([])\n const [total, setTotal] = React.useState(0)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [credentials, setCredentials] = React.useState<WebhookIntegrationCredentials>({})\n const [settingsError, setSettingsError] = React.useState<string | null>(null)\n const [isSavingSettings, setIsSavingSettings] = React.useState(false)\n\n React.useEffect(() => {\n let mounted = true\n\n const load = async () => {\n setIsLoading(true)\n setError(null)\n\n try {\n const [listCall, credentialsCall] = await Promise.all([\n apiCall<WebhookListResponse>(\n '/api/webhooks?page=1&pageSize=6',\n undefined,\n { fallback: { items: [], total: 0 } },\n ),\n apiCall<WebhookCredentialsResponse>(\n `/api/integrations/${encodeURIComponent(webhookCustomIntegrationId)}/credentials`,\n undefined,\n { fallback: null },\n ),\n ])\n\n if (!mounted) return\n\n if (!listCall.ok || !listCall.result) {\n setError(t('webhooks.integrationSetup.loadError', 'Failed to load configured webhooks.'))\n setItems([])\n setTotal(0)\n } else {\n setItems(listCall.result.items)\n setTotal(listCall.result.total)\n }\n\n if (credentialsCall.ok && credentialsCall.result?.credentials) {\n setCredentials(credentialsCall.result.credentials)\n setSettingsError(null)\n } else {\n setSettingsError(t('webhooks.integrationSetup.settingsLoadError', 'Failed to load webhook integration settings.'))\n }\n } catch {\n if (!mounted) return\n setError(t('webhooks.integrationSetup.loadError', 'Failed to load configured webhooks.'))\n setItems([])\n setTotal(0)\n setSettingsError(t('webhooks.integrationSetup.settingsLoadError', 'Failed to load webhook integration settings.'))\n } finally {\n if (mounted) setIsLoading(false)\n }\n }\n\n void load()\n\n return () => {\n mounted = false\n }\n }, [t])\n\n const isEnabled = typedContext?.state?.isEnabled !== false\n const notifyOnFailedDelivery = credentials.notifyOnFailedDelivery === true\n\n const handleToggleFailedDeliveryNotifications = React.useCallback(async (nextValue: boolean) => {\n const nextCredentials: WebhookIntegrationCredentials = {\n ...credentials,\n notifyOnFailedDelivery: nextValue,\n }\n\n setCredentials(nextCredentials)\n setIsSavingSettings(true)\n setSettingsError(null)\n\n try {\n const call = await apiCall(\n `/api/integrations/${encodeURIComponent(webhookCustomIntegrationId)}/credentials`,\n {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ credentials: nextCredentials }),\n },\n { fallback: null },\n )\n\n if (!call.ok) {\n setCredentials(credentials)\n setSettingsError(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'))\n flash(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'), 'error')\n return\n }\n\n flash(t('webhooks.integrationSetup.settingsSaveSuccess', 'Webhook integration settings saved.'), 'success')\n } catch {\n setCredentials(credentials)\n setSettingsError(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'))\n flash(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'), 'error')\n } finally {\n setIsSavingSettings(false)\n }\n }, [credentials, t])\n\n return (\n <div className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'webhooks.integrationSetup.summary',\n 'Manage Custom Webhooks from the dedicated webhook screen. Turning this integration off blocks outbound deliveries, test sends, retries, and inbound webhook receives.',\n )}\n </p>\n\n <Alert>\n <Webhook className=\"h-4 w-4\" />\n <AlertTitle>\n {isEnabled\n ? t('webhooks.integrationSetup.enabledTitle', 'Delivery processing is enabled')\n : t('webhooks.integrationSetup.disabledTitle', 'Delivery processing is disabled')}\n </AlertTitle>\n <AlertDescription>\n {isEnabled\n ? t('webhooks.integrationSetup.enabledBody', 'Your saved webhooks can send and receive traffic. Use the links below to review endpoints and open the delivery log on each webhook detail page.')\n : t('webhooks.integrationSetup.disabledBody', 'The integration switch is off, so webhook sends, retries, test deliveries, and inbound receives are blocked until you enable it again.')}\n </AlertDescription>\n </Alert>\n\n <div className=\"flex flex-wrap gap-3\">\n <Button asChild>\n <Link href=\"/backend/webhooks\">\n <ExternalLink className=\"mr-2 h-4 w-4\" />\n {t('webhooks.integrationSetup.actions.openList', 'Open webhook list')}\n </Link>\n </Button>\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/webhooks/create\">\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('webhooks.integrationSetup.actions.create', 'Create webhook')}\n </Link>\n </Button>\n </div>\n\n <div className=\"rounded-lg border bg-muted/10 p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"space-y-1\">\n <h4 className=\"text-sm font-semibold\">\n {t('webhooks.integrationSetup.notificationsTitle', 'Failed delivery notifications')}\n </h4>\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'webhooks.integrationSetup.notificationsBody',\n 'Notify admin users when a webhook delivery finally fails after retries are exhausted.',\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <Badge variant={notifyOnFailedDelivery ? 'default' : 'outline'}>\n {notifyOnFailedDelivery\n ? t('webhooks.integrationSetup.notificationsEnabled', 'Enabled')\n : t('webhooks.integrationSetup.notificationsDisabled', 'Disabled')}\n </Badge>\n <Switch\n checked={notifyOnFailedDelivery}\n disabled={isSavingSettings}\n onCheckedChange={(checked) => { void handleToggleFailedDeliveryNotifications(checked) }}\n />\n </div>\n </div>\n {settingsError ? (\n <div className=\"mt-3 rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-sm text-destructive\">\n {settingsError}\n </div>\n ) : null}\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <h4 className=\"text-sm font-semibold\">\n {t('webhooks.integrationSetup.configuredTitle', 'Configured webhooks')}\n </h4>\n {total > items.length ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('webhooks.integrationSetup.more', 'Showing {shown} of {total}.', {\n shown: String(items.length),\n total: String(total),\n })}\n </span>\n ) : null}\n </div>\n\n {isLoading ? (\n <div className=\"flex items-center gap-2 rounded-md border bg-muted/30 px-3 py-3 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n <span>{t('webhooks.integrationSetup.loading', 'Loading configured webhooks...')}</span>\n </div>\n ) : null}\n\n {!isLoading && error ? (\n <div className=\"rounded-md border border-destructive/30 bg-destructive/5 px-3 py-3 text-sm text-destructive\">\n {error}\n </div>\n ) : null}\n\n {!isLoading && !error && items.length === 0 ? (\n <div className=\"rounded-md border border-dashed px-3 py-4 text-sm text-muted-foreground\">\n {t('webhooks.integrationSetup.empty', 'No webhooks have been configured yet. Create one to start sending or receiving events.')}\n </div>\n ) : null}\n\n {!isLoading && !error && items.length > 0 ? (\n <div className=\"space-y-2\">\n {items.map((item) => (\n <div\n key={item.id}\n className=\"flex flex-col gap-3 rounded-lg border bg-muted/20 px-3 py-3 lg:flex-row lg:items-center lg:justify-between\"\n >\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-foreground\">{item.name}</span>\n <Badge variant={item.isActive ? 'default' : 'outline'}>\n {item.isActive\n ? t('webhooks.list.status.active', 'Active')\n : t('webhooks.list.status.inactive', 'Inactive')}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {t('webhooks.integrationSetup.eventCount', '{count} event patterns', {\n count: String(item.subscribedEvents.length),\n })}\n </span>\n </div>\n <code className=\"block truncate text-xs text-muted-foreground\">{item.url}</code>\n </div>\n\n <Button asChild variant=\"ghost\" size=\"sm\" className=\"w-fit\">\n <Link href={`/backend/webhooks/${encodeURIComponent(item.id)}`}>\n <PencilLine className=\"mr-2 h-4 w-4\" />\n {t('webhooks.integrationSetup.actions.edit', 'Edit webhook')}\n </Link>\n </Button>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { ExternalLink, PencilLine, Plus, Webhook } from 'lucide-react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { webhookCustomIntegrationId } from '../../../integration'\n\ntype WebhookIntegrationContext = {\n state?: {\n isEnabled?: boolean\n } | null\n}\n\ntype WebhookListItem = {\n id: string\n name: string\n url: string\n isActive: boolean\n subscribedEvents: string[]\n}\n\ntype WebhookListResponse = {\n items: WebhookListItem[]\n total: number\n}\n\ntype WebhookIntegrationCredentials = Record<string, string | number | boolean | null> & {\n notifyOnFailedDelivery?: boolean\n}\n\ntype WebhookCredentialsResponse = {\n credentials: WebhookIntegrationCredentials\n}\n\nexport default function IntegrationSetupWidget({ context }: InjectionWidgetComponentProps) {\n const t = useT()\n const typedContext = context as WebhookIntegrationContext | undefined\n const [items, setItems] = React.useState<WebhookListItem[]>([])\n const [total, setTotal] = React.useState(0)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [credentials, setCredentials] = React.useState<WebhookIntegrationCredentials>({})\n const [settingsError, setSettingsError] = React.useState<string | null>(null)\n const [isSavingSettings, setIsSavingSettings] = React.useState(false)\n\n React.useEffect(() => {\n let mounted = true\n\n const load = async () => {\n setIsLoading(true)\n setError(null)\n\n try {\n const [listCall, credentialsCall] = await Promise.all([\n apiCall<WebhookListResponse>(\n '/api/webhooks?page=1&pageSize=6',\n undefined,\n { fallback: { items: [], total: 0 } },\n ),\n apiCall<WebhookCredentialsResponse>(\n `/api/integrations/${encodeURIComponent(webhookCustomIntegrationId)}/credentials`,\n undefined,\n { fallback: null },\n ),\n ])\n\n if (!mounted) return\n\n if (!listCall.ok || !listCall.result) {\n setError(t('webhooks.integrationSetup.loadError', 'Failed to load configured webhooks.'))\n setItems([])\n setTotal(0)\n } else {\n setItems(listCall.result.items)\n setTotal(listCall.result.total)\n }\n\n if (credentialsCall.ok && credentialsCall.result?.credentials) {\n setCredentials(credentialsCall.result.credentials)\n setSettingsError(null)\n } else {\n setSettingsError(t('webhooks.integrationSetup.settingsLoadError', 'Failed to load webhook integration settings.'))\n }\n } catch {\n if (!mounted) return\n setError(t('webhooks.integrationSetup.loadError', 'Failed to load configured webhooks.'))\n setItems([])\n setTotal(0)\n setSettingsError(t('webhooks.integrationSetup.settingsLoadError', 'Failed to load webhook integration settings.'))\n } finally {\n if (mounted) setIsLoading(false)\n }\n }\n\n void load()\n\n return () => {\n mounted = false\n }\n }, [t])\n\n const isEnabled = typedContext?.state?.isEnabled !== false\n const notifyOnFailedDelivery = credentials.notifyOnFailedDelivery === true\n\n const handleToggleFailedDeliveryNotifications = React.useCallback(async (nextValue: boolean) => {\n const nextCredentials: WebhookIntegrationCredentials = {\n ...credentials,\n notifyOnFailedDelivery: nextValue,\n }\n\n setCredentials(nextCredentials)\n setIsSavingSettings(true)\n setSettingsError(null)\n\n try {\n const call = await apiCall(\n `/api/integrations/${encodeURIComponent(webhookCustomIntegrationId)}/credentials`,\n {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ credentials: nextCredentials }),\n },\n { fallback: null },\n )\n\n if (!call.ok) {\n setCredentials(credentials)\n setSettingsError(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'))\n flash(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'), 'error')\n return\n }\n\n flash(t('webhooks.integrationSetup.settingsSaveSuccess', 'Webhook integration settings saved.'), 'success')\n } catch {\n setCredentials(credentials)\n setSettingsError(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'))\n flash(t('webhooks.integrationSetup.settingsSaveError', 'Failed to save webhook integration settings.'), 'error')\n } finally {\n setIsSavingSettings(false)\n }\n }, [credentials, t])\n\n return (\n <div className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'webhooks.integrationSetup.summary',\n 'Manage Custom Webhooks from the dedicated webhook screen. Turning this integration off blocks outbound deliveries, test sends, retries, and inbound webhook receives.',\n )}\n </p>\n\n <Alert>\n <Webhook className=\"h-4 w-4\" />\n <AlertTitle>\n {isEnabled\n ? t('webhooks.integrationSetup.enabledTitle', 'Delivery processing is enabled')\n : t('webhooks.integrationSetup.disabledTitle', 'Delivery processing is disabled')}\n </AlertTitle>\n <AlertDescription>\n {isEnabled\n ? t('webhooks.integrationSetup.enabledBody', 'Your saved webhooks can send and receive traffic. Use the links below to review endpoints and open the delivery log on each webhook detail page.')\n : t('webhooks.integrationSetup.disabledBody', 'The integration switch is off, so webhook sends, retries, test deliveries, and inbound receives are blocked until you enable it again.')}\n </AlertDescription>\n </Alert>\n\n <div className=\"flex flex-wrap gap-3\">\n <Button asChild>\n <Link href=\"/backend/webhooks\">\n <ExternalLink className=\"mr-2 h-4 w-4\" />\n {t('webhooks.integrationSetup.actions.openList', 'Open webhook list')}\n </Link>\n </Button>\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/webhooks/create\">\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('webhooks.integrationSetup.actions.create', 'Create webhook')}\n </Link>\n </Button>\n </div>\n\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"space-y-1\">\n <h4 className=\"text-sm font-semibold\">\n {t('webhooks.integrationSetup.notificationsTitle', 'Failed delivery notifications')}\n </h4>\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'webhooks.integrationSetup.notificationsBody',\n 'Notify admin users when a webhook delivery finally fails after retries are exhausted.',\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <Badge variant={notifyOnFailedDelivery ? 'default' : 'outline'}>\n {notifyOnFailedDelivery\n ? t('webhooks.integrationSetup.notificationsEnabled', 'Enabled')\n : t('webhooks.integrationSetup.notificationsDisabled', 'Disabled')}\n </Badge>\n <Switch\n checked={notifyOnFailedDelivery}\n disabled={isSavingSettings}\n onCheckedChange={(checked) => { void handleToggleFailedDeliveryNotifications(checked) }}\n />\n </div>\n </div>\n {settingsError ? (\n <div className=\"mt-3 rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-sm text-destructive\">\n {settingsError}\n </div>\n ) : null}\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <h4 className=\"text-sm font-semibold\">\n {t('webhooks.integrationSetup.configuredTitle', 'Configured webhooks')}\n </h4>\n {total > items.length ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('webhooks.integrationSetup.more', 'Showing {shown} of {total}.', {\n shown: String(items.length),\n total: String(total),\n })}\n </span>\n ) : null}\n </div>\n\n {isLoading ? (\n <div className=\"flex items-center gap-2 rounded-md border bg-muted/30 px-3 py-3 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n <span>{t('webhooks.integrationSetup.loading', 'Loading configured webhooks...')}</span>\n </div>\n ) : null}\n\n {!isLoading && error ? (\n <div className=\"rounded-md border border-destructive/30 bg-destructive/5 px-3 py-3 text-sm text-destructive\">\n {error}\n </div>\n ) : null}\n\n {!isLoading && !error && items.length === 0 ? (\n <div className=\"rounded-md border border-dashed px-3 py-4 text-sm text-muted-foreground\">\n {t('webhooks.integrationSetup.empty', 'No webhooks have been configured yet. Create one to start sending or receiving events.')}\n </div>\n ) : null}\n\n {!isLoading && !error && items.length > 0 ? (\n <div className=\"space-y-2\">\n {items.map((item) => (\n <div\n key={item.id}\n className=\"flex flex-col gap-3 rounded-lg border bg-muted/30 px-3 py-3 lg:flex-row lg:items-center lg:justify-between\"\n >\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-foreground\">{item.name}</span>\n <Badge variant={item.isActive ? 'default' : 'outline'}>\n {item.isActive\n ? t('webhooks.list.status.active', 'Active')\n : t('webhooks.list.status.inactive', 'Inactive')}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {t('webhooks.integrationSetup.eventCount', '{count} event patterns', {\n count: String(item.subscribedEvents.length),\n })}\n </span>\n </div>\n <code className=\"block truncate text-xs text-muted-foreground\">{item.url}</code>\n </div>\n\n <Button asChild variant=\"ghost\" size=\"sm\" className=\"w-fit\">\n <Link href={`/backend/webhooks/${encodeURIComponent(item.id)}`}>\n <PencilLine className=\"mr-2 h-4 w-4\" />\n {t('webhooks.integrationSetup.actions.edit', 'Edit webhook')}\n </Link>\n </Button>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/webhooks",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2874.77704bccbd",
|
|
4
4
|
"description": "Webhooks module for Open Mercato — Standard Webhooks compliant outbound/inbound delivery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -69,18 +69,18 @@
|
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@open-mercato/core": "0.5.1-develop.
|
|
73
|
-
"@open-mercato/queue": "0.5.1-develop.
|
|
74
|
-
"@open-mercato/ui": "0.5.1-develop.
|
|
72
|
+
"@open-mercato/core": "0.5.1-develop.2874.77704bccbd",
|
|
73
|
+
"@open-mercato/queue": "0.5.1-develop.2874.77704bccbd",
|
|
74
|
+
"@open-mercato/ui": "0.5.1-develop.2874.77704bccbd"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"@mikro-orm/postgresql": "^7.0.10",
|
|
78
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
78
|
+
"@open-mercato/shared": "0.5.1-develop.2874.77704bccbd",
|
|
79
79
|
"react": "^19.0.0",
|
|
80
80
|
"react-dom": "^19.0.0"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
83
|
+
"@open-mercato/shared": "0.5.1-develop.2874.77704bccbd",
|
|
84
84
|
"@types/jest": "^30.0.0",
|
|
85
85
|
"esbuild": "^0.28.0",
|
|
86
86
|
"glob": "^13.0.6",
|
|
@@ -508,8 +508,8 @@ export default function WebhookDetailPage() {
|
|
|
508
508
|
statusBadge={
|
|
509
509
|
<Badge
|
|
510
510
|
className={webhook.isActive
|
|
511
|
-
? 'border-transparent bg-
|
|
512
|
-
: 'border-transparent bg-
|
|
511
|
+
? 'border-transparent bg-status-success-bg text-status-success-text'
|
|
512
|
+
: 'border-transparent bg-status-neutral-bg text-status-neutral-text'}
|
|
513
513
|
>
|
|
514
514
|
{webhook.isActive ? t('webhooks.list.status.active') : t('webhooks.list.status.inactive')}
|
|
515
515
|
</Badge>
|
|
@@ -589,7 +589,7 @@ export default function WebhookDetailPage() {
|
|
|
589
589
|
</div>
|
|
590
590
|
<div className="col-span-2">
|
|
591
591
|
<span className="text-muted-foreground">{t('webhooks.form.customHeaders')}:</span>
|
|
592
|
-
<pre className="mt-2 rounded border bg-muted/
|
|
592
|
+
<pre className="mt-2 rounded border bg-muted/50 p-3 text-xs">
|
|
593
593
|
{webhook.customHeaders ? JSON.stringify(webhook.customHeaders, null, 2) : '—'}
|
|
594
594
|
</pre>
|
|
595
595
|
</div>
|
|
@@ -603,7 +603,7 @@ export default function WebhookDetailPage() {
|
|
|
603
603
|
<div>{t('webhooks.deliveries.columns.status')}: {testDelivery.status}</div>
|
|
604
604
|
<div>{t('webhooks.deliveries.columns.responseStatus')}: {testDelivery.responseStatus ?? '—'}</div>
|
|
605
605
|
<div>{t('webhooks.deliveries.columns.duration')}: {testDelivery.durationMs != null ? `${testDelivery.durationMs}ms` : '—'}</div>
|
|
606
|
-
<pre className="overflow-auto rounded border bg-muted/
|
|
606
|
+
<pre className="overflow-auto rounded border bg-muted/50 p-3 text-xs">
|
|
607
607
|
{JSON.stringify(testDelivery.payload, null, 2)}
|
|
608
608
|
</pre>
|
|
609
609
|
</div>
|
|
@@ -677,19 +677,19 @@ export default function WebhookDetailPage() {
|
|
|
677
677
|
<div>{t('webhooks.deliveries.columns.duration')}: {selectedDelivery.durationMs != null ? `${selectedDelivery.durationMs}ms` : '—'}</div>
|
|
678
678
|
<div>
|
|
679
679
|
<div className="mb-2 font-medium">{t('webhooks.deliveries.requestBody')}</div>
|
|
680
|
-
<pre className="overflow-auto rounded border bg-muted/
|
|
680
|
+
<pre className="overflow-auto rounded border bg-muted/50 p-3 text-xs">
|
|
681
681
|
{JSON.stringify(selectedDelivery.payload, null, 2)}
|
|
682
682
|
</pre>
|
|
683
683
|
</div>
|
|
684
684
|
<div>
|
|
685
685
|
<div className="mb-2 font-medium">{t('webhooks.deliveries.responseBody')}</div>
|
|
686
|
-
<pre className="overflow-auto rounded border bg-muted/
|
|
686
|
+
<pre className="overflow-auto rounded border bg-muted/50 p-3 text-xs">
|
|
687
687
|
{selectedDelivery.responseBody ?? '—'}
|
|
688
688
|
</pre>
|
|
689
689
|
</div>
|
|
690
690
|
<div>
|
|
691
691
|
<div className="mb-2 font-medium">{t('webhooks.deliveries.responseHeaders')}</div>
|
|
692
|
-
<pre className="overflow-auto rounded border bg-muted/
|
|
692
|
+
<pre className="overflow-auto rounded border bg-muted/50 p-3 text-xs">
|
|
693
693
|
{selectedDelivery.responseHeaders ? JSON.stringify(selectedDelivery.responseHeaders, null, 2) : '—'}
|
|
694
694
|
</pre>
|
|
695
695
|
</div>
|
|
@@ -190,7 +190,7 @@ export default function WebhooksListPage() {
|
|
|
190
190
|
accessorKey: 'isActive',
|
|
191
191
|
header: t('webhooks.list.columns.status'),
|
|
192
192
|
cell: ({ row }) => (
|
|
193
|
-
<span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.original.isActive ? 'bg-
|
|
193
|
+
<span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.original.isActive ? 'bg-status-success-bg text-status-success-text' : 'bg-status-neutral-bg text-status-neutral-text'}`}>
|
|
194
194
|
{row.original.isActive ? t('webhooks.list.status.active') : t('webhooks.list.status.inactive')}
|
|
195
195
|
</span>
|
|
196
196
|
),
|
|
@@ -289,7 +289,7 @@ export default function IntegrationDeliveriesWidget(_props: InjectionWidgetCompo
|
|
|
289
289
|
className="p-4"
|
|
290
290
|
/>
|
|
291
291
|
|
|
292
|
-
<div className="rounded-lg border bg-muted/
|
|
292
|
+
<div className="rounded-lg border bg-muted/30 p-4">
|
|
293
293
|
<div className="mb-2 text-sm font-medium">{t('webhooks.deliveries.responseBody')}</div>
|
|
294
294
|
<pre className="overflow-auto whitespace-pre-wrap break-words text-xs">
|
|
295
295
|
{selectedDelivery.responseBody ?? '—'}
|
|
@@ -187,7 +187,7 @@ export default function IntegrationSetupWidget({ context }: InjectionWidgetCompo
|
|
|
187
187
|
</Button>
|
|
188
188
|
</div>
|
|
189
189
|
|
|
190
|
-
<div className="rounded-lg border bg-muted/
|
|
190
|
+
<div className="rounded-lg border bg-muted/30 p-4">
|
|
191
191
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
|
192
192
|
<div className="space-y-1">
|
|
193
193
|
<h4 className="text-sm font-semibold">
|
|
@@ -259,7 +259,7 @@ export default function IntegrationSetupWidget({ context }: InjectionWidgetCompo
|
|
|
259
259
|
{items.map((item) => (
|
|
260
260
|
<div
|
|
261
261
|
key={item.id}
|
|
262
|
-
className="flex flex-col gap-3 rounded-lg border bg-muted/
|
|
262
|
+
className="flex flex-col gap-3 rounded-lg border bg-muted/30 px-3 py-3 lg:flex-row lg:items-center lg:justify-between"
|
|
263
263
|
>
|
|
264
264
|
<div className="min-w-0 space-y-1">
|
|
265
265
|
<div className="flex flex-wrap items-center gap-2">
|