@open-mercato/webhooks 0.6.5-develop.4782.1.29bd722d3d → 0.6.5-develop.4790.1.bffb4fd44b

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.
@@ -15,6 +15,7 @@ import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/u
15
15
  import { useT } from "@open-mercato/shared/lib/i18n/context";
16
16
  import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
17
17
  import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
18
+ import { ListEmptyState } from "@open-mercato/ui/backend/filters/ListEmptyState";
18
19
  import { useWebhookFeatureAccess } from "./useWebhookFeatureAccess.js";
19
20
  function WebhooksListPage() {
20
21
  const [rows, setRows] = React.useState([]);
@@ -245,6 +246,14 @@ function WebhooksListPage() {
245
246
  }
246
247
  return /* @__PURE__ */ jsx(RowActions, { items });
247
248
  },
249
+ emptyState: /* @__PURE__ */ jsx(
250
+ ListEmptyState,
251
+ {
252
+ entityName: t("webhooks.list.title"),
253
+ createHref: access.canManage ? "/backend/webhooks/create" : void 0,
254
+ createLabel: access.canManage ? t("webhooks.nav.create") : void 0
255
+ }
256
+ ),
248
257
  pagination: { page, pageSize: 20, total, totalPages, onPageChange: setPage },
249
258
  isLoading
250
259
  }
@@ -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 { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\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', headers: buildOptimisticLockHeader(row.updatedAt) },\n { fallback: null },\n )\n if (!call.ok) {\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return\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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",
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 { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\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 { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\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', headers: buildOptimisticLockHeader(row.updatedAt) },\n { fallback: null },\n )\n if (!call.ok) {\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return\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 emptyState={(\n <ListEmptyState\n entityName={t('webhooks.list.title')}\n createHref={access.canManage ? '/backend/webhooks/create' : undefined}\n createLabel={access.canManage ? t('webhooks.nav.create') : undefined}\n />\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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/webhooks",
3
- "version": "0.6.5-develop.4782.1.29bd722d3d",
3
+ "version": "0.6.5-develop.4790.1.bffb4fd44b",
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,19 +69,19 @@
69
69
  }
70
70
  },
71
71
  "dependencies": {
72
- "@open-mercato/core": "0.6.5-develop.4782.1.29bd722d3d",
73
- "@open-mercato/queue": "0.6.5-develop.4782.1.29bd722d3d",
74
- "@open-mercato/ui": "0.6.5-develop.4782.1.29bd722d3d",
72
+ "@open-mercato/core": "0.6.5-develop.4790.1.bffb4fd44b",
73
+ "@open-mercato/queue": "0.6.5-develop.4790.1.bffb4fd44b",
74
+ "@open-mercato/ui": "0.6.5-develop.4790.1.bffb4fd44b",
75
75
  "svix": "^1.95.1"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "@mikro-orm/postgresql": "^7.0.14",
79
- "@open-mercato/shared": "0.6.5-develop.4782.1.29bd722d3d",
79
+ "@open-mercato/shared": "0.6.5-develop.4790.1.bffb4fd44b",
80
80
  "react": "^19.0.0",
81
81
  "react-dom": "^19.0.0"
82
82
  },
83
83
  "devDependencies": {
84
- "@open-mercato/shared": "0.6.5-develop.4782.1.29bd722d3d",
84
+ "@open-mercato/shared": "0.6.5-develop.4790.1.bffb4fd44b",
85
85
  "@types/jest": "^30.0.0",
86
86
  "@types/react": "^19.2.16",
87
87
  "@types/react-dom": "^19.2.3",
@@ -16,6 +16,7 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
16
16
  import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
17
17
  import type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'
18
18
  import { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'
19
+ import { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'
19
20
  import { useWebhookFeatureAccess } from './useWebhookFeatureAccess'
20
21
 
21
22
  type Row = {
@@ -279,6 +280,13 @@ export default function WebhooksListPage() {
279
280
 
280
281
  return <RowActions items={items} />
281
282
  }}
283
+ emptyState={(
284
+ <ListEmptyState
285
+ entityName={t('webhooks.list.title')}
286
+ createHref={access.canManage ? '/backend/webhooks/create' : undefined}
287
+ createLabel={access.canManage ? t('webhooks.nav.create') : undefined}
288
+ />
289
+ )}
282
290
  pagination={{ page, pageSize: 20, total, totalPages, onPageChange: setPage }}
283
291
  isLoading={isLoading}
284
292
  />