@burdenoff/microfe-devportal 2026.609.3 → 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.
Files changed (58) hide show
  1. package/dist/devportal/DevportalRoot.js +6 -1
  2. package/dist/devportal/DevportalRoot.js.map +1 -1
  3. package/dist/devportal/DevportalRoutes.js +169 -158
  4. package/dist/devportal/DevportalRoutes.js.map +1 -1
  5. package/dist/devportal/hooks/usePackageUpload.js +120 -0
  6. package/dist/devportal/hooks/usePackageUpload.js.map +1 -0
  7. package/dist/devportal/pages/AnalyticsDashboardPage.js +73 -62
  8. package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
  9. package/dist/devportal/pages/AppLogsPage.js +89 -82
  10. package/dist/devportal/pages/AppLogsPage.js.map +1 -1
  11. package/dist/devportal/pages/ApplicationDetailPage.js +948 -367
  12. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  13. package/dist/devportal/pages/ApplicationVersionsPage.js +56 -45
  14. package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
  15. package/dist/devportal/pages/CreateApiKeyPage.js +30 -32
  16. package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
  17. package/dist/devportal/pages/CreateApplicationPage.js +8 -3
  18. package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
  19. package/dist/devportal/pages/CreateOAuthClientPage.js +4 -4
  20. package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
  21. package/dist/devportal/pages/CreateOrganizationPage.js +233 -228
  22. package/dist/devportal/pages/CreateOrganizationPage.js.map +1 -1
  23. package/dist/devportal/pages/CreateWebhookPage.js +159 -148
  24. package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
  25. package/dist/devportal/pages/DelegationsPage.js +1 -1
  26. package/dist/devportal/pages/DelegationsPage.js.map +1 -1
  27. package/dist/devportal/pages/EditApplicationPage.js +25 -17
  28. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  29. package/dist/devportal/pages/ListingPreviewPage.js +159 -153
  30. package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
  31. package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
  32. package/dist/devportal/pages/OAuthClientsPage.js +2 -2
  33. package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
  34. package/dist/devportal/pages/OrganizationDetailPage.js +158 -153
  35. package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
  36. package/dist/devportal/pages/OrganizationMembersPage.js +223 -212
  37. package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
  38. package/dist/devportal/pages/PublishPage.js +172 -165
  39. package/dist/devportal/pages/PublishPage.js.map +1 -1
  40. package/dist/devportal/pages/ResourcesPage.js.map +1 -1
  41. package/dist/devportal/pages/RevenueDashboardPage.js +405 -0
  42. package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -0
  43. package/dist/devportal/pages/SetupPage.js +170 -217
  44. package/dist/devportal/pages/SetupPage.js.map +1 -1
  45. package/dist/devportal/pages/StoreSubmissionPage.js +76 -97
  46. package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
  47. package/dist/devportal/pages/WebhookDetailPage.js +172 -154
  48. package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
  49. package/dist/devportal/pages/WebhooksPage.js +218 -200
  50. package/dist/devportal/pages/WebhooksPage.js.map +1 -1
  51. package/dist/devportal/providers/DevportalProvider.js +16 -13
  52. package/dist/devportal/providers/DevportalProvider.js.map +1 -1
  53. package/dist/devportal/types/index.js.map +1 -1
  54. package/dist/generated/global-operations.js +310 -225
  55. package/dist/generated/global-operations.js.map +1 -1
  56. package/package.json +1 -1
  57. package/dist/devportal/pages/RevenueRedirectPage.js +0 -14
  58. 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, useGetApplicationsQuery as l } from "../../generated/global-operations.js";
7
- import { PermissionGuard as u } from "../components/PermissionGuard.js";
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 d } from "../constants/permissions.js";
10
- import { getErrorMessage as f } from "../hooks/useGraphQL.js";
11
- import { useDevportalPermission as p } from "../hooks/usePermission.js";
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 m } from "../types/index.js";
14
- import { useTr as h } from "../utils/i18n.js";
15
- import { useMemo as g, useState as _ } from "react";
16
- import { Loader2 as v, Webhook as y } from "lucide-react";
17
- import { useParams as b } from "react-router-dom";
18
- import { jsx as x, jsxs as S } from "react/jsx-runtime";
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 C = {
21
- Application: m.filter((e) => e.startsWith("application.")),
22
- Installation: m.filter((e) => e.startsWith("installation.")),
23
- User: m.filter((e) => e.startsWith("user.")),
24
- Workspace: m.filter((e) => e.startsWith("workspace.")),
25
- Project: m.filter((e) => e.startsWith("project.")),
26
- Task: m.filter((e) => e.startsWith("task.")),
27
- Comment: m.filter((e) => e.startsWith("comment.")),
28
- File: m.filter((e) => e.startsWith("file.")),
29
- Member: m.filter((e) => e.startsWith("member."))
30
- }, w = () => {
31
- let { appId: m } = b(), { navigate: w, basePath: T } = e(), [E, D] = _({
32
- applicationId: m || "",
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
- }), [O, k] = _({}), [A, j] = _(null), { data: M, loading: N, error: P } = l({
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: !!m,
52
+ skip: !!h,
42
53
  fetchPolicy: "cache-and-network"
43
- }), [F, { loading: I }] = c(), L = t(), R = h(), z = p(d.WEBHOOK_CREATE), B = g(() => M?.applications?.edges?.map((e) => e.node).map((e) => ({
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
- })) ?? [], [M?.applications?.edges]), V = B.find((e) => e.id === E.applicationId), H = (e, t) => {
48
- D((n) => ({
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
- })), k((t) => {
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
- }, U = (e) => {
57
- D((t) => ({
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
- }, W = (e) => {
62
- let t = e.every((e) => E.events.includes(e));
63
- D((n) => ({
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
- }, G = () => {
78
+ }, J = () => {
68
79
  let e = {};
69
- return E.applicationId || (e.applicationId = R("devportal.createWebhook.errors.appRequired", "Select an application")), E.name.trim() || (e.name = R("devportal.createWebhook.errors.nameRequired", "Name is required")), E.url.trim() ? /^https:\/\//i.test(E.url) || (e.url = R("devportal.createWebhook.errors.urlHttps", "Endpoint URL must use HTTPS")) : e.url = R("devportal.createWebhook.errors.urlRequired", "Endpoint URL is required"), E.events.length === 0 && (e.events = R("devportal.createWebhook.errors.eventsRequired", "Select at least one event")), E.retryEnabled && (E.maxRetries < 1 || E.maxRetries > 10) && (e.maxRetries = R("devportal.createWebhook.errors.retriesRange", "Retry count must be between 1 and 10")), k(e), Object.keys(e).length === 0;
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__ */ x(u, {
72
- permission: d.WEBHOOK_CREATE,
73
- children: /* @__PURE__ */ x(n, {
74
- title: R("devportal.createWebhook.title", "Create Webhook"),
75
- description: R("devportal.createWebhook.description", "Set up a real webhook endpoint to receive platform events through the public gateway"),
76
- backLink: E.applicationId ? `/apps/${E.applicationId}/webhooks` : "/webhooks",
77
- backLabel: R("devportal.createWebhook.back", "Back to Webhooks"),
78
- children: /* @__PURE__ */ S("form", {
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(), j(null), G()) try {
81
- let e = (await F({ variables: {
82
- applicationId: E.applicationId,
91
+ if (e.preventDefault(), N(null), J()) try {
92
+ let e = (await R({ variables: {
93
+ applicationId: O.applicationId,
83
94
  input: {
84
- name: E.name.trim(),
85
- description: E.description.trim() || void 0,
86
- url: E.url.trim(),
87
- events: E.events,
88
- retryEnabled: E.retryEnabled,
89
- maxRetries: E.retryEnabled ? E.maxRetries : 0
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(R("devportal.createWebhook.errors.noId", "Webhook creation did not return an identifier"));
93
- L.emit("devportal.webhook.created", {
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: E.applicationId
96
- }), w?.(`${T}/apps/${E.applicationId}/webhooks/${e.id}`);
106
+ applicationId: O.applicationId
107
+ }), E?.(`${D}/apps/${O.applicationId}/webhooks/${e.id}`);
97
108
  } catch (e) {
98
- j(e instanceof Error ? e.message : R("devportal.createWebhook.errors.createFailed", "Failed to create webhook"));
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__ */ x(s, {
114
+ /* @__PURE__ */ C(s, {
104
115
  variant: "info",
105
- children: R("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.")
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
- A && /* @__PURE__ */ x(s, {
118
+ M && /* @__PURE__ */ C(s, {
108
119
  variant: "error",
109
- children: A
120
+ children: M
110
121
  }),
111
- P && !m && /* @__PURE__ */ x(s, {
122
+ L && !h && /* @__PURE__ */ C(s, {
112
123
  variant: "error",
113
- children: f(P)
124
+ children: p(L)
114
125
  }),
115
- /* @__PURE__ */ x(r, {
116
- title: R("devportal.createWebhook.basicInfo", "Basic Information"),
117
- children: /* @__PURE__ */ S("div", {
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
- !m && /* @__PURE__ */ S("label", {
131
+ !h && /* @__PURE__ */ w("label", {
121
132
  className: "grid gap-2 text-sm font-medium",
122
133
  children: [
123
- /* @__PURE__ */ x("span", { children: R("devportal.createWebhook.application", "Application") }),
124
- /* @__PURE__ */ S("select", {
125
- value: E.applicationId,
126
- onChange: (e) => H("applicationId", e.target.value),
127
- disabled: N,
128
- "aria-label": R("devportal.createWebhook.application", "Application"),
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__ */ x("option", {
141
+ children: [/* @__PURE__ */ C("option", {
131
142
  value: "",
132
- children: R("devportal.createWebhook.errors.appRequired", "Select an application")
133
- }), B.map((e) => /* @__PURE__ */ x("option", {
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
- O.applicationId && /* @__PURE__ */ x("span", {
149
+ A.applicationId && /* @__PURE__ */ C("span", {
139
150
  className: "text-sm text-status-error-text",
140
- children: O.applicationId
151
+ children: A.applicationId
141
152
  })
142
153
  ]
143
154
  }),
144
- N && !m && /* @__PURE__ */ S("div", {
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__ */ x(v, {
159
+ children: [/* @__PURE__ */ C(b, {
149
160
  className: "h-4 w-4 animate-spin",
150
161
  "aria-hidden": "true"
151
- }), R("devportal.createWebhook.loadingApps", "Loading applications...")]
162
+ }), V("devportal.createWebhook.loadingApps", "Loading applications...")]
152
163
  }),
153
- V && /* @__PURE__ */ S("div", {
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
- R("devportal.createWebhook.creatingFor", "Creating webhook for"),
167
+ V("devportal.createWebhook.creatingFor", "Creating webhook for"),
157
168
  " ",
158
- /* @__PURE__ */ x("span", {
169
+ /* @__PURE__ */ C("span", {
159
170
  className: "font-medium text-foreground",
160
- children: V.name
171
+ children: W.name
161
172
  })
162
173
  ]
163
174
  }),
164
- /* @__PURE__ */ x(a, {
165
- label: R("devportal.createWebhook.webhookName", "Webhook Name"),
166
- value: E.name,
167
- onChange: (e) => H("name", e.target.value),
168
- placeholder: R("devportal.createWebhook.webhookNamePlaceholder", "Production webhook"),
169
- error: O.name,
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__ */ x(o, {
173
- label: R("devportal.createWebhook.descriptionLabel", "Description"),
174
- value: E.description,
175
- onChange: (e) => H("description", e.target.value),
176
- placeholder: R("devportal.createWebhook.descriptionPlaceholder", "What this webhook is used for"),
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__ */ x(a, {
180
- label: R("devportal.createWebhook.endpointUrl", "Endpoint URL"),
190
+ /* @__PURE__ */ C(a, {
191
+ label: V("devportal.createWebhook.endpointUrl", "Endpoint URL"),
181
192
  type: "url",
182
- value: E.url,
183
- onChange: (e) => H("url", e.target.value),
193
+ value: O.url,
194
+ onChange: (e) => G("url", e.target.value),
184
195
  placeholder: "https://your-app.example.com/webhooks/burdenoff",
185
- hint: R("devportal.createWebhook.httpsOnly", "HTTPS only"),
186
- error: O.url,
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__ */ x(r, {
193
- title: R("devportal.createWebhook.subscribedEvents", "Subscribed Events"),
194
- children: /* @__PURE__ */ S("div", {
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: [O.events && /* @__PURE__ */ x("p", {
207
+ children: [A.events && /* @__PURE__ */ C("p", {
197
208
  className: "text-sm text-status-error-text",
198
209
  role: "alert",
199
- children: O.events
200
- }), Object.entries(C).map(([e, t]) => /* @__PURE__ */ S("section", {
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__ */ S("div", {
213
+ children: [/* @__PURE__ */ w("div", {
203
214
  className: "flex items-center justify-between gap-3",
204
- children: [/* @__PURE__ */ x("h3", {
215
+ children: [/* @__PURE__ */ C("h3", {
205
216
  className: "font-medium",
206
- children: R(`devportal.createWebhook.category.${e.toLowerCase()}`, e)
207
- }), /* @__PURE__ */ x("button", {
217
+ children: V(`devportal.createWebhook.category.${e.toLowerCase()}`, e)
218
+ }), /* @__PURE__ */ C("button", {
208
219
  type: "button",
209
- onClick: () => W(t),
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) => E.events.includes(e)) ? R("devportal.createWebhook.deselectAll", "Deselect all") : R("devportal.createWebhook.selectAll", "Select all")
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__ */ x("div", {
224
+ }), /* @__PURE__ */ C("div", {
214
225
  className: "grid gap-2 sm:grid-cols-2",
215
- children: t.map((e) => /* @__PURE__ */ S("label", {
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__ */ x("input", {
228
+ children: [/* @__PURE__ */ C("input", {
218
229
  type: "checkbox",
219
- checked: E.events.includes(e),
220
- onChange: () => U(e),
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__ */ x("code", {
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__ */ x(r, {
233
- title: R("devportal.createWebhook.retrySettings", "Retry Settings"),
234
- children: /* @__PURE__ */ S("div", {
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__ */ x(i, {
237
- label: R("devportal.createWebhook.enableRetries", "Enable retries"),
238
- description: R("devportal.createWebhook.enableRetriesDesc", "Retry failed deliveries automatically"),
239
- checked: E.retryEnabled,
240
- onChange: (e) => H("retryEnabled", e.target.checked)
241
- }), E.retryEnabled && /* @__PURE__ */ x(a, {
242
- label: R("devportal.createWebhook.maxRetries", "Maximum retries"),
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: E.maxRetries,
245
- onChange: (e) => H("maxRetries", Number(e.target.value)),
255
+ value: O.maxRetries,
256
+ onChange: (e) => G("maxRetries", Number(e.target.value)),
246
257
  min: 1,
247
258
  max: 10,
248
- hint: R("devportal.createWebhook.attemptsHint", "1 to 10 attempts"),
249
- error: O.maxRetries
259
+ hint: V("devportal.createWebhook.attemptsHint", "1 to 10 attempts"),
260
+ error: A.maxRetries
250
261
  })]
251
262
  })
252
263
  }),
253
- /* @__PURE__ */ S("div", {
264
+ /* @__PURE__ */ w("div", {
254
265
  className: "flex flex-col gap-3 sm:flex-row",
255
- children: [/* @__PURE__ */ x("button", {
266
+ children: [/* @__PURE__ */ C("button", {
256
267
  type: "button",
257
- onClick: () => w?.(`${T}${E.applicationId ? `/apps/${E.applicationId}/webhooks` : "/webhooks"}`),
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: R("devportal.common.cancel", "Cancel")
260
- }), /* @__PURE__ */ S("button", {
270
+ children: V("devportal.common.cancel", "Cancel")
271
+ }), /* @__PURE__ */ w("button", {
261
272
  type: "submit",
262
- disabled: I || N || !z.allowed,
263
- "aria-disabled": I || N || !z.allowed,
264
- title: z.allowed ? void 0 : R("devportal.common.noPermission", "You do not have permission to perform this action"),
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: [I ? /* @__PURE__ */ x(v, {
277
+ children: [z ? /* @__PURE__ */ C(b, {
267
278
  className: "h-4 w-4 animate-spin",
268
279
  "aria-hidden": "true"
269
- }) : /* @__PURE__ */ x(y, {
280
+ }) : /* @__PURE__ */ C(x, {
270
281
  size: 16,
271
282
  "aria-hidden": "true"
272
- }), I ? R("devportal.createWebhook.creating", "Creating...") : R("devportal.createWebhook.title", "Create Webhook")]
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 { w as CreateWebhookPage };
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) => {