@burdenoff/microfe-devportal 2026.609.4 → 2026.611.1
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/DevportalRoot.js +6 -1
- package/dist/devportal/DevportalRoot.js.map +1 -1
- package/dist/devportal/DevportalRoutes.js +169 -158
- package/dist/devportal/DevportalRoutes.js.map +1 -1
- package/dist/devportal/hooks/usePackageUpload.js +120 -0
- package/dist/devportal/hooks/usePackageUpload.js.map +1 -0
- package/dist/devportal/pages/AnalyticsDashboardPage.js +73 -62
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +89 -82
- package/dist/devportal/pages/AppLogsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationDetailPage.js +948 -367
- package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +56 -45
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +30 -32
- package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
- package/dist/devportal/pages/CreateApplicationPage.js +8 -3
- package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
- package/dist/devportal/pages/CreateOAuthClientPage.js +4 -4
- package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
- package/dist/devportal/pages/CreateOrganizationPage.js +233 -228
- package/dist/devportal/pages/CreateOrganizationPage.js.map +1 -1
- package/dist/devportal/pages/CreateWebhookPage.js +159 -148
- package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
- package/dist/devportal/pages/DelegationsPage.js +1 -1
- package/dist/devportal/pages/DelegationsPage.js.map +1 -1
- package/dist/devportal/pages/EditApplicationPage.js +25 -17
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +159 -153
- package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientsPage.js +2 -2
- package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.js +158 -153
- package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationMembersPage.js +223 -212
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/PublishPage.js +172 -165
- package/dist/devportal/pages/PublishPage.js.map +1 -1
- package/dist/devportal/pages/ResourcesPage.js.map +1 -1
- package/dist/devportal/pages/RevenueDashboardPage.js +405 -0
- package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -0
- package/dist/devportal/pages/SetupPage.js +186 -181
- package/dist/devportal/pages/SetupPage.js.map +1 -1
- package/dist/devportal/pages/StoreSubmissionPage.js +76 -97
- package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
- package/dist/devportal/pages/WebhookDetailPage.js +172 -154
- package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +218 -200
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/dist/devportal/providers/DevportalProvider.js +16 -13
- package/dist/devportal/providers/DevportalProvider.js.map +1 -1
- package/dist/devportal/types/index.js.map +1 -1
- package/dist/generated/global-operations.js +310 -225
- package/dist/generated/global-operations.js.map +1 -1
- package/package.json +1 -1
- package/dist/devportal/pages/RevenueRedirectPage.js +0 -14
- package/dist/devportal/pages/RevenueRedirectPage.js.map +0 -1
|
@@ -3,224 +3,235 @@ import { useDevportalEventBus as t } from "../events/index.js";
|
|
|
3
3
|
import { PageLayout as n, PageSection as r } from "../components/PageLayout.js";
|
|
4
4
|
import { CheckboxField as i, InputField as a, TextareaField as o } from "../components/FormField.js";
|
|
5
5
|
import { Alert as s } from "../components/ConfirmDialog.js";
|
|
6
|
-
import { useCreateWebhookMutation as c,
|
|
7
|
-
import { PermissionGuard as
|
|
6
|
+
import { useCreateWebhookMutation as c, useGetApplicationQuery as l, useGetApplicationsQuery as u } from "../../generated/global-operations.js";
|
|
7
|
+
import { PermissionGuard as d } from "../components/PermissionGuard.js";
|
|
8
8
|
import "../components/index.js";
|
|
9
|
-
import { DEVPORTAL_PERMISSIONS as
|
|
10
|
-
import { getErrorMessage as
|
|
11
|
-
import { useDevportalPermission as
|
|
9
|
+
import { DEVPORTAL_PERMISSIONS as f } from "../constants/permissions.js";
|
|
10
|
+
import { getErrorMessage as p } from "../hooks/useGraphQL.js";
|
|
11
|
+
import { useDevportalPermission as m } from "../hooks/usePermission.js";
|
|
12
12
|
import "../hooks/index.js";
|
|
13
|
-
import { WEBHOOK_EVENTS as
|
|
14
|
-
import { useTr as
|
|
15
|
-
import { useMemo as
|
|
16
|
-
import { Loader2 as
|
|
17
|
-
import { useParams as
|
|
18
|
-
import { jsx as
|
|
13
|
+
import { WEBHOOK_EVENTS as h } from "../types/index.js";
|
|
14
|
+
import { useTr as g } from "../utils/i18n.js";
|
|
15
|
+
import { useEffect as _, useMemo as v, useState as y } from "react";
|
|
16
|
+
import { Loader2 as b, Webhook as x } from "lucide-react";
|
|
17
|
+
import { useParams as S } from "react-router-dom";
|
|
18
|
+
import { jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
19
19
|
//#region src/devportal/pages/CreateWebhookPage.tsx
|
|
20
|
-
var
|
|
21
|
-
Application:
|
|
22
|
-
Installation:
|
|
23
|
-
User:
|
|
24
|
-
Workspace:
|
|
25
|
-
Project:
|
|
26
|
-
Task:
|
|
27
|
-
Comment:
|
|
28
|
-
File:
|
|
29
|
-
Member:
|
|
30
|
-
},
|
|
31
|
-
let { appId:
|
|
32
|
-
applicationId:
|
|
20
|
+
var T = {
|
|
21
|
+
Application: h.filter((e) => e.startsWith("application.")),
|
|
22
|
+
Installation: h.filter((e) => e.startsWith("installation.")),
|
|
23
|
+
User: h.filter((e) => e.startsWith("user.")),
|
|
24
|
+
Workspace: h.filter((e) => e.startsWith("workspace.")),
|
|
25
|
+
Project: h.filter((e) => e.startsWith("project.")),
|
|
26
|
+
Task: h.filter((e) => e.startsWith("task.")),
|
|
27
|
+
Comment: h.filter((e) => e.startsWith("comment.")),
|
|
28
|
+
File: h.filter((e) => e.startsWith("file.")),
|
|
29
|
+
Member: h.filter((e) => e.startsWith("member."))
|
|
30
|
+
}, E = () => {
|
|
31
|
+
let { appId: h } = S(), { navigate: E, basePath: D } = e(), [O, k] = y({
|
|
32
|
+
applicationId: h || "",
|
|
33
33
|
name: "",
|
|
34
34
|
description: "",
|
|
35
35
|
url: "",
|
|
36
36
|
events: [],
|
|
37
37
|
retryEnabled: !0,
|
|
38
38
|
maxRetries: 3
|
|
39
|
-
}), [
|
|
39
|
+
}), [A, j] = y({}), [M, N] = y(null), { data: P } = l({
|
|
40
|
+
variables: { id: h ?? "" },
|
|
41
|
+
skip: !h,
|
|
42
|
+
fetchPolicy: "cache-first"
|
|
43
|
+
});
|
|
44
|
+
_(() => {
|
|
45
|
+
let e = P?.application?.name;
|
|
46
|
+
if (!h || !e) return;
|
|
47
|
+
let t = window.__breadcrumbRegistry;
|
|
48
|
+
return t?.register(h, e), () => t?.unregister(h);
|
|
49
|
+
}, [h, P?.application?.name]);
|
|
50
|
+
let { data: F, loading: I, error: L } = u({
|
|
40
51
|
variables: { limit: 100 },
|
|
41
|
-
skip: !!
|
|
52
|
+
skip: !!h,
|
|
42
53
|
fetchPolicy: "cache-and-network"
|
|
43
|
-
}), [
|
|
54
|
+
}), [R, { loading: z }] = c(), B = t(), V = g(), H = m(f.WEBHOOK_CREATE), U = v(() => F?.applications?.edges?.map((e) => e.node).map((e) => ({
|
|
44
55
|
id: e.id,
|
|
45
56
|
name: e.name,
|
|
46
57
|
slug: e.slug
|
|
47
|
-
})) ?? [], [
|
|
48
|
-
|
|
58
|
+
})) ?? [], [F?.applications?.edges]), W = U.find((e) => e.id === O.applicationId), G = (e, t) => {
|
|
59
|
+
k((n) => ({
|
|
49
60
|
...n,
|
|
50
61
|
[e]: t
|
|
51
|
-
})),
|
|
62
|
+
})), j((t) => {
|
|
52
63
|
if (!t[e]) return t;
|
|
53
64
|
let n = { ...t };
|
|
54
65
|
return delete n[e], n;
|
|
55
66
|
});
|
|
56
|
-
},
|
|
57
|
-
|
|
67
|
+
}, K = (e) => {
|
|
68
|
+
k((t) => ({
|
|
58
69
|
...t,
|
|
59
70
|
events: t.events.includes(e) ? t.events.filter((t) => t !== e) : [...t.events, e]
|
|
60
71
|
}));
|
|
61
|
-
},
|
|
62
|
-
let t = e.every((e) =>
|
|
63
|
-
|
|
72
|
+
}, q = (e) => {
|
|
73
|
+
let t = e.every((e) => O.events.includes(e));
|
|
74
|
+
k((n) => ({
|
|
64
75
|
...n,
|
|
65
76
|
events: t ? n.events.filter((t) => !e.includes(t)) : [...new Set([...n.events, ...e])]
|
|
66
77
|
}));
|
|
67
|
-
},
|
|
78
|
+
}, J = () => {
|
|
68
79
|
let e = {};
|
|
69
|
-
return
|
|
80
|
+
return O.applicationId || (e.applicationId = V("devportal.createWebhook.errors.appRequired", "Select an application")), O.name.trim() || (e.name = V("devportal.createWebhook.errors.nameRequired", "Name is required")), O.url.trim() ? /^https:\/\//i.test(O.url) || (e.url = V("devportal.createWebhook.errors.urlHttps", "Endpoint URL must use HTTPS")) : e.url = V("devportal.createWebhook.errors.urlRequired", "Endpoint URL is required"), O.events.length === 0 && (e.events = V("devportal.createWebhook.errors.eventsRequired", "Select at least one event")), O.retryEnabled && (O.maxRetries < 1 || O.maxRetries > 10) && (e.maxRetries = V("devportal.createWebhook.errors.retriesRange", "Retry count must be between 1 and 10")), j(e), Object.keys(e).length === 0;
|
|
70
81
|
};
|
|
71
|
-
return /* @__PURE__ */
|
|
72
|
-
permission:
|
|
73
|
-
children: /* @__PURE__ */
|
|
74
|
-
title:
|
|
75
|
-
description:
|
|
76
|
-
backLink:
|
|
77
|
-
backLabel:
|
|
78
|
-
children: /* @__PURE__ */
|
|
82
|
+
return /* @__PURE__ */ C(d, {
|
|
83
|
+
permission: f.WEBHOOK_CREATE,
|
|
84
|
+
children: /* @__PURE__ */ C(n, {
|
|
85
|
+
title: V("devportal.createWebhook.title", "Create Webhook"),
|
|
86
|
+
description: V("devportal.createWebhook.description", "Set up a real webhook endpoint to receive platform events through the public gateway"),
|
|
87
|
+
backLink: O.applicationId ? `/apps/${O.applicationId}/webhooks` : "/webhooks",
|
|
88
|
+
backLabel: V("devportal.createWebhook.back", "Back to Webhooks"),
|
|
89
|
+
children: /* @__PURE__ */ w("form", {
|
|
79
90
|
onSubmit: async (e) => {
|
|
80
|
-
if (e.preventDefault(),
|
|
81
|
-
let e = (await
|
|
82
|
-
applicationId:
|
|
91
|
+
if (e.preventDefault(), N(null), J()) try {
|
|
92
|
+
let e = (await R({ variables: {
|
|
93
|
+
applicationId: O.applicationId,
|
|
83
94
|
input: {
|
|
84
|
-
name:
|
|
85
|
-
description:
|
|
86
|
-
url:
|
|
87
|
-
events:
|
|
88
|
-
retryEnabled:
|
|
89
|
-
maxRetries:
|
|
95
|
+
name: O.name.trim(),
|
|
96
|
+
description: O.description.trim() || void 0,
|
|
97
|
+
url: O.url.trim(),
|
|
98
|
+
events: O.events,
|
|
99
|
+
retryEnabled: O.retryEnabled,
|
|
100
|
+
maxRetries: O.retryEnabled ? O.maxRetries : 0
|
|
90
101
|
}
|
|
91
102
|
} })).data?.createWebhook;
|
|
92
|
-
if (!e?.id) throw Error(
|
|
93
|
-
|
|
103
|
+
if (!e?.id) throw Error(V("devportal.createWebhook.errors.noId", "Webhook creation did not return an identifier"));
|
|
104
|
+
B.emit("devportal.webhook.created", {
|
|
94
105
|
webhookId: e.id,
|
|
95
|
-
applicationId:
|
|
96
|
-
}),
|
|
106
|
+
applicationId: O.applicationId
|
|
107
|
+
}), E?.(`${D}/apps/${O.applicationId}/webhooks/${e.id}`);
|
|
97
108
|
} catch (e) {
|
|
98
|
-
|
|
109
|
+
N(e instanceof Error ? e.message : V("devportal.createWebhook.errors.createFailed", "Failed to create webhook"));
|
|
99
110
|
}
|
|
100
111
|
},
|
|
101
112
|
className: "space-y-6",
|
|
102
113
|
children: [
|
|
103
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ C(s, {
|
|
104
115
|
variant: "info",
|
|
105
|
-
children:
|
|
116
|
+
children: V("devportal.createWebhook.info", "Webhook deliveries are signed and sent through the public global gateway. Use an HTTPS endpoint that accepts POST requests and returns a 2xx response for successful deliveries.")
|
|
106
117
|
}),
|
|
107
|
-
|
|
118
|
+
M && /* @__PURE__ */ C(s, {
|
|
108
119
|
variant: "error",
|
|
109
|
-
children:
|
|
120
|
+
children: M
|
|
110
121
|
}),
|
|
111
|
-
|
|
122
|
+
L && !h && /* @__PURE__ */ C(s, {
|
|
112
123
|
variant: "error",
|
|
113
|
-
children:
|
|
124
|
+
children: p(L)
|
|
114
125
|
}),
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
title:
|
|
117
|
-
children: /* @__PURE__ */
|
|
126
|
+
/* @__PURE__ */ C(r, {
|
|
127
|
+
title: V("devportal.createWebhook.basicInfo", "Basic Information"),
|
|
128
|
+
children: /* @__PURE__ */ w("div", {
|
|
118
129
|
className: "space-y-4 rounded-lg border bg-card p-4",
|
|
119
130
|
children: [
|
|
120
|
-
!
|
|
131
|
+
!h && /* @__PURE__ */ w("label", {
|
|
121
132
|
className: "grid gap-2 text-sm font-medium",
|
|
122
133
|
children: [
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
-
value:
|
|
126
|
-
onChange: (e) =>
|
|
127
|
-
disabled:
|
|
128
|
-
"aria-label":
|
|
134
|
+
/* @__PURE__ */ C("span", { children: V("devportal.createWebhook.application", "Application") }),
|
|
135
|
+
/* @__PURE__ */ w("select", {
|
|
136
|
+
value: O.applicationId,
|
|
137
|
+
onChange: (e) => G("applicationId", e.target.value),
|
|
138
|
+
disabled: I,
|
|
139
|
+
"aria-label": V("devportal.createWebhook.application", "Application"),
|
|
129
140
|
className: "rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
141
|
+
children: [/* @__PURE__ */ C("option", {
|
|
131
142
|
value: "",
|
|
132
|
-
children:
|
|
133
|
-
}),
|
|
143
|
+
children: V("devportal.createWebhook.errors.appRequired", "Select an application")
|
|
144
|
+
}), U.map((e) => /* @__PURE__ */ C("option", {
|
|
134
145
|
value: e.id,
|
|
135
146
|
children: e.name
|
|
136
147
|
}, e.id))]
|
|
137
148
|
}),
|
|
138
|
-
|
|
149
|
+
A.applicationId && /* @__PURE__ */ C("span", {
|
|
139
150
|
className: "text-sm text-status-error-text",
|
|
140
|
-
children:
|
|
151
|
+
children: A.applicationId
|
|
141
152
|
})
|
|
142
153
|
]
|
|
143
154
|
}),
|
|
144
|
-
|
|
155
|
+
I && !h && /* @__PURE__ */ w("div", {
|
|
145
156
|
className: "flex items-center gap-2 text-sm text-muted-foreground",
|
|
146
157
|
role: "status",
|
|
147
158
|
"aria-live": "polite",
|
|
148
|
-
children: [/* @__PURE__ */
|
|
159
|
+
children: [/* @__PURE__ */ C(b, {
|
|
149
160
|
className: "h-4 w-4 animate-spin",
|
|
150
161
|
"aria-hidden": "true"
|
|
151
|
-
}),
|
|
162
|
+
}), V("devportal.createWebhook.loadingApps", "Loading applications...")]
|
|
152
163
|
}),
|
|
153
|
-
|
|
164
|
+
W && /* @__PURE__ */ w("div", {
|
|
154
165
|
className: "rounded-md border bg-muted/40 px-3 py-2 text-sm text-muted-foreground",
|
|
155
166
|
children: [
|
|
156
|
-
|
|
167
|
+
V("devportal.createWebhook.creatingFor", "Creating webhook for"),
|
|
157
168
|
" ",
|
|
158
|
-
/* @__PURE__ */
|
|
169
|
+
/* @__PURE__ */ C("span", {
|
|
159
170
|
className: "font-medium text-foreground",
|
|
160
|
-
children:
|
|
171
|
+
children: W.name
|
|
161
172
|
})
|
|
162
173
|
]
|
|
163
174
|
}),
|
|
164
|
-
/* @__PURE__ */
|
|
165
|
-
label:
|
|
166
|
-
value:
|
|
167
|
-
onChange: (e) =>
|
|
168
|
-
placeholder:
|
|
169
|
-
error:
|
|
175
|
+
/* @__PURE__ */ C(a, {
|
|
176
|
+
label: V("devportal.createWebhook.webhookName", "Webhook Name"),
|
|
177
|
+
value: O.name,
|
|
178
|
+
onChange: (e) => G("name", e.target.value),
|
|
179
|
+
placeholder: V("devportal.createWebhook.webhookNamePlaceholder", "Production webhook"),
|
|
180
|
+
error: A.name,
|
|
170
181
|
required: !0
|
|
171
182
|
}),
|
|
172
|
-
/* @__PURE__ */
|
|
173
|
-
label:
|
|
174
|
-
value:
|
|
175
|
-
onChange: (e) =>
|
|
176
|
-
placeholder:
|
|
183
|
+
/* @__PURE__ */ C(o, {
|
|
184
|
+
label: V("devportal.createWebhook.descriptionLabel", "Description"),
|
|
185
|
+
value: O.description,
|
|
186
|
+
onChange: (e) => G("description", e.target.value),
|
|
187
|
+
placeholder: V("devportal.createWebhook.descriptionPlaceholder", "What this webhook is used for"),
|
|
177
188
|
rows: 2
|
|
178
189
|
}),
|
|
179
|
-
/* @__PURE__ */
|
|
180
|
-
label:
|
|
190
|
+
/* @__PURE__ */ C(a, {
|
|
191
|
+
label: V("devportal.createWebhook.endpointUrl", "Endpoint URL"),
|
|
181
192
|
type: "url",
|
|
182
|
-
value:
|
|
183
|
-
onChange: (e) =>
|
|
193
|
+
value: O.url,
|
|
194
|
+
onChange: (e) => G("url", e.target.value),
|
|
184
195
|
placeholder: "https://your-app.example.com/webhooks/burdenoff",
|
|
185
|
-
hint:
|
|
186
|
-
error:
|
|
196
|
+
hint: V("devportal.createWebhook.httpsOnly", "HTTPS only"),
|
|
197
|
+
error: A.url,
|
|
187
198
|
required: !0
|
|
188
199
|
})
|
|
189
200
|
]
|
|
190
201
|
})
|
|
191
202
|
}),
|
|
192
|
-
/* @__PURE__ */
|
|
193
|
-
title:
|
|
194
|
-
children: /* @__PURE__ */
|
|
203
|
+
/* @__PURE__ */ C(r, {
|
|
204
|
+
title: V("devportal.createWebhook.subscribedEvents", "Subscribed Events"),
|
|
205
|
+
children: /* @__PURE__ */ w("div", {
|
|
195
206
|
className: "space-y-4 rounded-lg border bg-card p-4",
|
|
196
|
-
children: [
|
|
207
|
+
children: [A.events && /* @__PURE__ */ C("p", {
|
|
197
208
|
className: "text-sm text-status-error-text",
|
|
198
209
|
role: "alert",
|
|
199
|
-
children:
|
|
200
|
-
}), Object.entries(
|
|
210
|
+
children: A.events
|
|
211
|
+
}), Object.entries(T).map(([e, t]) => /* @__PURE__ */ w("section", {
|
|
201
212
|
className: "space-y-3 border-b pb-4 last:border-b-0 last:pb-0",
|
|
202
|
-
children: [/* @__PURE__ */
|
|
213
|
+
children: [/* @__PURE__ */ w("div", {
|
|
203
214
|
className: "flex items-center justify-between gap-3",
|
|
204
|
-
children: [/* @__PURE__ */
|
|
215
|
+
children: [/* @__PURE__ */ C("h3", {
|
|
205
216
|
className: "font-medium",
|
|
206
|
-
children:
|
|
207
|
-
}), /* @__PURE__ */
|
|
217
|
+
children: V(`devportal.createWebhook.category.${e.toLowerCase()}`, e)
|
|
218
|
+
}), /* @__PURE__ */ C("button", {
|
|
208
219
|
type: "button",
|
|
209
|
-
onClick: () =>
|
|
220
|
+
onClick: () => q(t),
|
|
210
221
|
className: "text-xs font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
|
|
211
|
-
children: t.every((e) =>
|
|
222
|
+
children: t.every((e) => O.events.includes(e)) ? V("devportal.createWebhook.deselectAll", "Deselect all") : V("devportal.createWebhook.selectAll", "Select all")
|
|
212
223
|
})]
|
|
213
|
-
}), /* @__PURE__ */
|
|
224
|
+
}), /* @__PURE__ */ C("div", {
|
|
214
225
|
className: "grid gap-2 sm:grid-cols-2",
|
|
215
|
-
children: t.map((e) => /* @__PURE__ */
|
|
226
|
+
children: t.map((e) => /* @__PURE__ */ w("label", {
|
|
216
227
|
className: "flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm",
|
|
217
|
-
children: [/* @__PURE__ */
|
|
228
|
+
children: [/* @__PURE__ */ C("input", {
|
|
218
229
|
type: "checkbox",
|
|
219
|
-
checked:
|
|
220
|
-
onChange: () =>
|
|
230
|
+
checked: O.events.includes(e),
|
|
231
|
+
onChange: () => K(e),
|
|
221
232
|
className: "rounded border-border-default text-primary focus:ring-primary",
|
|
222
233
|
"aria-label": e
|
|
223
|
-
}), /* @__PURE__ */
|
|
234
|
+
}), /* @__PURE__ */ C("code", {
|
|
224
235
|
className: "text-xs text-foreground",
|
|
225
236
|
children: e
|
|
226
237
|
})]
|
|
@@ -229,47 +240,47 @@ var C = {
|
|
|
229
240
|
}, e))]
|
|
230
241
|
})
|
|
231
242
|
}),
|
|
232
|
-
/* @__PURE__ */
|
|
233
|
-
title:
|
|
234
|
-
children: /* @__PURE__ */
|
|
243
|
+
/* @__PURE__ */ C(r, {
|
|
244
|
+
title: V("devportal.createWebhook.retrySettings", "Retry Settings"),
|
|
245
|
+
children: /* @__PURE__ */ w("div", {
|
|
235
246
|
className: "space-y-4 rounded-lg border bg-card p-4",
|
|
236
|
-
children: [/* @__PURE__ */
|
|
237
|
-
label:
|
|
238
|
-
description:
|
|
239
|
-
checked:
|
|
240
|
-
onChange: (e) =>
|
|
241
|
-
}),
|
|
242
|
-
label:
|
|
247
|
+
children: [/* @__PURE__ */ C(i, {
|
|
248
|
+
label: V("devportal.createWebhook.enableRetries", "Enable retries"),
|
|
249
|
+
description: V("devportal.createWebhook.enableRetriesDesc", "Retry failed deliveries automatically"),
|
|
250
|
+
checked: O.retryEnabled,
|
|
251
|
+
onChange: (e) => G("retryEnabled", e.target.checked)
|
|
252
|
+
}), O.retryEnabled && /* @__PURE__ */ C(a, {
|
|
253
|
+
label: V("devportal.createWebhook.maxRetries", "Maximum retries"),
|
|
243
254
|
type: "number",
|
|
244
|
-
value:
|
|
245
|
-
onChange: (e) =>
|
|
255
|
+
value: O.maxRetries,
|
|
256
|
+
onChange: (e) => G("maxRetries", Number(e.target.value)),
|
|
246
257
|
min: 1,
|
|
247
258
|
max: 10,
|
|
248
|
-
hint:
|
|
249
|
-
error:
|
|
259
|
+
hint: V("devportal.createWebhook.attemptsHint", "1 to 10 attempts"),
|
|
260
|
+
error: A.maxRetries
|
|
250
261
|
})]
|
|
251
262
|
})
|
|
252
263
|
}),
|
|
253
|
-
/* @__PURE__ */
|
|
264
|
+
/* @__PURE__ */ w("div", {
|
|
254
265
|
className: "flex flex-col gap-3 sm:flex-row",
|
|
255
|
-
children: [/* @__PURE__ */
|
|
266
|
+
children: [/* @__PURE__ */ C("button", {
|
|
256
267
|
type: "button",
|
|
257
|
-
onClick: () =>
|
|
268
|
+
onClick: () => E?.(`${D}${O.applicationId ? `/apps/${O.applicationId}/webhooks` : "/webhooks"}`),
|
|
258
269
|
className: "rounded-md border px-4 py-2 text-sm font-medium hover:bg-accent focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
|
|
259
|
-
children:
|
|
260
|
-
}), /* @__PURE__ */
|
|
270
|
+
children: V("devportal.common.cancel", "Cancel")
|
|
271
|
+
}), /* @__PURE__ */ w("button", {
|
|
261
272
|
type: "submit",
|
|
262
|
-
disabled:
|
|
263
|
-
"aria-disabled":
|
|
264
|
-
title:
|
|
273
|
+
disabled: z || I || !H.allowed,
|
|
274
|
+
"aria-disabled": z || I || !H.allowed,
|
|
275
|
+
title: H.allowed ? void 0 : V("devportal.common.noPermission", "You do not have permission to perform this action"),
|
|
265
276
|
className: "inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
|
|
266
|
-
children: [
|
|
277
|
+
children: [z ? /* @__PURE__ */ C(b, {
|
|
267
278
|
className: "h-4 w-4 animate-spin",
|
|
268
279
|
"aria-hidden": "true"
|
|
269
|
-
}) : /* @__PURE__ */ x
|
|
280
|
+
}) : /* @__PURE__ */ C(x, {
|
|
270
281
|
size: 16,
|
|
271
282
|
"aria-hidden": "true"
|
|
272
|
-
}),
|
|
283
|
+
}), z ? V("devportal.createWebhook.creating", "Creating...") : V("devportal.createWebhook.title", "Create Webhook")]
|
|
273
284
|
})]
|
|
274
285
|
})
|
|
275
286
|
]
|
|
@@ -278,6 +289,6 @@ var C = {
|
|
|
278
289
|
});
|
|
279
290
|
};
|
|
280
291
|
//#endregion
|
|
281
|
-
export {
|
|
292
|
+
export { E as CreateWebhookPage };
|
|
282
293
|
|
|
283
294
|
//# sourceMappingURL=CreateWebhookPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateWebhookPage.js","names":[],"sources":["../../../src/devportal/pages/CreateWebhookPage.tsx"],"sourcesContent":["import type { FC, FormEvent } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { Loader2, Webhook } from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n TextareaField,\n CheckboxField,\n} from \"../components/FormField\";\nimport { Alert } from \"../components/ConfirmDialog\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalEventBus } from \"../events\";\nimport { WEBHOOK_EVENTS } from \"../types\";\nimport {\n type GetApplicationsQuery,\n getErrorMessage,\n useCreateWebhookMutation,\n useGetApplicationsQuery,\n useDevportalPermission,\n} from \"../hooks\";\nimport { useTr } from \"../utils/i18n\";\n\nconst eventCategories = {\n Application: WEBHOOK_EVENTS.filter((event) =>\n event.startsWith(\"application.\"),\n ),\n Installation: WEBHOOK_EVENTS.filter((event) =>\n event.startsWith(\"installation.\"),\n ),\n User: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"user.\")),\n Workspace: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"workspace.\")),\n Project: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"project.\")),\n Task: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"task.\")),\n Comment: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"comment.\")),\n File: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"file.\")),\n Member: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"member.\")),\n};\n\ninterface CreateWebhookFormState {\n applicationId: string;\n name: string;\n description: string;\n url: string;\n events: string[];\n retryEnabled: boolean;\n maxRetries: number;\n}\n\ntype ApplicationOption =\n GetApplicationsQuery[\"applications\"][\"edges\"][number][\"node\"];\n\nexport const CreateWebhookPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath } = useDevportal();\n const [formData, setFormData] = useState<CreateWebhookFormState>({\n applicationId: appId || \"\",\n name: \"\",\n description: \"\",\n url: \"\",\n events: [],\n retryEnabled: true,\n maxRetries: 3,\n });\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [submitError, setSubmitError] = useState<string | null>(null);\n\n const {\n data: appsData,\n loading: appsLoading,\n error: appsError,\n } = useGetApplicationsQuery({\n variables: { limit: 100 },\n skip: !!appId,\n fetchPolicy: \"cache-and-network\",\n });\n const [createWebhook, { loading: isSubmitting }] = useCreateWebhookMutation();\n const bus = useDevportalEventBus();\n const tr = useTr();\n const createPerm = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.WEBHOOK_CREATE,\n );\n\n const applications = useMemo(\n () =>\n appsData?.applications?.edges\n ?.map(\n (edge: GetApplicationsQuery[\"applications\"][\"edges\"][number]) =>\n edge.node,\n )\n .map((application: ApplicationOption) => ({\n id: application.id,\n name: application.name,\n slug: application.slug,\n })) ?? [],\n [appsData?.applications?.edges],\n );\n\n const selectedApplication = applications.find(\n (application: { id: string; name: string; slug: string }) =>\n application.id === formData.applicationId,\n );\n\n const handleChange = <K extends keyof CreateWebhookFormState>(\n key: K,\n value: CreateWebhookFormState[K],\n ) => {\n setFormData((previous) => ({\n ...previous,\n [key]: value,\n }));\n setErrors((previous) => {\n if (!previous[key as string]) return previous;\n const nextErrors = { ...previous };\n delete nextErrors[key as string];\n return nextErrors;\n });\n };\n\n const toggleEvent = (event: string) => {\n setFormData((previous) => ({\n ...previous,\n events: previous.events.includes(event)\n ? previous.events.filter((value) => value !== event)\n : [...previous.events, event],\n }));\n };\n\n const toggleCategory = (events: readonly string[]) => {\n const allSelected = events.every((event) =>\n formData.events.includes(event),\n );\n\n setFormData((previous) => ({\n ...previous,\n events: allSelected\n ? previous.events.filter((event) => !events.includes(event))\n : [...new Set([...previous.events, ...events])],\n }));\n };\n\n const validate = (): boolean => {\n const nextErrors: Record<string, string> = {};\n\n if (!formData.applicationId) {\n nextErrors.applicationId = tr(\n \"devportal.createWebhook.errors.appRequired\",\n \"Select an application\",\n );\n }\n if (!formData.name.trim()) {\n nextErrors.name = tr(\n \"devportal.createWebhook.errors.nameRequired\",\n \"Name is required\",\n );\n }\n if (!formData.url.trim()) {\n nextErrors.url = tr(\n \"devportal.createWebhook.errors.urlRequired\",\n \"Endpoint URL is required\",\n );\n } else if (!/^https:\\/\\//i.test(formData.url)) {\n nextErrors.url = tr(\n \"devportal.createWebhook.errors.urlHttps\",\n \"Endpoint URL must use HTTPS\",\n );\n }\n if (formData.events.length === 0) {\n nextErrors.events = tr(\n \"devportal.createWebhook.errors.eventsRequired\",\n \"Select at least one event\",\n );\n }\n if (\n formData.retryEnabled &&\n (formData.maxRetries < 1 || formData.maxRetries > 10)\n ) {\n nextErrors.maxRetries = tr(\n \"devportal.createWebhook.errors.retriesRange\",\n \"Retry count must be between 1 and 10\",\n );\n }\n\n setErrors(nextErrors);\n return Object.keys(nextErrors).length === 0;\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setSubmitError(null);\n\n if (!validate()) return;\n\n try {\n const result = await createWebhook({\n variables: {\n applicationId: formData.applicationId,\n input: {\n name: formData.name.trim(),\n description: formData.description.trim() || undefined,\n url: formData.url.trim(),\n events: formData.events,\n retryEnabled: formData.retryEnabled,\n maxRetries: formData.retryEnabled ? formData.maxRetries : 0,\n },\n },\n });\n\n const createdWebhook = result.data?.createWebhook;\n if (!createdWebhook?.id) {\n throw new Error(\n tr(\n \"devportal.createWebhook.errors.noId\",\n \"Webhook creation did not return an identifier\",\n ),\n );\n }\n\n bus.emit(\"devportal.webhook.created\", {\n webhookId: createdWebhook.id,\n applicationId: formData.applicationId,\n });\n\n navigate?.(\n `${basePath}/apps/${formData.applicationId}/webhooks/${createdWebhook.id}`,\n );\n } catch (error) {\n setSubmitError(\n error instanceof Error\n ? error.message\n : tr(\n \"devportal.createWebhook.errors.createFailed\",\n \"Failed to create webhook\",\n ),\n );\n }\n };\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.WEBHOOK_CREATE}>\n <PageLayout\n title={tr(\"devportal.createWebhook.title\", \"Create Webhook\")}\n description={tr(\n \"devportal.createWebhook.description\",\n \"Set up a real webhook endpoint to receive platform events through the public gateway\",\n )}\n backLink={\n formData.applicationId\n ? `/apps/${formData.applicationId}/webhooks`\n : \"/webhooks\"\n }\n backLabel={tr(\"devportal.createWebhook.back\", \"Back to Webhooks\")}\n >\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <Alert variant=\"info\">\n {tr(\n \"devportal.createWebhook.info\",\n \"Webhook deliveries are signed and sent through the public global gateway. Use an HTTPS endpoint that accepts POST requests and returns a 2xx response for successful deliveries.\",\n )}\n </Alert>\n\n {submitError && <Alert variant=\"error\">{submitError}</Alert>}\n {appsError && !appId && (\n <Alert variant=\"error\">{getErrorMessage(appsError)}</Alert>\n )}\n\n <PageSection\n title={tr(\"devportal.createWebhook.basicInfo\", \"Basic Information\")}\n >\n <div className=\"space-y-4 rounded-lg border bg-card p-4\">\n {!appId && (\n <label className=\"grid gap-2 text-sm font-medium\">\n <span>\n {tr(\"devportal.createWebhook.application\", \"Application\")}\n </span>\n <select\n value={formData.applicationId}\n onChange={(changeEvent) =>\n handleChange(\"applicationId\", changeEvent.target.value)\n }\n disabled={appsLoading}\n aria-label={tr(\n \"devportal.createWebhook.application\",\n \"Application\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\n \"devportal.createWebhook.errors.appRequired\",\n \"Select an application\",\n )}\n </option>\n {applications.map(\n (application: { id: string; name: string }) => (\n <option key={application.id} value={application.id}>\n {application.name}\n </option>\n ),\n )}\n </select>\n {errors.applicationId && (\n <span className=\"text-sm text-status-error-text\">\n {errors.applicationId}\n </span>\n )}\n </label>\n )}\n\n {appsLoading && !appId && (\n <div\n className=\"flex items-center gap-2 text-sm text-muted-foreground\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <Loader2\n className=\"h-4 w-4 animate-spin\"\n aria-hidden=\"true\"\n />\n {tr(\n \"devportal.createWebhook.loadingApps\",\n \"Loading applications...\",\n )}\n </div>\n )}\n\n {selectedApplication && (\n <div className=\"rounded-md border bg-muted/40 px-3 py-2 text-sm text-muted-foreground\">\n {tr(\n \"devportal.createWebhook.creatingFor\",\n \"Creating webhook for\",\n )}{\" \"}\n <span className=\"font-medium text-foreground\">\n {selectedApplication.name}\n </span>\n </div>\n )}\n\n <InputField\n label={tr(\n \"devportal.createWebhook.webhookName\",\n \"Webhook Name\",\n )}\n value={formData.name}\n onChange={(changeEvent) =>\n handleChange(\"name\", changeEvent.target.value)\n }\n placeholder={tr(\n \"devportal.createWebhook.webhookNamePlaceholder\",\n \"Production webhook\",\n )}\n error={errors.name}\n required\n />\n\n <TextareaField\n label={tr(\n \"devportal.createWebhook.descriptionLabel\",\n \"Description\",\n )}\n value={formData.description}\n onChange={(changeEvent) =>\n handleChange(\"description\", changeEvent.target.value)\n }\n placeholder={tr(\n \"devportal.createWebhook.descriptionPlaceholder\",\n \"What this webhook is used for\",\n )}\n rows={2}\n />\n\n <InputField\n label={tr(\n \"devportal.createWebhook.endpointUrl\",\n \"Endpoint URL\",\n )}\n type=\"url\"\n value={formData.url}\n onChange={(changeEvent) =>\n handleChange(\"url\", changeEvent.target.value)\n }\n placeholder=\"https://your-app.example.com/webhooks/burdenoff\"\n hint={tr(\"devportal.createWebhook.httpsOnly\", \"HTTPS only\")}\n error={errors.url}\n required\n />\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\n \"devportal.createWebhook.subscribedEvents\",\n \"Subscribed Events\",\n )}\n >\n <div className=\"space-y-4 rounded-lg border bg-card p-4\">\n {errors.events && (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {errors.events}\n </p>\n )}\n {Object.entries(eventCategories).map(([category, events]) => (\n <section\n key={category}\n className=\"space-y-3 border-b pb-4 last:border-b-0 last:pb-0\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <h3 className=\"font-medium\">\n {tr(\n `devportal.createWebhook.category.${category.toLowerCase()}`,\n category,\n )}\n </h3>\n <button\n type=\"button\"\n onClick={() => toggleCategory(events)}\n className=\"text-xs font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {events.every((item) => formData.events.includes(item))\n ? tr(\n \"devportal.createWebhook.deselectAll\",\n \"Deselect all\",\n )\n : tr(\"devportal.createWebhook.selectAll\", \"Select all\")}\n </button>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {events.map((eventName) => (\n <label\n key={eventName}\n className=\"flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm\"\n >\n <input\n type=\"checkbox\"\n checked={formData.events.includes(eventName)}\n onChange={() => toggleEvent(eventName)}\n className=\"rounded border-border-default text-primary focus:ring-primary\"\n aria-label={eventName}\n />\n <code className=\"text-xs text-foreground\">\n {eventName}\n </code>\n </label>\n ))}\n </div>\n </section>\n ))}\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\n \"devportal.createWebhook.retrySettings\",\n \"Retry Settings\",\n )}\n >\n <div className=\"space-y-4 rounded-lg border bg-card p-4\">\n <CheckboxField\n label={tr(\n \"devportal.createWebhook.enableRetries\",\n \"Enable retries\",\n )}\n description={tr(\n \"devportal.createWebhook.enableRetriesDesc\",\n \"Retry failed deliveries automatically\",\n )}\n checked={formData.retryEnabled}\n onChange={(changeEvent) =>\n handleChange(\"retryEnabled\", changeEvent.target.checked)\n }\n />\n\n {formData.retryEnabled && (\n <InputField\n label={tr(\n \"devportal.createWebhook.maxRetries\",\n \"Maximum retries\",\n )}\n type=\"number\"\n value={formData.maxRetries}\n onChange={(changeEvent) =>\n handleChange(\"maxRetries\", Number(changeEvent.target.value))\n }\n min={1}\n max={10}\n hint={tr(\n \"devportal.createWebhook.attemptsHint\",\n \"1 to 10 attempts\",\n )}\n error={errors.maxRetries}\n />\n )}\n </div>\n </PageSection>\n\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <button\n type=\"button\"\n onClick={() =>\n navigate?.(\n `${basePath}${formData.applicationId ? `/apps/${formData.applicationId}/webhooks` : \"/webhooks\"}`,\n )\n }\n className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-accent focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {tr(\"devportal.common.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"submit\"\n disabled={isSubmitting || appsLoading || !createPerm.allowed}\n aria-disabled={isSubmitting || appsLoading || !createPerm.allowed}\n title={\n !createPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {isSubmitting ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <Webhook size={16} aria-hidden=\"true\" />\n )}\n {isSubmitting\n ? tr(\"devportal.createWebhook.creating\", \"Creating...\")\n : tr(\"devportal.createWebhook.title\", \"Create Webhook\")}\n </button>\n </div>\n </form>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateWebhookPage.js","names":[],"sources":["../../../src/devportal/pages/CreateWebhookPage.tsx"],"sourcesContent":["import type { FC, FormEvent } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { Loader2, Webhook } from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n TextareaField,\n CheckboxField,\n} from \"../components/FormField\";\nimport { Alert } from \"../components/ConfirmDialog\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalEventBus } from \"../events\";\nimport { WEBHOOK_EVENTS } from \"../types\";\nimport {\n type GetApplicationsQuery,\n getErrorMessage,\n useCreateWebhookMutation,\n useGetApplicationQuery,\n useGetApplicationsQuery,\n useDevportalPermission,\n} from \"../hooks\";\nimport { useTr } from \"../utils/i18n\";\n\nconst eventCategories = {\n Application: WEBHOOK_EVENTS.filter((event) =>\n event.startsWith(\"application.\"),\n ),\n Installation: WEBHOOK_EVENTS.filter((event) =>\n event.startsWith(\"installation.\"),\n ),\n User: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"user.\")),\n Workspace: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"workspace.\")),\n Project: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"project.\")),\n Task: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"task.\")),\n Comment: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"comment.\")),\n File: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"file.\")),\n Member: WEBHOOK_EVENTS.filter((event) => event.startsWith(\"member.\")),\n};\n\ninterface CreateWebhookFormState {\n applicationId: string;\n name: string;\n description: string;\n url: string;\n events: string[];\n retryEnabled: boolean;\n maxRetries: number;\n}\n\ntype ApplicationOption =\n GetApplicationsQuery[\"applications\"][\"edges\"][number][\"node\"];\n\nexport const CreateWebhookPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath } = useDevportal();\n const [formData, setFormData] = useState<CreateWebhookFormState>({\n applicationId: appId || \"\",\n name: \"\",\n description: \"\",\n url: \"\",\n events: [],\n retryEnabled: true,\n maxRetries: 3,\n });\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [submitError, setSubmitError] = useState<string | null>(null);\n\n const { data: singleAppData } = useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-first\",\n });\n\n useEffect(() => {\n const name = singleAppData?.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, singleAppData?.application?.name]);\n\n const {\n data: appsData,\n loading: appsLoading,\n error: appsError,\n } = useGetApplicationsQuery({\n variables: { limit: 100 },\n skip: !!appId,\n fetchPolicy: \"cache-and-network\",\n });\n const [createWebhook, { loading: isSubmitting }] = useCreateWebhookMutation();\n const bus = useDevportalEventBus();\n const tr = useTr();\n const createPerm = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.WEBHOOK_CREATE,\n );\n\n const applications = useMemo(\n () =>\n appsData?.applications?.edges\n ?.map(\n (edge: GetApplicationsQuery[\"applications\"][\"edges\"][number]) =>\n edge.node,\n )\n .map((application: ApplicationOption) => ({\n id: application.id,\n name: application.name,\n slug: application.slug,\n })) ?? [],\n [appsData?.applications?.edges],\n );\n\n const selectedApplication = applications.find(\n (application: { id: string; name: string; slug: string }) =>\n application.id === formData.applicationId,\n );\n\n const handleChange = <K extends keyof CreateWebhookFormState>(\n key: K,\n value: CreateWebhookFormState[K],\n ) => {\n setFormData((previous) => ({\n ...previous,\n [key]: value,\n }));\n setErrors((previous) => {\n if (!previous[key as string]) return previous;\n const nextErrors = { ...previous };\n delete nextErrors[key as string];\n return nextErrors;\n });\n };\n\n const toggleEvent = (event: string) => {\n setFormData((previous) => ({\n ...previous,\n events: previous.events.includes(event)\n ? previous.events.filter((value) => value !== event)\n : [...previous.events, event],\n }));\n };\n\n const toggleCategory = (events: readonly string[]) => {\n const allSelected = events.every((event) =>\n formData.events.includes(event),\n );\n\n setFormData((previous) => ({\n ...previous,\n events: allSelected\n ? previous.events.filter((event) => !events.includes(event))\n : [...new Set([...previous.events, ...events])],\n }));\n };\n\n const validate = (): boolean => {\n const nextErrors: Record<string, string> = {};\n\n if (!formData.applicationId) {\n nextErrors.applicationId = tr(\n \"devportal.createWebhook.errors.appRequired\",\n \"Select an application\",\n );\n }\n if (!formData.name.trim()) {\n nextErrors.name = tr(\n \"devportal.createWebhook.errors.nameRequired\",\n \"Name is required\",\n );\n }\n if (!formData.url.trim()) {\n nextErrors.url = tr(\n \"devportal.createWebhook.errors.urlRequired\",\n \"Endpoint URL is required\",\n );\n } else if (!/^https:\\/\\//i.test(formData.url)) {\n nextErrors.url = tr(\n \"devportal.createWebhook.errors.urlHttps\",\n \"Endpoint URL must use HTTPS\",\n );\n }\n if (formData.events.length === 0) {\n nextErrors.events = tr(\n \"devportal.createWebhook.errors.eventsRequired\",\n \"Select at least one event\",\n );\n }\n if (\n formData.retryEnabled &&\n (formData.maxRetries < 1 || formData.maxRetries > 10)\n ) {\n nextErrors.maxRetries = tr(\n \"devportal.createWebhook.errors.retriesRange\",\n \"Retry count must be between 1 and 10\",\n );\n }\n\n setErrors(nextErrors);\n return Object.keys(nextErrors).length === 0;\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setSubmitError(null);\n\n if (!validate()) return;\n\n try {\n const result = await createWebhook({\n variables: {\n applicationId: formData.applicationId,\n input: {\n name: formData.name.trim(),\n description: formData.description.trim() || undefined,\n url: formData.url.trim(),\n events: formData.events,\n retryEnabled: formData.retryEnabled,\n maxRetries: formData.retryEnabled ? formData.maxRetries : 0,\n },\n },\n });\n\n const createdWebhook = result.data?.createWebhook;\n if (!createdWebhook?.id) {\n throw new Error(\n tr(\n \"devportal.createWebhook.errors.noId\",\n \"Webhook creation did not return an identifier\",\n ),\n );\n }\n\n bus.emit(\"devportal.webhook.created\", {\n webhookId: createdWebhook.id,\n applicationId: formData.applicationId,\n });\n\n navigate?.(\n `${basePath}/apps/${formData.applicationId}/webhooks/${createdWebhook.id}`,\n );\n } catch (error) {\n setSubmitError(\n error instanceof Error\n ? error.message\n : tr(\n \"devportal.createWebhook.errors.createFailed\",\n \"Failed to create webhook\",\n ),\n );\n }\n };\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.WEBHOOK_CREATE}>\n <PageLayout\n title={tr(\"devportal.createWebhook.title\", \"Create Webhook\")}\n description={tr(\n \"devportal.createWebhook.description\",\n \"Set up a real webhook endpoint to receive platform events through the public gateway\",\n )}\n backLink={\n formData.applicationId\n ? `/apps/${formData.applicationId}/webhooks`\n : \"/webhooks\"\n }\n backLabel={tr(\"devportal.createWebhook.back\", \"Back to Webhooks\")}\n >\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <Alert variant=\"info\">\n {tr(\n \"devportal.createWebhook.info\",\n \"Webhook deliveries are signed and sent through the public global gateway. Use an HTTPS endpoint that accepts POST requests and returns a 2xx response for successful deliveries.\",\n )}\n </Alert>\n\n {submitError && <Alert variant=\"error\">{submitError}</Alert>}\n {appsError && !appId && (\n <Alert variant=\"error\">{getErrorMessage(appsError)}</Alert>\n )}\n\n <PageSection\n title={tr(\"devportal.createWebhook.basicInfo\", \"Basic Information\")}\n >\n <div className=\"space-y-4 rounded-lg border bg-card p-4\">\n {!appId && (\n <label className=\"grid gap-2 text-sm font-medium\">\n <span>\n {tr(\"devportal.createWebhook.application\", \"Application\")}\n </span>\n <select\n value={formData.applicationId}\n onChange={(changeEvent) =>\n handleChange(\"applicationId\", changeEvent.target.value)\n }\n disabled={appsLoading}\n aria-label={tr(\n \"devportal.createWebhook.application\",\n \"Application\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\n \"devportal.createWebhook.errors.appRequired\",\n \"Select an application\",\n )}\n </option>\n {applications.map(\n (application: { id: string; name: string }) => (\n <option key={application.id} value={application.id}>\n {application.name}\n </option>\n ),\n )}\n </select>\n {errors.applicationId && (\n <span className=\"text-sm text-status-error-text\">\n {errors.applicationId}\n </span>\n )}\n </label>\n )}\n\n {appsLoading && !appId && (\n <div\n className=\"flex items-center gap-2 text-sm text-muted-foreground\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <Loader2\n className=\"h-4 w-4 animate-spin\"\n aria-hidden=\"true\"\n />\n {tr(\n \"devportal.createWebhook.loadingApps\",\n \"Loading applications...\",\n )}\n </div>\n )}\n\n {selectedApplication && (\n <div className=\"rounded-md border bg-muted/40 px-3 py-2 text-sm text-muted-foreground\">\n {tr(\n \"devportal.createWebhook.creatingFor\",\n \"Creating webhook for\",\n )}{\" \"}\n <span className=\"font-medium text-foreground\">\n {selectedApplication.name}\n </span>\n </div>\n )}\n\n <InputField\n label={tr(\n \"devportal.createWebhook.webhookName\",\n \"Webhook Name\",\n )}\n value={formData.name}\n onChange={(changeEvent) =>\n handleChange(\"name\", changeEvent.target.value)\n }\n placeholder={tr(\n \"devportal.createWebhook.webhookNamePlaceholder\",\n \"Production webhook\",\n )}\n error={errors.name}\n required\n />\n\n <TextareaField\n label={tr(\n \"devportal.createWebhook.descriptionLabel\",\n \"Description\",\n )}\n value={formData.description}\n onChange={(changeEvent) =>\n handleChange(\"description\", changeEvent.target.value)\n }\n placeholder={tr(\n \"devportal.createWebhook.descriptionPlaceholder\",\n \"What this webhook is used for\",\n )}\n rows={2}\n />\n\n <InputField\n label={tr(\n \"devportal.createWebhook.endpointUrl\",\n \"Endpoint URL\",\n )}\n type=\"url\"\n value={formData.url}\n onChange={(changeEvent) =>\n handleChange(\"url\", changeEvent.target.value)\n }\n placeholder=\"https://your-app.example.com/webhooks/burdenoff\"\n hint={tr(\"devportal.createWebhook.httpsOnly\", \"HTTPS only\")}\n error={errors.url}\n required\n />\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\n \"devportal.createWebhook.subscribedEvents\",\n \"Subscribed Events\",\n )}\n >\n <div className=\"space-y-4 rounded-lg border bg-card p-4\">\n {errors.events && (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {errors.events}\n </p>\n )}\n {Object.entries(eventCategories).map(([category, events]) => (\n <section\n key={category}\n className=\"space-y-3 border-b pb-4 last:border-b-0 last:pb-0\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <h3 className=\"font-medium\">\n {tr(\n `devportal.createWebhook.category.${category.toLowerCase()}`,\n category,\n )}\n </h3>\n <button\n type=\"button\"\n onClick={() => toggleCategory(events)}\n className=\"text-xs font-medium text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {events.every((item) => formData.events.includes(item))\n ? tr(\n \"devportal.createWebhook.deselectAll\",\n \"Deselect all\",\n )\n : tr(\"devportal.createWebhook.selectAll\", \"Select all\")}\n </button>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {events.map((eventName) => (\n <label\n key={eventName}\n className=\"flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm\"\n >\n <input\n type=\"checkbox\"\n checked={formData.events.includes(eventName)}\n onChange={() => toggleEvent(eventName)}\n className=\"rounded border-border-default text-primary focus:ring-primary\"\n aria-label={eventName}\n />\n <code className=\"text-xs text-foreground\">\n {eventName}\n </code>\n </label>\n ))}\n </div>\n </section>\n ))}\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\n \"devportal.createWebhook.retrySettings\",\n \"Retry Settings\",\n )}\n >\n <div className=\"space-y-4 rounded-lg border bg-card p-4\">\n <CheckboxField\n label={tr(\n \"devportal.createWebhook.enableRetries\",\n \"Enable retries\",\n )}\n description={tr(\n \"devportal.createWebhook.enableRetriesDesc\",\n \"Retry failed deliveries automatically\",\n )}\n checked={formData.retryEnabled}\n onChange={(changeEvent) =>\n handleChange(\"retryEnabled\", changeEvent.target.checked)\n }\n />\n\n {formData.retryEnabled && (\n <InputField\n label={tr(\n \"devportal.createWebhook.maxRetries\",\n \"Maximum retries\",\n )}\n type=\"number\"\n value={formData.maxRetries}\n onChange={(changeEvent) =>\n handleChange(\"maxRetries\", Number(changeEvent.target.value))\n }\n min={1}\n max={10}\n hint={tr(\n \"devportal.createWebhook.attemptsHint\",\n \"1 to 10 attempts\",\n )}\n error={errors.maxRetries}\n />\n )}\n </div>\n </PageSection>\n\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <button\n type=\"button\"\n onClick={() =>\n navigate?.(\n `${basePath}${formData.applicationId ? `/apps/${formData.applicationId}/webhooks` : \"/webhooks\"}`,\n )\n }\n className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-accent focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {tr(\"devportal.common.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"submit\"\n disabled={isSubmitting || appsLoading || !createPerm.allowed}\n aria-disabled={isSubmitting || appsLoading || !createPerm.allowed}\n title={\n !createPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {isSubmitting ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <Webhook size={16} aria-hidden=\"true\" />\n )}\n {isSubmitting\n ? tr(\"devportal.createWebhook.creating\", \"Creating...\")\n : tr(\"devportal.createWebhook.title\", \"Create Webhook\")}\n </button>\n </div>\n </form>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
@@ -331,7 +331,7 @@ var A = ({ type: t, className: n }) => {
|
|
|
331
331
|
let { t: f } = m(), _ = (e, t) => {
|
|
332
332
|
let n = f(e);
|
|
333
333
|
return n === e ? t : n;
|
|
334
|
-
}, { allowed: y } = ee(u.DELEGATION_REVOKE), [b, C] = p("acting-as-me"), [w, O] = p([]), [k, A] = p(null), [j, M] = p(/* @__PURE__ */ new Set()), { data: N, loading: ce, error: le, refetch: P } = o({ fetchPolicy: "cache-and-network" }), { data: F, loading: ue, error: de, refetch: I } = s({ fetchPolicy: "cache-and-network" }), [L, { loading: R }] = c(), z = (N?.currentUserDelegations ?? []).map(D), B = (F?.currentUserGrantedDelegations ?? []).map(D), V = z.filter((e) => e.status === "ACTIVE"), H = z.filter((e) => e.status !== "ACTIVE"), U = B.filter((e) => e.status === "ACTIVE"), W = b === "acting-as-me" ? V : U, G = te(() => W.filter((e) => j.has(e.id)), [j, W]), K = W.length > 0 && W.every((e) => j.has(e.id)), fe = W.some((e) => j.has(e.id)) && !K, q = b === "acting-as-me" ? ce : ue, J = b === "acting-as-me" ? le : de, Y = d((e) => {
|
|
334
|
+
}, { allowed: y } = ee(u.DELEGATION_REVOKE), [b, C] = p("acting-as-me"), [w, O] = p([]), [k, A] = p(null), [j, M] = p(/* @__PURE__ */ new Set()), { data: N, loading: ce, error: le, refetch: P } = o({ fetchPolicy: "cache-and-network" }), { data: F, loading: ue, error: de, refetch: I } = s({ fetchPolicy: "cache-and-network" }), [L, { loading: R }] = c(), z = (N?.currentUserDelegations?.delegations ?? []).map(D), B = (F?.currentUserGrantedDelegations?.delegations ?? []).map(D), V = z.filter((e) => e.status === "ACTIVE"), H = z.filter((e) => e.status !== "ACTIVE"), U = B.filter((e) => e.status === "ACTIVE"), W = b === "acting-as-me" ? V : U, G = te(() => W.filter((e) => j.has(e.id)), [j, W]), K = W.length > 0 && W.every((e) => j.has(e.id)), fe = W.some((e) => j.has(e.id)) && !K, q = b === "acting-as-me" ? ce : ue, J = b === "acting-as-me" ? le : de, Y = d((e) => {
|
|
335
335
|
O([e]);
|
|
336
336
|
}, []), X = d((e, t) => {
|
|
337
337
|
M((n) => {
|