@burdenoff/microfe-devportal 2026.623.5 → 2026.623.7
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/devportal/DevportalRoutes.js +123 -108
- package/dist/devportal/DevportalRoutes.js.map +1 -1
- package/dist/devportal/components/SectionNav.js +71 -5
- package/dist/devportal/components/SectionNav.js.map +1 -0
- package/dist/devportal/components/index.js +1 -1
- package/dist/devportal/hooks/useGraphQL.js +1 -1
- package/dist/devportal/pages/AdminReviewPage.js +39 -39
- package/dist/devportal/pages/AnalyticsDashboardPage.js +54 -54
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/ApiKeysPage.js +53 -53
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +9 -9
- package/dist/devportal/pages/ApplicationDetailPage.js +462 -462
- package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +120 -120
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationsPage.js +73 -73
- package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +20 -20
- package/dist/devportal/pages/CreateApplicationPage.js +32 -32
- package/dist/devportal/pages/CreateOAuthClientPage.js +18 -18
- package/dist/devportal/pages/CreateOrganizationPage.js +12 -12
- package/dist/devportal/pages/CreateWebhookPage.js +23 -23
- package/dist/devportal/pages/DashboardPage.js +23 -23
- package/dist/devportal/pages/DelegationsPage.js +22 -22
- package/dist/devportal/pages/EditApplicationPage.js +283 -283
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +9 -9
- package/dist/devportal/pages/OAuthClientDetailPage.js +15 -15
- package/dist/devportal/pages/OAuthClientsPage.js +14 -14
- package/dist/devportal/pages/OrganizationDetailPage.js +84 -84
- package/dist/devportal/pages/OrganizationMembersPage.js +260 -260
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +16 -16
- package/dist/devportal/pages/PublishPage.js +16 -16
- package/dist/devportal/pages/PublisherProfilePage.js +18 -18
- package/dist/devportal/pages/RevenueDashboardPage.js +29 -29
- package/dist/devportal/pages/SettingsPage.js +17 -17
- package/dist/devportal/pages/SetupPage.js +99 -99
- package/dist/devportal/pages/SetupPage.js.map +1 -1
- package/dist/devportal/pages/WebhookDetailPage.js +143 -143
- package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +133 -133
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,237 +1,237 @@
|
|
|
1
1
|
import { useDevportal as e } from "../providers/DevportalProvider.js";
|
|
2
2
|
import { EmptyState as t } from "../components/EmptyState.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { DEVPORTAL_PERMISSIONS as
|
|
13
|
-
import { useDevportalPermission as
|
|
3
|
+
import { useDeleteWebhookMutation as n, useGetApplicationQuery as r, useGetWebhookDetailQuery as i, useTestWebhookMutation as a, useUpdateWebhookMutation as o } from "../../generated/global-operations.js";
|
|
4
|
+
import { getErrorMessage as ee } from "../hooks/useGraphQL.js";
|
|
5
|
+
import { PageLayout as s, PageSection as c } from "../components/PageLayout.js";
|
|
6
|
+
import { StatCard as l, StatCardGrid as u } from "../components/StatCard.js";
|
|
7
|
+
import { StatusBadge as d } from "../components/StatusBadge.js";
|
|
8
|
+
import { nativeImpact as f, nativeNotify as p } from "../../utils/nativeBridge.js";
|
|
9
|
+
import { SecretDisplay as m } from "../components/SecretDisplay.js";
|
|
10
|
+
import { DataTable as h, DetailList as g } from "../components/DataTable.js";
|
|
11
|
+
import { Alert as _, ConfirmDialog as v } from "../components/ConfirmDialog.js";
|
|
12
|
+
import { DEVPORTAL_PERMISSIONS as y } from "../constants/permissions.js";
|
|
13
|
+
import { useDevportalPermission as b } from "../hooks/usePermission.js";
|
|
14
14
|
import "../hooks/index.js";
|
|
15
|
-
import
|
|
16
|
-
import { useEffect as
|
|
17
|
-
import { useI18n as
|
|
18
|
-
import { AlertCircle as
|
|
19
|
-
import { useParams as
|
|
20
|
-
import { jsx as
|
|
15
|
+
import x from "../../node_modules/.bun/date-fns@3.6.0/node_modules/date-fns/format.js";
|
|
16
|
+
import { useEffect as S, useMemo as C, useState as w } from "react";
|
|
17
|
+
import { useI18n as te } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
18
|
+
import { AlertCircle as ne, CheckCircle as T, Clock as re, ExternalLink as ie, Loader2 as ae, Pause as oe, Play as se, Send as ce, Trash2 as le, Webhook as ue, XCircle as E } from "lucide-react";
|
|
19
|
+
import { useParams as D } from "react-router-dom";
|
|
20
|
+
import { jsx as O, jsxs as k } from "react/jsx-runtime";
|
|
21
21
|
//#region src/devportal/pages/WebhookDetailPage.tsx
|
|
22
|
-
var
|
|
23
|
-
let { appId:
|
|
24
|
-
let n =
|
|
22
|
+
var A = (e) => e ? x(new Date(e), "MMM d, yyyy HH:mm:ss") : "Never", j = () => {
|
|
23
|
+
let { appId: j, webhookId: M } = D(), { navigate: N, basePath: P } = e(), { t: F } = te(), I = (e, t) => {
|
|
24
|
+
let n = F(e);
|
|
25
25
|
return n === e ? t : n;
|
|
26
|
-
}, { allowed:
|
|
27
|
-
variables: { id:
|
|
28
|
-
skip: !
|
|
26
|
+
}, { allowed: L } = b(y.WEBHOOK_UPDATE), { allowed: R } = b(y.WEBHOOK_DELETE), [z, B] = w(!1), [V, H] = w(!1), [U, W] = w(null), [de, G] = w(!1), { data: K } = r({
|
|
27
|
+
variables: { id: j ?? "" },
|
|
28
|
+
skip: !j,
|
|
29
29
|
fetchPolicy: "cache-first"
|
|
30
30
|
});
|
|
31
|
-
|
|
32
|
-
let e =
|
|
33
|
-
if (!
|
|
31
|
+
S(() => {
|
|
32
|
+
let e = K?.application?.name;
|
|
33
|
+
if (!j || !e) return;
|
|
34
34
|
let t = window.__breadcrumbRegistry;
|
|
35
|
-
return t?.register(
|
|
36
|
-
}, [
|
|
37
|
-
let { data:
|
|
35
|
+
return t?.register(j, e), () => t?.unregister(j);
|
|
36
|
+
}, [j, K?.application?.name]);
|
|
37
|
+
let { data: q, loading: fe, error: J, refetch: Y } = i({
|
|
38
38
|
variables: {
|
|
39
|
-
id:
|
|
39
|
+
id: M || "",
|
|
40
40
|
limit: 20,
|
|
41
41
|
offset: 0
|
|
42
42
|
},
|
|
43
|
-
skip: !
|
|
43
|
+
skip: !M,
|
|
44
44
|
fetchPolicy: "cache-and-network"
|
|
45
|
-
}), [
|
|
46
|
-
|
|
45
|
+
}), [pe, { loading: me }] = o(), [he, { loading: ge }] = n(), [X, { loading: _e }] = a(), Z = q?.webhook;
|
|
46
|
+
S(() => {
|
|
47
47
|
let e = Z?.name;
|
|
48
|
-
if (!
|
|
48
|
+
if (!M || !e) return;
|
|
49
49
|
let t = window.__breadcrumbRegistry;
|
|
50
|
-
return t?.register(
|
|
51
|
-
}, [
|
|
52
|
-
let Q =
|
|
50
|
+
return t?.register(M, e), () => t?.unregister(M);
|
|
51
|
+
}, [M, Z?.name]);
|
|
52
|
+
let Q = q?.webhookDeliveries?.edges?.map((e) => e.node) ?? [], $ = j || Z?.applicationId, ve = C(() => {
|
|
53
53
|
if (!Z) return 0;
|
|
54
54
|
let e = (Z.successCount ?? 0) + (Z.failureCount ?? 0);
|
|
55
55
|
return e === 0 ? 100 : Math.round((Z.successCount ?? 0) / e * 100);
|
|
56
56
|
}, [Z]), ye = (e) => {
|
|
57
|
-
|
|
57
|
+
N?.(`${P}${e}`);
|
|
58
58
|
}, be = async () => {
|
|
59
|
-
Z && (await
|
|
59
|
+
Z && (await pe({ variables: {
|
|
60
60
|
id: Z.id,
|
|
61
61
|
input: { isActive: !Z.isActive }
|
|
62
|
-
} }), await
|
|
62
|
+
} }), await Y());
|
|
63
63
|
}, xe = async () => {
|
|
64
64
|
if (Z) {
|
|
65
|
-
|
|
65
|
+
f("medium");
|
|
66
66
|
try {
|
|
67
|
-
await
|
|
67
|
+
await he({ variables: { id: Z.id } }), p("success"), ye(`/apps/${Z.applicationId}/webhooks`);
|
|
68
68
|
} catch {
|
|
69
|
-
|
|
69
|
+
p("error");
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}, Se = async () => {
|
|
73
73
|
if (!Z) return;
|
|
74
|
-
let e = (await
|
|
74
|
+
let e = (await X({ variables: {
|
|
75
75
|
id: Z.id,
|
|
76
76
|
eventType: Z.events[0] || "application.updated"
|
|
77
77
|
} })).data?.testWebhook;
|
|
78
78
|
if (!e) {
|
|
79
|
-
|
|
79
|
+
G(!1), W("Test request did not return a response.");
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
G(e.success), W(e.success ? `Test delivery succeeded with HTTP ${e.statusCode ?? 200}.` : e.error || "Webhook test failed."), await Y();
|
|
83
83
|
};
|
|
84
|
-
return
|
|
85
|
-
title:
|
|
86
|
-
description:
|
|
84
|
+
return fe && !Z ? /* @__PURE__ */ O(s, {
|
|
85
|
+
title: I("devportal.webhook", "Webhook"),
|
|
86
|
+
description: I("devportal.loadingWebhookDetails", "Loading webhook details"),
|
|
87
87
|
backLink: $ ? `/apps/${$}/webhooks` : "/webhooks",
|
|
88
|
-
backLabel:
|
|
89
|
-
children: /* @__PURE__ */
|
|
88
|
+
backLabel: I("devportal.backToWebhooks", "Back to Webhooks"),
|
|
89
|
+
children: /* @__PURE__ */ O("div", {
|
|
90
90
|
className: "flex items-center justify-center py-16 text-muted-foreground",
|
|
91
|
-
children: /* @__PURE__ */
|
|
91
|
+
children: /* @__PURE__ */ O(ae, { className: "h-8 w-8 animate-spin" })
|
|
92
92
|
})
|
|
93
|
-
}) :
|
|
94
|
-
title:
|
|
95
|
-
description:
|
|
93
|
+
}) : J || !Z ? /* @__PURE__ */ O(s, {
|
|
94
|
+
title: I("devportal.webhook", "Webhook"),
|
|
95
|
+
description: I("devportal.webhookDetails", "Webhook details"),
|
|
96
96
|
backLink: $ ? `/apps/${$}/webhooks` : "/webhooks",
|
|
97
|
-
backLabel:
|
|
98
|
-
children: /* @__PURE__ */
|
|
99
|
-
icon: /* @__PURE__ */
|
|
97
|
+
backLabel: I("devportal.backToWebhooks", "Back to Webhooks"),
|
|
98
|
+
children: /* @__PURE__ */ O(t, {
|
|
99
|
+
icon: /* @__PURE__ */ O(ne, {
|
|
100
100
|
size: 32,
|
|
101
101
|
className: "text-status-error-text"
|
|
102
102
|
}),
|
|
103
|
-
title:
|
|
104
|
-
description:
|
|
103
|
+
title: I("devportal.unableToLoadWebhook", "Unable to load webhook"),
|
|
104
|
+
description: J ? ee(J) : I("devportal.webhookNotFound", "Webhook not found")
|
|
105
105
|
})
|
|
106
|
-
}) : /* @__PURE__ */
|
|
106
|
+
}) : /* @__PURE__ */ k(s, {
|
|
107
107
|
title: Z.name,
|
|
108
108
|
description: Z.description || "Webhook configuration and delivery history",
|
|
109
109
|
backLink: `/apps/${$}/webhooks`,
|
|
110
|
-
backLabel:
|
|
111
|
-
actions: /* @__PURE__ */
|
|
110
|
+
backLabel: I("devportal.backToWebhooks", "Back to Webhooks"),
|
|
111
|
+
actions: /* @__PURE__ */ k("div", {
|
|
112
112
|
className: "flex flex-wrap gap-2",
|
|
113
113
|
children: [
|
|
114
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ k("button", {
|
|
115
115
|
type: "button",
|
|
116
116
|
onClick: () => {
|
|
117
|
-
|
|
117
|
+
W(null), H(!0);
|
|
118
118
|
},
|
|
119
119
|
className: "inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent",
|
|
120
|
-
children: [/* @__PURE__ */
|
|
120
|
+
children: [/* @__PURE__ */ O(ce, { size: 16 }), I("devportal.test", "Test")]
|
|
121
121
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ k("button", {
|
|
123
123
|
type: "button",
|
|
124
|
-
disabled:
|
|
125
|
-
"aria-disabled": !
|
|
124
|
+
disabled: me || !L,
|
|
125
|
+
"aria-disabled": !L,
|
|
126
126
|
onClick: () => void be(),
|
|
127
127
|
className: "inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50",
|
|
128
|
-
children: [Z.isActive ? /* @__PURE__ */
|
|
128
|
+
children: [Z.isActive ? /* @__PURE__ */ O(oe, { size: 16 }) : /* @__PURE__ */ O(se, { size: 16 }), Z.isActive ? I("devportal.pauseWebhook", "Pause") : I("devportal.resumeWebhook", "Resume")]
|
|
129
129
|
}),
|
|
130
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ k("button", {
|
|
131
131
|
type: "button",
|
|
132
|
-
onClick: () =>
|
|
133
|
-
disabled: !
|
|
134
|
-
"aria-disabled": !
|
|
132
|
+
onClick: () => B(!0),
|
|
133
|
+
disabled: !R,
|
|
134
|
+
"aria-disabled": !R,
|
|
135
135
|
className: "inline-flex items-center gap-2 rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:opacity-50",
|
|
136
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ O(le, { size: 16 }), I("devportal.deleteWebhook", "Delete")]
|
|
137
137
|
})
|
|
138
138
|
]
|
|
139
139
|
}),
|
|
140
140
|
children: [
|
|
141
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ k(u, {
|
|
142
142
|
columns: 4,
|
|
143
143
|
children: [
|
|
144
|
-
/* @__PURE__ */
|
|
145
|
-
title:
|
|
144
|
+
/* @__PURE__ */ O(l, {
|
|
145
|
+
title: I("devportal.successRate", "Success Rate"),
|
|
146
146
|
value: `${ve}%`,
|
|
147
|
-
icon: /* @__PURE__ */
|
|
147
|
+
icon: /* @__PURE__ */ O(T, { size: 20 })
|
|
148
148
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
150
|
-
title:
|
|
149
|
+
/* @__PURE__ */ O(l, {
|
|
150
|
+
title: I("devportal.successfulDeliveries", "Successful Deliveries"),
|
|
151
151
|
value: (Z.successCount ?? 0).toLocaleString(),
|
|
152
|
-
icon: /* @__PURE__ */
|
|
152
|
+
icon: /* @__PURE__ */ O(T, { size: 20 })
|
|
153
153
|
}),
|
|
154
|
-
/* @__PURE__ */
|
|
155
|
-
title:
|
|
154
|
+
/* @__PURE__ */ O(l, {
|
|
155
|
+
title: I("devportal.failedDeliveries", "Failed Deliveries"),
|
|
156
156
|
value: (Z.failureCount ?? 0).toLocaleString(),
|
|
157
|
-
icon: /* @__PURE__ */
|
|
157
|
+
icon: /* @__PURE__ */ O(E, { size: 20 })
|
|
158
158
|
}),
|
|
159
|
-
/* @__PURE__ */
|
|
160
|
-
title:
|
|
161
|
-
value: Z.lastTriggeredAt ?
|
|
162
|
-
icon: /* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ O(l, {
|
|
160
|
+
title: I("devportal.lastTriggered", "Last Triggered"),
|
|
161
|
+
value: Z.lastTriggeredAt ? x(new Date(Z.lastTriggeredAt), "MMM d, HH:mm") : I("devportal.never", "Never"),
|
|
162
|
+
icon: /* @__PURE__ */ O(re, { size: 20 })
|
|
163
163
|
})
|
|
164
164
|
]
|
|
165
165
|
}),
|
|
166
|
-
/* @__PURE__ */
|
|
167
|
-
title:
|
|
168
|
-
children: /* @__PURE__ */
|
|
166
|
+
/* @__PURE__ */ O(c, {
|
|
167
|
+
title: I("devportal.configuration", "Configuration"),
|
|
168
|
+
children: /* @__PURE__ */ O(g, { items: [
|
|
169
169
|
{
|
|
170
|
-
label:
|
|
171
|
-
value: /* @__PURE__ */
|
|
170
|
+
label: I("devportal.status", "Status"),
|
|
171
|
+
value: /* @__PURE__ */ O(d, {
|
|
172
172
|
status: Z.status,
|
|
173
173
|
type: "webhook"
|
|
174
174
|
})
|
|
175
175
|
},
|
|
176
176
|
{
|
|
177
|
-
label:
|
|
178
|
-
value: /* @__PURE__ */
|
|
177
|
+
label: I("devportal.endpointUrl", "Endpoint URL"),
|
|
178
|
+
value: /* @__PURE__ */ k("span", {
|
|
179
179
|
className: "flex flex-wrap items-center gap-2 font-mono text-sm",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
180
|
+
children: [/* @__PURE__ */ O("span", {
|
|
181
181
|
className: "break-all",
|
|
182
182
|
children: Z.url
|
|
183
|
-
}), /* @__PURE__ */
|
|
183
|
+
}), /* @__PURE__ */ O("a", {
|
|
184
184
|
href: Z.url,
|
|
185
185
|
target: "_blank",
|
|
186
186
|
rel: "noopener noreferrer",
|
|
187
187
|
className: "text-primary",
|
|
188
|
-
children: /* @__PURE__ */
|
|
188
|
+
children: /* @__PURE__ */ O(ie, { size: 14 })
|
|
189
189
|
})]
|
|
190
190
|
})
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
|
-
label:
|
|
194
|
-
value: /* @__PURE__ */
|
|
193
|
+
label: I("devportal.signingSecret", "Signing Secret"),
|
|
194
|
+
value: /* @__PURE__ */ O(m, {
|
|
195
195
|
value: Z.secret || "******",
|
|
196
196
|
label: ""
|
|
197
197
|
})
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
|
-
label:
|
|
201
|
-
value: /* @__PURE__ */
|
|
200
|
+
label: I("devportal.subscribedEvents", "Subscribed Events"),
|
|
201
|
+
value: /* @__PURE__ */ O("div", {
|
|
202
202
|
className: "flex flex-wrap gap-1",
|
|
203
|
-
children: Z.events.map((e) => /* @__PURE__ */
|
|
203
|
+
children: Z.events.map((e) => /* @__PURE__ */ O("code", {
|
|
204
204
|
className: "rounded bg-muted px-1.5 py-0.5 text-xs",
|
|
205
205
|
children: e
|
|
206
206
|
}, e))
|
|
207
207
|
})
|
|
208
208
|
},
|
|
209
209
|
{
|
|
210
|
-
label:
|
|
211
|
-
value: Z.retryEnabled ?
|
|
210
|
+
label: I("devportal.retryPolicy", "Retry Policy"),
|
|
211
|
+
value: Z.retryEnabled ? I("devportal.retryPolicyEnabled", `Up to ${Z.maxRetries ?? 0} retries`) : I("devportal.retriesDisabled", "Retries disabled")
|
|
212
212
|
},
|
|
213
213
|
{
|
|
214
|
-
label:
|
|
215
|
-
value:
|
|
214
|
+
label: I("devportal.created", "Created"),
|
|
215
|
+
value: A(Z.createdAt)
|
|
216
216
|
},
|
|
217
217
|
{
|
|
218
|
-
label:
|
|
219
|
-
value:
|
|
218
|
+
label: I("devportal.updated", "Updated"),
|
|
219
|
+
value: A(Z.updatedAt)
|
|
220
220
|
}
|
|
221
221
|
] })
|
|
222
222
|
}),
|
|
223
|
-
/* @__PURE__ */
|
|
224
|
-
title:
|
|
225
|
-
children: Q.length > 0 ? /* @__PURE__ */
|
|
223
|
+
/* @__PURE__ */ O(c, {
|
|
224
|
+
title: I("devportal.recentDeliveries", "Recent Deliveries"),
|
|
225
|
+
children: Q.length > 0 ? /* @__PURE__ */ O(h, {
|
|
226
226
|
data: Q,
|
|
227
227
|
keyField: "id",
|
|
228
228
|
columns: [
|
|
229
229
|
{
|
|
230
230
|
key: "status",
|
|
231
|
-
header:
|
|
232
|
-
render: (e) => /* @__PURE__ */
|
|
231
|
+
header: I("devportal.status", "Status"),
|
|
232
|
+
render: (e) => /* @__PURE__ */ O("div", {
|
|
233
233
|
className: "flex items-center gap-2",
|
|
234
|
-
children: /* @__PURE__ */
|
|
234
|
+
children: /* @__PURE__ */ O(d, {
|
|
235
235
|
status: e.status,
|
|
236
236
|
type: "delivery"
|
|
237
237
|
})
|
|
@@ -239,63 +239,63 @@ var j = (e) => e ? y(new Date(e), "MMM d, yyyy HH:mm:ss") : "Never", M = () => {
|
|
|
239
239
|
},
|
|
240
240
|
{
|
|
241
241
|
key: "eventType",
|
|
242
|
-
header:
|
|
243
|
-
render: (e) => /* @__PURE__ */
|
|
242
|
+
header: I("devportal.event", "Event"),
|
|
243
|
+
render: (e) => /* @__PURE__ */ O("code", {
|
|
244
244
|
className: "text-xs",
|
|
245
245
|
children: e.eventType
|
|
246
246
|
})
|
|
247
247
|
},
|
|
248
248
|
{
|
|
249
249
|
key: "responseStatus",
|
|
250
|
-
header:
|
|
250
|
+
header: I("devportal.response", "Response"),
|
|
251
251
|
render: (e) => e.responseStatus ?? "-"
|
|
252
252
|
},
|
|
253
253
|
{
|
|
254
254
|
key: "attemptNumber",
|
|
255
|
-
header:
|
|
255
|
+
header: I("devportal.attempts", "Attempts"),
|
|
256
256
|
render: (e) => e.attemptNumber
|
|
257
257
|
},
|
|
258
258
|
{
|
|
259
259
|
key: "createdAt",
|
|
260
|
-
header:
|
|
261
|
-
render: (e) =>
|
|
260
|
+
header: I("devportal.created", "Created"),
|
|
261
|
+
render: (e) => A(e.createdAt)
|
|
262
262
|
}
|
|
263
263
|
]
|
|
264
|
-
}) : /* @__PURE__ */
|
|
265
|
-
icon: /* @__PURE__ */
|
|
266
|
-
title:
|
|
267
|
-
description:
|
|
264
|
+
}) : /* @__PURE__ */ O(t, {
|
|
265
|
+
icon: /* @__PURE__ */ O(ue, { size: 24 }),
|
|
266
|
+
title: I("devportal.noDeliveriesYet", "No deliveries yet"),
|
|
267
|
+
description: I("devportal.noDeliveriesYetDescription", "Deliveries will appear here after the first matching event is sent to this endpoint.")
|
|
268
268
|
})
|
|
269
269
|
}),
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
-
open:
|
|
272
|
-
onOpenChange:
|
|
270
|
+
/* @__PURE__ */ O(v, {
|
|
271
|
+
open: z,
|
|
272
|
+
onOpenChange: B,
|
|
273
273
|
onConfirm: () => void xe(),
|
|
274
|
-
loading:
|
|
275
|
-
title:
|
|
276
|
-
description:
|
|
277
|
-
confirmLabel:
|
|
274
|
+
loading: ge,
|
|
275
|
+
title: I("devportal.deleteWebhookTitle", "Delete webhook"),
|
|
276
|
+
description: I("devportal.deleteWebhookDescription", "Deleting this webhook stops all future deliveries for this endpoint."),
|
|
277
|
+
confirmLabel: I("devportal.deleteWebhookConfirm", "Delete webhook"),
|
|
278
278
|
variant: "danger"
|
|
279
279
|
}),
|
|
280
|
-
/* @__PURE__ */
|
|
281
|
-
open:
|
|
280
|
+
/* @__PURE__ */ O(v, {
|
|
281
|
+
open: V,
|
|
282
282
|
onOpenChange: (e) => {
|
|
283
|
-
|
|
283
|
+
H(e), e || W(null);
|
|
284
284
|
},
|
|
285
285
|
onConfirm: () => void Se(),
|
|
286
286
|
loading: _e,
|
|
287
|
-
title:
|
|
288
|
-
description:
|
|
289
|
-
confirmLabel:
|
|
290
|
-
children:
|
|
291
|
-
variant:
|
|
292
|
-
children:
|
|
287
|
+
title: I("devportal.sendTestDelivery", "Send test delivery"),
|
|
288
|
+
description: I("devportal.sendTestDeliveryDescription", "A signed test event will be sent to the configured endpoint through the public gateway."),
|
|
289
|
+
confirmLabel: I("devportal.sendTestEvent", "Send test event"),
|
|
290
|
+
children: U && /* @__PURE__ */ O(_, {
|
|
291
|
+
variant: de ? "success" : "error",
|
|
292
|
+
children: U
|
|
293
293
|
})
|
|
294
294
|
})
|
|
295
295
|
]
|
|
296
296
|
});
|
|
297
297
|
};
|
|
298
298
|
//#endregion
|
|
299
|
-
export {
|
|
299
|
+
export { j as WebhookDetailPage };
|
|
300
300
|
|
|
301
301
|
//# sourceMappingURL=WebhookDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebhookDetailPage.js","names":[],"sources":["../../../src/devportal/pages/WebhookDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n CheckCircle,\n Clock,\n ExternalLink,\n Loader2,\n Pause,\n Play,\n Send,\n Trash2,\n Webhook,\n XCircle,\n AlertCircle,\n} from \"lucide-react\";\nimport { format } from \"date-fns\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { ConfirmDialog, Alert } from \"../components/ConfirmDialog\";\nimport { DataTable, DetailList } from \"../components/DataTable\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { SecretDisplay } from \"../components/SecretDisplay\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\nimport {\n type GetWebhookDetailQuery,\n getErrorMessage,\n useDeleteWebhookMutation,\n useGetApplicationQuery,\n useGetWebhookDetailQuery,\n useTestWebhookMutation,\n useUpdateWebhookMutation,\n} from \"../hooks\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\n\nconst formatTimestamp = (value?: string | null) => {\n if (!value) return \"Never\";\n return format(new Date(value), \"MMM d, yyyy HH:mm:ss\");\n};\n\ntype WebhookDeliveryEntry =\n GetWebhookDetailQuery[\"webhookDeliveries\"][\"edges\"][number][\"node\"];\n\nexport const WebhookDetailPage: FC = () => {\n const { appId, webhookId } = useParams<{\n appId: string;\n webhookId: string;\n }>();\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.WEBHOOK_UPDATE,\n );\n const { allowed: canDelete } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.WEBHOOK_DELETE,\n );\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [showTestDialog, setShowTestDialog] = useState(false);\n const [testMessage, setTestMessage] = useState<string | null>(null);\n const [testSuccess, setTestSuccess] = useState(false);\n\n const { data: appData } = useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-first\",\n });\n\n useEffect(() => {\n const name = appData?.application?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, appData?.application?.name]);\n\n const { data, loading, error, refetch } = useGetWebhookDetailQuery({\n variables: {\n id: webhookId || \"\",\n limit: 20,\n offset: 0,\n },\n skip: !webhookId,\n fetchPolicy: \"cache-and-network\",\n });\n const [updateWebhook, { loading: updateLoading }] =\n useUpdateWebhookMutation();\n const [deleteWebhook, { loading: deleteLoading }] =\n useDeleteWebhookMutation();\n const [testWebhook, { loading: testLoading }] = useTestWebhookMutation();\n\n const webhook = data?.webhook;\n\n useEffect(() => {\n const name = webhook?.name;\n if (!webhookId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(webhookId, name);\n return () => reg?.unregister(webhookId);\n }, [webhookId, webhook?.name]);\n\n const deliveries: WebhookDeliveryEntry[] =\n data?.webhookDeliveries?.edges?.map(\n (edge: GetWebhookDetailQuery[\"webhookDeliveries\"][\"edges\"][number]) =>\n edge.node,\n ) ?? [];\n const backAppId = appId || webhook?.applicationId;\n const successRate = useMemo(() => {\n if (!webhook) return 0;\n const total = (webhook.successCount ?? 0) + (webhook.failureCount ?? 0);\n if (total === 0) return 100;\n return Math.round(((webhook.successCount ?? 0) / total) * 100);\n }, [webhook]);\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleToggleActive = async () => {\n if (!webhook) return;\n\n await updateWebhook({\n variables: {\n id: webhook.id,\n input: {\n isActive: !webhook.isActive,\n },\n },\n });\n\n await refetch();\n };\n\n const handleDelete = async () => {\n if (!webhook) return;\n void nativeImpact(\"medium\");\n\n try {\n await deleteWebhook({\n variables: {\n id: webhook.id,\n },\n });\n void nativeNotify(\"success\");\n handleNavigate(`/apps/${webhook.applicationId}/webhooks`);\n } catch {\n void nativeNotify(\"error\");\n }\n };\n\n const handleTest = async () => {\n if (!webhook) return;\n\n const result = await testWebhook({\n variables: {\n id: webhook.id,\n eventType: webhook.events[0] || \"application.updated\",\n },\n });\n\n const response = result.data?.testWebhook;\n if (!response) {\n setTestSuccess(false);\n setTestMessage(\"Test request did not return a response.\");\n return;\n }\n\n setTestSuccess(response.success);\n setTestMessage(\n response.success\n ? `Test delivery succeeded with HTTP ${response.statusCode ?? 200}.`\n : response.error || \"Webhook test failed.\",\n );\n\n await refetch();\n };\n\n if (loading && !webhook) {\n return (\n <PageLayout\n title={tr(\"devportal.webhook\", \"Webhook\")}\n description={tr(\n \"devportal.loadingWebhookDetails\",\n \"Loading webhook details\",\n )}\n backLink={backAppId ? `/apps/${backAppId}/webhooks` : \"/webhooks\"}\n backLabel={tr(\"devportal.backToWebhooks\", \"Back to Webhooks\")}\n >\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n </PageLayout>\n );\n }\n\n if (error || !webhook) {\n return (\n <PageLayout\n title={tr(\"devportal.webhook\", \"Webhook\")}\n description={tr(\"devportal.webhookDetails\", \"Webhook details\")}\n backLink={backAppId ? `/apps/${backAppId}/webhooks` : \"/webhooks\"}\n backLabel={tr(\"devportal.backToWebhooks\", \"Back to Webhooks\")}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\"devportal.unableToLoadWebhook\", \"Unable to load webhook\")}\n description={\n error\n ? getErrorMessage(error)\n : tr(\"devportal.webhookNotFound\", \"Webhook not found\")\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={webhook.name}\n description={\n webhook.description || \"Webhook configuration and delivery history\"\n }\n backLink={`/apps/${backAppId}/webhooks`}\n backLabel={tr(\"devportal.backToWebhooks\", \"Back to Webhooks\")}\n actions={\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setTestMessage(null);\n setShowTestDialog(true);\n }}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent\"\n >\n <Send size={16} />\n {tr(\"devportal.test\", \"Test\")}\n </button>\n <button\n type=\"button\"\n disabled={updateLoading || !canUpdate}\n aria-disabled={!canUpdate}\n onClick={() => void handleToggleActive()}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {webhook.isActive ? <Pause size={16} /> : <Play size={16} />}\n {webhook.isActive\n ? tr(\"devportal.pauseWebhook\", \"Pause\")\n : tr(\"devportal.resumeWebhook\", \"Resume\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowDeleteDialog(true)}\n disabled={!canDelete}\n aria-disabled={!canDelete}\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n <Trash2 size={16} />\n {tr(\"devportal.deleteWebhook\", \"Delete\")}\n </button>\n </div>\n }\n >\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.successRate\", \"Success Rate\")}\n value={`${successRate}%`}\n icon={<CheckCircle size={20} />}\n />\n <StatCard\n title={tr(\"devportal.successfulDeliveries\", \"Successful Deliveries\")}\n value={(webhook.successCount ?? 0).toLocaleString()}\n icon={<CheckCircle size={20} />}\n />\n <StatCard\n title={tr(\"devportal.failedDeliveries\", \"Failed Deliveries\")}\n value={(webhook.failureCount ?? 0).toLocaleString()}\n icon={<XCircle size={20} />}\n />\n <StatCard\n title={tr(\"devportal.lastTriggered\", \"Last Triggered\")}\n value={\n webhook.lastTriggeredAt\n ? format(new Date(webhook.lastTriggeredAt), \"MMM d, HH:mm\")\n : tr(\"devportal.never\", \"Never\")\n }\n icon={<Clock size={20} />}\n />\n </StatCardGrid>\n\n <PageSection title={tr(\"devportal.configuration\", \"Configuration\")}>\n <DetailList\n items={[\n {\n label: tr(\"devportal.status\", \"Status\"),\n value: <StatusBadge status={webhook.status} type=\"webhook\" />,\n },\n {\n label: tr(\"devportal.endpointUrl\", \"Endpoint URL\"),\n value: (\n <span className=\"flex flex-wrap items-center gap-2 font-mono text-sm\">\n <span className=\"break-all\">{webhook.url}</span>\n <a\n href={webhook.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-primary\"\n >\n <ExternalLink size={14} />\n </a>\n </span>\n ),\n },\n {\n label: tr(\"devportal.signingSecret\", \"Signing Secret\"),\n value: (\n <SecretDisplay value={webhook.secret || \"******\"} label=\"\" />\n ),\n },\n {\n label: tr(\"devportal.subscribedEvents\", \"Subscribed Events\"),\n value: (\n <div className=\"flex flex-wrap gap-1\">\n {webhook.events.map((eventName: string) => (\n <code\n key={eventName}\n className=\"rounded bg-muted px-1.5 py-0.5 text-xs\"\n >\n {eventName}\n </code>\n ))}\n </div>\n ),\n },\n {\n label: tr(\"devportal.retryPolicy\", \"Retry Policy\"),\n value: webhook.retryEnabled\n ? tr(\n \"devportal.retryPolicyEnabled\",\n `Up to ${webhook.maxRetries ?? 0} retries`,\n )\n : tr(\"devportal.retriesDisabled\", \"Retries disabled\"),\n },\n {\n label: tr(\"devportal.created\", \"Created\"),\n value: formatTimestamp(webhook.createdAt),\n },\n {\n label: tr(\"devportal.updated\", \"Updated\"),\n value: formatTimestamp(webhook.updatedAt),\n },\n ]}\n />\n </PageSection>\n\n <PageSection\n title={tr(\"devportal.recentDeliveries\", \"Recent Deliveries\")}\n >\n {deliveries.length > 0 ? (\n <DataTable\n data={deliveries}\n keyField=\"id\"\n columns={[\n {\n key: \"status\",\n header: tr(\"devportal.status\", \"Status\"),\n render: (delivery) => (\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={delivery.status} type=\"delivery\" />\n </div>\n ),\n },\n {\n key: \"eventType\",\n header: tr(\"devportal.event\", \"Event\"),\n render: (delivery) => (\n <code className=\"text-xs\">{delivery.eventType}</code>\n ),\n },\n {\n key: \"responseStatus\",\n header: tr(\"devportal.response\", \"Response\"),\n render: (delivery) => delivery.responseStatus ?? \"-\",\n },\n {\n key: \"attemptNumber\",\n header: tr(\"devportal.attempts\", \"Attempts\"),\n render: (delivery) => delivery.attemptNumber,\n },\n {\n key: \"createdAt\",\n header: tr(\"devportal.created\", \"Created\"),\n render: (delivery) => formatTimestamp(delivery.createdAt),\n },\n ]}\n />\n ) : (\n <EmptyState\n icon={<Webhook size={24} />}\n title={tr(\"devportal.noDeliveriesYet\", \"No deliveries yet\")}\n description={tr(\n \"devportal.noDeliveriesYetDescription\",\n \"Deliveries will appear here after the first matching event is sent to this endpoint.\",\n )}\n />\n )}\n </PageSection>\n\n <ConfirmDialog\n open={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n onConfirm={() => void handleDelete()}\n loading={deleteLoading}\n title={tr(\"devportal.deleteWebhookTitle\", \"Delete webhook\")}\n description={tr(\n \"devportal.deleteWebhookDescription\",\n \"Deleting this webhook stops all future deliveries for this endpoint.\",\n )}\n confirmLabel={tr(\"devportal.deleteWebhookConfirm\", \"Delete webhook\")}\n variant=\"danger\"\n />\n\n <ConfirmDialog\n open={showTestDialog}\n onOpenChange={(open) => {\n setShowTestDialog(open);\n if (!open) {\n setTestMessage(null);\n }\n }}\n onConfirm={() => void handleTest()}\n loading={testLoading}\n title={tr(\"devportal.sendTestDelivery\", \"Send test delivery\")}\n description={tr(\n \"devportal.sendTestDeliveryDescription\",\n \"A signed test event will be sent to the configured endpoint through the public gateway.\",\n )}\n confirmLabel={tr(\"devportal.sendTestEvent\", \"Send test event\")}\n >\n {testMessage && (\n <Alert variant={testSuccess ? \"success\" : \"error\"}>\n {testMessage}\n </Alert>\n )}\n </ConfirmDialog>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WebhookDetailPage.js","names":[],"sources":["../../../src/devportal/pages/WebhookDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n CheckCircle,\n Clock,\n ExternalLink,\n Loader2,\n Pause,\n Play,\n Send,\n Trash2,\n Webhook,\n XCircle,\n AlertCircle,\n} from \"lucide-react\";\nimport { format } from \"date-fns\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { ConfirmDialog, Alert } from \"../components/ConfirmDialog\";\nimport { DataTable, DetailList } from \"../components/DataTable\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { SecretDisplay } from \"../components/SecretDisplay\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\nimport {\n type GetWebhookDetailQuery,\n getErrorMessage,\n useDeleteWebhookMutation,\n useGetApplicationQuery,\n useGetWebhookDetailQuery,\n useTestWebhookMutation,\n useUpdateWebhookMutation,\n} from \"../hooks\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\n\nconst formatTimestamp = (value?: string | null) => {\n if (!value) return \"Never\";\n return format(new Date(value), \"MMM d, yyyy HH:mm:ss\");\n};\n\ntype WebhookDeliveryEntry =\n GetWebhookDetailQuery[\"webhookDeliveries\"][\"edges\"][number][\"node\"];\n\nexport const WebhookDetailPage: FC = () => {\n const { appId, webhookId } = useParams<{\n appId: string;\n webhookId: string;\n }>();\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.WEBHOOK_UPDATE,\n );\n const { allowed: canDelete } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.WEBHOOK_DELETE,\n );\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [showTestDialog, setShowTestDialog] = useState(false);\n const [testMessage, setTestMessage] = useState<string | null>(null);\n const [testSuccess, setTestSuccess] = useState(false);\n\n const { data: appData } = useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-first\",\n });\n\n useEffect(() => {\n const name = appData?.application?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, appData?.application?.name]);\n\n const { data, loading, error, refetch } = useGetWebhookDetailQuery({\n variables: {\n id: webhookId || \"\",\n limit: 20,\n offset: 0,\n },\n skip: !webhookId,\n fetchPolicy: \"cache-and-network\",\n });\n const [updateWebhook, { loading: updateLoading }] =\n useUpdateWebhookMutation();\n const [deleteWebhook, { loading: deleteLoading }] =\n useDeleteWebhookMutation();\n const [testWebhook, { loading: testLoading }] = useTestWebhookMutation();\n\n const webhook = data?.webhook;\n\n useEffect(() => {\n const name = webhook?.name;\n if (!webhookId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(webhookId, name);\n return () => reg?.unregister(webhookId);\n }, [webhookId, webhook?.name]);\n\n const deliveries: WebhookDeliveryEntry[] =\n data?.webhookDeliveries?.edges?.map(\n (edge: GetWebhookDetailQuery[\"webhookDeliveries\"][\"edges\"][number]) =>\n edge.node,\n ) ?? [];\n const backAppId = appId || webhook?.applicationId;\n const successRate = useMemo(() => {\n if (!webhook) return 0;\n const total = (webhook.successCount ?? 0) + (webhook.failureCount ?? 0);\n if (total === 0) return 100;\n return Math.round(((webhook.successCount ?? 0) / total) * 100);\n }, [webhook]);\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleToggleActive = async () => {\n if (!webhook) return;\n\n await updateWebhook({\n variables: {\n id: webhook.id,\n input: {\n isActive: !webhook.isActive,\n },\n },\n });\n\n await refetch();\n };\n\n const handleDelete = async () => {\n if (!webhook) return;\n void nativeImpact(\"medium\");\n\n try {\n await deleteWebhook({\n variables: {\n id: webhook.id,\n },\n });\n void nativeNotify(\"success\");\n handleNavigate(`/apps/${webhook.applicationId}/webhooks`);\n } catch {\n void nativeNotify(\"error\");\n }\n };\n\n const handleTest = async () => {\n if (!webhook) return;\n\n const result = await testWebhook({\n variables: {\n id: webhook.id,\n eventType: webhook.events[0] || \"application.updated\",\n },\n });\n\n const response = result.data?.testWebhook;\n if (!response) {\n setTestSuccess(false);\n setTestMessage(\"Test request did not return a response.\");\n return;\n }\n\n setTestSuccess(response.success);\n setTestMessage(\n response.success\n ? `Test delivery succeeded with HTTP ${response.statusCode ?? 200}.`\n : response.error || \"Webhook test failed.\",\n );\n\n await refetch();\n };\n\n if (loading && !webhook) {\n return (\n <PageLayout\n title={tr(\"devportal.webhook\", \"Webhook\")}\n description={tr(\n \"devportal.loadingWebhookDetails\",\n \"Loading webhook details\",\n )}\n backLink={backAppId ? `/apps/${backAppId}/webhooks` : \"/webhooks\"}\n backLabel={tr(\"devportal.backToWebhooks\", \"Back to Webhooks\")}\n >\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n </PageLayout>\n );\n }\n\n if (error || !webhook) {\n return (\n <PageLayout\n title={tr(\"devportal.webhook\", \"Webhook\")}\n description={tr(\"devportal.webhookDetails\", \"Webhook details\")}\n backLink={backAppId ? `/apps/${backAppId}/webhooks` : \"/webhooks\"}\n backLabel={tr(\"devportal.backToWebhooks\", \"Back to Webhooks\")}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\"devportal.unableToLoadWebhook\", \"Unable to load webhook\")}\n description={\n error\n ? getErrorMessage(error)\n : tr(\"devportal.webhookNotFound\", \"Webhook not found\")\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={webhook.name}\n description={\n webhook.description || \"Webhook configuration and delivery history\"\n }\n backLink={`/apps/${backAppId}/webhooks`}\n backLabel={tr(\"devportal.backToWebhooks\", \"Back to Webhooks\")}\n actions={\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setTestMessage(null);\n setShowTestDialog(true);\n }}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent\"\n >\n <Send size={16} />\n {tr(\"devportal.test\", \"Test\")}\n </button>\n <button\n type=\"button\"\n disabled={updateLoading || !canUpdate}\n aria-disabled={!canUpdate}\n onClick={() => void handleToggleActive()}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {webhook.isActive ? <Pause size={16} /> : <Play size={16} />}\n {webhook.isActive\n ? tr(\"devportal.pauseWebhook\", \"Pause\")\n : tr(\"devportal.resumeWebhook\", \"Resume\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowDeleteDialog(true)}\n disabled={!canDelete}\n aria-disabled={!canDelete}\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n <Trash2 size={16} />\n {tr(\"devportal.deleteWebhook\", \"Delete\")}\n </button>\n </div>\n }\n >\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.successRate\", \"Success Rate\")}\n value={`${successRate}%`}\n icon={<CheckCircle size={20} />}\n />\n <StatCard\n title={tr(\"devportal.successfulDeliveries\", \"Successful Deliveries\")}\n value={(webhook.successCount ?? 0).toLocaleString()}\n icon={<CheckCircle size={20} />}\n />\n <StatCard\n title={tr(\"devportal.failedDeliveries\", \"Failed Deliveries\")}\n value={(webhook.failureCount ?? 0).toLocaleString()}\n icon={<XCircle size={20} />}\n />\n <StatCard\n title={tr(\"devportal.lastTriggered\", \"Last Triggered\")}\n value={\n webhook.lastTriggeredAt\n ? format(new Date(webhook.lastTriggeredAt), \"MMM d, HH:mm\")\n : tr(\"devportal.never\", \"Never\")\n }\n icon={<Clock size={20} />}\n />\n </StatCardGrid>\n\n <PageSection title={tr(\"devportal.configuration\", \"Configuration\")}>\n <DetailList\n items={[\n {\n label: tr(\"devportal.status\", \"Status\"),\n value: <StatusBadge status={webhook.status} type=\"webhook\" />,\n },\n {\n label: tr(\"devportal.endpointUrl\", \"Endpoint URL\"),\n value: (\n <span className=\"flex flex-wrap items-center gap-2 font-mono text-sm\">\n <span className=\"break-all\">{webhook.url}</span>\n <a\n href={webhook.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-primary\"\n >\n <ExternalLink size={14} />\n </a>\n </span>\n ),\n },\n {\n label: tr(\"devportal.signingSecret\", \"Signing Secret\"),\n value: (\n <SecretDisplay value={webhook.secret || \"******\"} label=\"\" />\n ),\n },\n {\n label: tr(\"devportal.subscribedEvents\", \"Subscribed Events\"),\n value: (\n <div className=\"flex flex-wrap gap-1\">\n {webhook.events.map((eventName: string) => (\n <code\n key={eventName}\n className=\"rounded bg-muted px-1.5 py-0.5 text-xs\"\n >\n {eventName}\n </code>\n ))}\n </div>\n ),\n },\n {\n label: tr(\"devportal.retryPolicy\", \"Retry Policy\"),\n value: webhook.retryEnabled\n ? tr(\n \"devportal.retryPolicyEnabled\",\n `Up to ${webhook.maxRetries ?? 0} retries`,\n )\n : tr(\"devportal.retriesDisabled\", \"Retries disabled\"),\n },\n {\n label: tr(\"devportal.created\", \"Created\"),\n value: formatTimestamp(webhook.createdAt),\n },\n {\n label: tr(\"devportal.updated\", \"Updated\"),\n value: formatTimestamp(webhook.updatedAt),\n },\n ]}\n />\n </PageSection>\n\n <PageSection\n title={tr(\"devportal.recentDeliveries\", \"Recent Deliveries\")}\n >\n {deliveries.length > 0 ? (\n <DataTable\n data={deliveries}\n keyField=\"id\"\n columns={[\n {\n key: \"status\",\n header: tr(\"devportal.status\", \"Status\"),\n render: (delivery) => (\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={delivery.status} type=\"delivery\" />\n </div>\n ),\n },\n {\n key: \"eventType\",\n header: tr(\"devportal.event\", \"Event\"),\n render: (delivery) => (\n <code className=\"text-xs\">{delivery.eventType}</code>\n ),\n },\n {\n key: \"responseStatus\",\n header: tr(\"devportal.response\", \"Response\"),\n render: (delivery) => delivery.responseStatus ?? \"-\",\n },\n {\n key: \"attemptNumber\",\n header: tr(\"devportal.attempts\", \"Attempts\"),\n render: (delivery) => delivery.attemptNumber,\n },\n {\n key: \"createdAt\",\n header: tr(\"devportal.created\", \"Created\"),\n render: (delivery) => formatTimestamp(delivery.createdAt),\n },\n ]}\n />\n ) : (\n <EmptyState\n icon={<Webhook size={24} />}\n title={tr(\"devportal.noDeliveriesYet\", \"No deliveries yet\")}\n description={tr(\n \"devportal.noDeliveriesYetDescription\",\n \"Deliveries will appear here after the first matching event is sent to this endpoint.\",\n )}\n />\n )}\n </PageSection>\n\n <ConfirmDialog\n open={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n onConfirm={() => void handleDelete()}\n loading={deleteLoading}\n title={tr(\"devportal.deleteWebhookTitle\", \"Delete webhook\")}\n description={tr(\n \"devportal.deleteWebhookDescription\",\n \"Deleting this webhook stops all future deliveries for this endpoint.\",\n )}\n confirmLabel={tr(\"devportal.deleteWebhookConfirm\", \"Delete webhook\")}\n variant=\"danger\"\n />\n\n <ConfirmDialog\n open={showTestDialog}\n onOpenChange={(open) => {\n setShowTestDialog(open);\n if (!open) {\n setTestMessage(null);\n }\n }}\n onConfirm={() => void handleTest()}\n loading={testLoading}\n title={tr(\"devportal.sendTestDelivery\", \"Send test delivery\")}\n description={tr(\n \"devportal.sendTestDeliveryDescription\",\n \"A signed test event will be sent to the configured endpoint through the public gateway.\",\n )}\n confirmLabel={tr(\"devportal.sendTestEvent\", \"Send test event\")}\n >\n {testMessage && (\n <Alert variant={testSuccess ? \"success\" : \"error\"}>\n {testMessage}\n </Alert>\n )}\n </ConfirmDialog>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|