@burdenoff/microfe-devportal 2026.720.4 → 2026.720.6

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 (36) hide show
  1. package/dist/devportal/hooks/usePackageUpload.d.ts.map +1 -1
  2. package/dist/devportal/hooks/usePackageUpload.js.map +1 -1
  3. package/dist/devportal/pages/ApplicationDetailPage.d.ts.map +1 -1
  4. package/dist/devportal/pages/ApplicationDetailPage.js +3 -3
  5. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  6. package/dist/devportal/pages/CreateApiKeyPage.d.ts.map +1 -1
  7. package/dist/devportal/pages/CreateApiKeyPage.js +103 -104
  8. package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
  9. package/dist/devportal/pages/CreateApplicationPage.d.ts.map +1 -1
  10. package/dist/devportal/pages/CreateApplicationPage.js +115 -116
  11. package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
  12. package/dist/devportal/pages/CreateOAuthClientPage.d.ts.map +1 -1
  13. package/dist/devportal/pages/CreateOAuthClientPage.js +129 -130
  14. package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
  15. package/dist/devportal/pages/CreateWebhookPage.js +1 -1
  16. package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
  17. package/dist/devportal/pages/DelegationsPage.js +214 -214
  18. package/dist/devportal/pages/DelegationsPage.js.map +1 -1
  19. package/dist/devportal/pages/EditApplicationPage.d.ts.map +1 -1
  20. package/dist/devportal/pages/EditApplicationPage.js +1 -1
  21. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  22. package/dist/devportal/pages/PublishPage.d.ts.map +1 -1
  23. package/dist/devportal/pages/PublishPage.js +106 -106
  24. package/dist/devportal/pages/PublishPage.js.map +1 -1
  25. package/dist/devportal/pages/SellerDashboardPage.d.ts.map +1 -1
  26. package/dist/devportal/pages/SellerDashboardPage.js +136 -137
  27. package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
  28. package/dist/devportal/pages/SellerItemsPage.d.ts.map +1 -1
  29. package/dist/devportal/pages/SellerItemsPage.js +190 -191
  30. package/dist/devportal/pages/SellerItemsPage.js.map +1 -1
  31. package/dist/devportal/pages/SellerOrdersPage.d.ts.map +1 -1
  32. package/dist/devportal/pages/SellerOrdersPage.js +138 -139
  33. package/dist/devportal/pages/SellerOrdersPage.js.map +1 -1
  34. package/dist/devportal/types/index.d.ts.map +1 -1
  35. package/dist/devportal/types/index.js.map +1 -1
  36. package/package.json +1 -1
@@ -8,241 +8,240 @@ import { InputField as l, SelectField as u, TextareaField as d } from "../compon
8
8
  import { PermissionGuard as f } from "../components/PermissionGuard.js";
9
9
  import "../components/index.js";
10
10
  import "../hooks/index.js";
11
- import { DEVPORTAL_PERMISSIONS as p } from "../constants/permissions.js";
12
- import { useState as m } from "react";
13
- import { useI18n as h } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
14
- import { Plus as g, Save as _, Trash2 as v, X as y } from "lucide-react";
15
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
16
- import { OptionalFields as S } from "@burdenoff/fe-libs/ui";
11
+ import { useState as p } from "react";
12
+ import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
13
+ import { Plus as h, Save as g, Trash2 as _, X as v } from "lucide-react";
14
+ import { jsx as y, jsxs as b } from "react/jsx-runtime";
15
+ import { OptionalFields as x } from "@burdenoff/fe-libs/ui";
17
16
  //#region src/devportal/pages/CreateOAuthClientPage.tsx
18
- var C = () => {
19
- let { navigate: C, basePath: w } = e(), { t: T } = h(), E = (e, t) => {
20
- let n = T(e);
17
+ var S = () => {
18
+ let { navigate: S, basePath: C } = e(), { t: w } = m(), T = (e, t) => {
19
+ let n = w(e);
21
20
  return n === e ? t : n;
22
- }, [D, O] = m(""), [k, A] = m(""), [j, M] = m("CONFIDENTIAL"), [N, P] = m([]), [F, I] = m(""), [L, R] = m([]), [z, B] = m(""), [V, H] = m(null), [U, W] = m(null), [G, { loading: K, error: q }] = n(), J = (e) => {
23
- C?.(`${w}${e}`);
24
- }, Y = () => {
25
- let e = F.trim();
26
- e && !N.includes(e) && (P([...N, e]), I(""));
27
- }, X = (e) => {
28
- P(N.filter((t) => t !== e));
29
- }, Z = () => {
30
- let e = z.trim();
31
- e && !L.includes(e) && (R([...L, e]), B(""));
32
- }, Q = (e) => {
33
- R(L.filter((t) => t !== e));
21
+ }, [E, D] = p(""), [O, k] = p(""), [A, j] = p("CONFIDENTIAL"), [M, N] = p([]), [P, F] = p(""), [I, L] = p([]), [R, z] = p(""), [B, V] = p(null), [H, U] = p(null), [W, { loading: G, error: K }] = n(), q = (e) => {
22
+ S?.(`${C}${e}`);
23
+ }, J = () => {
24
+ let e = P.trim();
25
+ e && !M.includes(e) && (N([...M, e]), F(""));
26
+ }, Y = (e) => {
27
+ N(M.filter((t) => t !== e));
28
+ }, X = () => {
29
+ let e = R.trim();
30
+ e && !I.includes(e) && (L([...I, e]), z(""));
31
+ }, Z = (e) => {
32
+ L(I.filter((t) => t !== e));
34
33
  };
35
- return V ? /* @__PURE__ */ b(i, {
36
- title: E("devportal.appCreated", "App Created!"),
37
- description: E("devportal.appCreatedDescription", "Save the client secret below. It will not be shown again."),
34
+ return B ? /* @__PURE__ */ y(i, {
35
+ title: T("devportal.appCreated", "App Created!"),
36
+ description: T("devportal.appCreatedDescription", "Save the client secret below. It will not be shown again."),
38
37
  backLink: "/oauth",
39
- backLabel: E("devportal.backToOAuthApps", "Back to OAuth Apps"),
40
- children: /* @__PURE__ */ x("div", {
38
+ backLabel: T("devportal.backToOAuthApps", "Back to OAuth Apps"),
39
+ children: /* @__PURE__ */ b("div", {
41
40
  className: "rounded-lg border border-border-subtle bg-status-success-bg-subtle p-6",
42
41
  children: [
43
- /* @__PURE__ */ b("h3", {
42
+ /* @__PURE__ */ y("h3", {
44
43
  className: "font-medium text-status-success-text",
45
- children: E("devportal.oauthAppCreated", "Your OAuth App has been created")
44
+ children: T("devportal.oauthAppCreated", "Your OAuth App has been created")
46
45
  }),
47
- /* @__PURE__ */ x("div", {
46
+ /* @__PURE__ */ b("div", {
48
47
  className: "mt-4 space-y-3",
49
- children: [/* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("label", {
48
+ children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
50
49
  className: "text-xs font-medium text-status-success-text",
51
- children: E("devportal.clientSecret", "Client Secret")
52
- }), /* @__PURE__ */ x("div", {
50
+ children: T("devportal.clientSecret", "Client Secret")
51
+ }), /* @__PURE__ */ b("div", {
53
52
  className: "mt-1 flex items-center gap-2",
54
- children: [/* @__PURE__ */ b("code", {
53
+ children: [/* @__PURE__ */ y("code", {
55
54
  className: "flex-1 rounded border bg-bg-surface px-3 py-2 text-sm font-mono break-all",
56
- children: V
57
- }), /* @__PURE__ */ b("button", {
55
+ children: B
56
+ }), /* @__PURE__ */ y("button", {
58
57
  onClick: async () => {
59
- s("light"), c(await o(V) ? "success" : "error");
58
+ s("light"), c(await o(B) ? "success" : "error");
60
59
  },
61
60
  className: "rounded bg-status-success-bg-subtle px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle transition-colors",
62
- children: E("devportal.copy", "Copy")
61
+ children: T("devportal.copy", "Copy")
63
62
  })]
64
- })] }), /* @__PURE__ */ b("p", {
63
+ })] }), /* @__PURE__ */ y("p", {
65
64
  className: "text-sm text-status-success-text",
66
- children: E("devportal.storeSecretSecurely", "Store this secret securely. You will not be able to see it again.")
65
+ children: T("devportal.storeSecretSecurely", "Store this secret securely. You will not be able to see it again.")
67
66
  })]
68
67
  }),
69
- /* @__PURE__ */ x("div", {
68
+ /* @__PURE__ */ b("div", {
70
69
  className: "mt-6 flex gap-3",
71
- children: [U && /* @__PURE__ */ b("button", {
72
- onClick: () => J(`/oauth/${U}`),
70
+ children: [H && /* @__PURE__ */ y("button", {
71
+ onClick: () => q(`/oauth/${H}`),
73
72
  className: "rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors",
74
- children: E("devportal.viewAppDetails", "View App Details")
75
- }), /* @__PURE__ */ b("button", {
76
- onClick: () => J("/oauth"),
73
+ children: T("devportal.viewAppDetails", "View App Details")
74
+ }), /* @__PURE__ */ y("button", {
75
+ onClick: () => q("/oauth"),
77
76
  className: "rounded-md border px-4 py-2 text-sm font-medium hover:bg-bg-sunken transition-colors",
78
- children: E("devportal.backToOAuthApps", "Back to OAuth Apps")
77
+ children: T("devportal.backToOAuthApps", "Back to OAuth Apps")
79
78
  })]
80
79
  })
81
80
  ]
82
81
  })
83
- }) : /* @__PURE__ */ b(f, {
84
- permission: p.APP_CREATE,
85
- children: /* @__PURE__ */ b(i, {
86
- title: E("devportal.createOAuthApp", "Create OAuth App"),
87
- description: E("devportal.createOAuthAppDescription", "Register a new OAuth application for authentication"),
88
- purpose: E("devportal.createOAuthAppPurpose", "Register an OAuth app so an external service can let users sign in with their account and call the API on their behalf. Set its redirect URIs and request only the scopes it needs — you will receive a client ID and secret to finish the integration."),
82
+ }) : /* @__PURE__ */ y(f, {
83
+ authOnly: !0,
84
+ children: /* @__PURE__ */ y(i, {
85
+ title: T("devportal.createOAuthApp", "Create OAuth App"),
86
+ description: T("devportal.createOAuthAppDescription", "Register a new OAuth application for authentication"),
87
+ purpose: T("devportal.createOAuthAppPurpose", "Register an OAuth app so an external service can let users sign in with their account and call the API on their behalf. Set its redirect URIs and request only the scopes it needs — you will receive a client ID and secret to finish the integration."),
89
88
  backLink: "/oauth",
90
- backLabel: E("devportal.backToOAuthApps", "Back to OAuth Apps"),
91
- children: /* @__PURE__ */ x("form", {
89
+ backLabel: T("devportal.backToOAuthApps", "Back to OAuth Apps"),
90
+ children: /* @__PURE__ */ b("form", {
92
91
  onSubmit: async (e) => {
93
- if (e.preventDefault(), D.trim()) try {
94
- let e = await G({ variables: { input: {
95
- name: D.trim(),
96
- description: k.trim() || void 0,
97
- type: j,
98
- scopes: N,
99
- redirectUris: L
92
+ if (e.preventDefault(), E.trim()) try {
93
+ let e = await W({ variables: { input: {
94
+ name: E.trim(),
95
+ description: O.trim() || void 0,
96
+ type: A,
97
+ scopes: M,
98
+ redirectUris: I
100
99
  } } }), t = e.data?.createApp?.clientSecret, n = e.data?.createApp?.app?.id;
101
- t && (H(t), W(n || null));
100
+ t && (V(t), U(n || null));
102
101
  } catch {}
103
102
  },
104
103
  className: "space-y-6 max-w-2xl",
105
104
  children: [
106
- q && /* @__PURE__ */ b("div", {
105
+ K && /* @__PURE__ */ y("div", {
107
106
  className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-4",
108
- children: /* @__PURE__ */ b("p", {
107
+ children: /* @__PURE__ */ y("p", {
109
108
  className: "text-sm text-status-error-text",
110
- children: r(q)
109
+ children: r(K)
111
110
  })
112
111
  }),
113
- /* @__PURE__ */ x(a, {
114
- title: E("devportal.basicInformation", "Basic Information"),
112
+ /* @__PURE__ */ b(a, {
113
+ title: T("devportal.basicInformation", "Basic Information"),
115
114
  children: [
116
- /* @__PURE__ */ b(l, {
117
- label: E("devportal.appName", "App Name"),
118
- value: D,
119
- onChange: (e) => O(e.target.value),
120
- placeholder: E("devportal.myOAuthAppPlaceholder", "My OAuth App"),
115
+ /* @__PURE__ */ y(l, {
116
+ label: T("devportal.appName", "App Name"),
117
+ value: E,
118
+ onChange: (e) => D(e.target.value),
119
+ placeholder: T("devportal.myOAuthAppPlaceholder", "My OAuth App"),
121
120
  required: !0
122
121
  }),
123
- /* @__PURE__ */ b(d, {
124
- label: E("devportal.description", "Description"),
125
- value: k,
126
- onChange: (e) => A(e.target.value),
127
- placeholder: E("devportal.appDescriptionPlaceholder", "Brief description of what this app does...")
122
+ /* @__PURE__ */ y(d, {
123
+ label: T("devportal.description", "Description"),
124
+ value: O,
125
+ onChange: (e) => k(e.target.value),
126
+ placeholder: T("devportal.appDescriptionPlaceholder", "Brief description of what this app does...")
128
127
  }),
129
- /* @__PURE__ */ b(u, {
130
- label: E("devportal.appType", "App Type"),
131
- value: j,
132
- onChange: (e) => M(e.target.value),
128
+ /* @__PURE__ */ y(u, {
129
+ label: T("devportal.appType", "App Type"),
130
+ value: A,
131
+ onChange: (e) => j(e.target.value),
133
132
  options: [
134
133
  {
135
134
  value: "SERVICE",
136
- label: E("devportal.appTypeService", "Service (M2M)")
135
+ label: T("devportal.appTypeService", "Service (M2M)")
137
136
  },
138
137
  {
139
138
  value: "INTEGRATION",
140
- label: E("devportal.appTypeIntegration", "Integration")
139
+ label: T("devportal.appTypeIntegration", "Integration")
141
140
  },
142
141
  {
143
142
  value: "BOT",
144
- label: E("devportal.appTypeBot", "Bot")
143
+ label: T("devportal.appTypeBot", "Bot")
145
144
  },
146
145
  {
147
146
  value: "WEB_APP",
148
- label: E("devportal.appTypeWebApp", "Web App")
147
+ label: T("devportal.appTypeWebApp", "Web App")
149
148
  },
150
149
  {
151
150
  value: "AUTOMATION",
152
- label: E("devportal.appTypeAutomation", "Automation")
151
+ label: T("devportal.appTypeAutomation", "Automation")
153
152
  }
154
153
  ]
155
154
  })
156
155
  ]
157
156
  }),
158
- /* @__PURE__ */ x(S, {
159
- title: E("devportal.advancedOAuthSettings", "Advanced settings"),
160
- description: E("devportal.advancedOAuthSettingsDescription", "Advanced grant types, PKCE-required toggles, scope tuning, and redirect URIs."),
161
- children: [/* @__PURE__ */ b(a, {
162
- title: E("devportal.scopes", "Scopes"),
163
- children: /* @__PURE__ */ x("div", {
157
+ /* @__PURE__ */ b(x, {
158
+ title: T("devportal.advancedOAuthSettings", "Advanced settings"),
159
+ description: T("devportal.advancedOAuthSettingsDescription", "Advanced grant types, PKCE-required toggles, scope tuning, and redirect URIs."),
160
+ children: [/* @__PURE__ */ y(a, {
161
+ title: T("devportal.scopes", "Scopes"),
162
+ children: /* @__PURE__ */ b("div", {
164
163
  className: "space-y-3",
165
- children: [/* @__PURE__ */ x("div", {
164
+ children: [/* @__PURE__ */ b("div", {
166
165
  className: "flex items-center gap-2",
167
- children: [/* @__PURE__ */ b("input", {
166
+ children: [/* @__PURE__ */ y("input", {
168
167
  type: "text",
169
- value: F,
170
- onChange: (e) => I(e.target.value),
168
+ value: P,
169
+ onChange: (e) => F(e.target.value),
171
170
  onKeyDown: (e) => {
172
- e.key === "Enter" && (e.preventDefault(), Y());
171
+ e.key === "Enter" && (e.preventDefault(), J());
173
172
  },
174
173
  placeholder: "e.g. workspace:read",
175
174
  className: "flex-1 rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
176
- }), /* @__PURE__ */ b("button", {
175
+ }), /* @__PURE__ */ y("button", {
177
176
  type: "button",
178
- onClick: Y,
177
+ onClick: J,
179
178
  className: "rounded-md bg-action-primary-bg/10 p-2 text-primary hover:bg-action-primary-bg/20 transition-colors",
180
- children: /* @__PURE__ */ b(g, { size: 16 })
179
+ children: /* @__PURE__ */ y(h, { size: 16 })
181
180
  })]
182
- }), N.length > 0 && /* @__PURE__ */ b("div", {
181
+ }), M.length > 0 && /* @__PURE__ */ y("div", {
183
182
  className: "flex flex-wrap gap-2",
184
- children: N.map((e) => /* @__PURE__ */ x("span", {
183
+ children: M.map((e) => /* @__PURE__ */ b("span", {
185
184
  className: "inline-flex items-center gap-1 rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary",
186
- children: [e, /* @__PURE__ */ b("button", {
185
+ children: [e, /* @__PURE__ */ y("button", {
187
186
  type: "button",
188
- onClick: () => X(e),
187
+ onClick: () => Y(e),
189
188
  className: "hover:text-status-error-text",
190
- children: /* @__PURE__ */ b(y, { size: 12 })
189
+ children: /* @__PURE__ */ y(v, { size: 12 })
191
190
  })]
192
191
  }, e))
193
192
  })]
194
193
  })
195
- }), /* @__PURE__ */ b(a, {
196
- title: E("devportal.redirectUris", "Redirect URIs"),
197
- children: /* @__PURE__ */ x("div", {
194
+ }), /* @__PURE__ */ y(a, {
195
+ title: T("devportal.redirectUris", "Redirect URIs"),
196
+ children: /* @__PURE__ */ b("div", {
198
197
  className: "space-y-3",
199
- children: [/* @__PURE__ */ x("div", {
198
+ children: [/* @__PURE__ */ b("div", {
200
199
  className: "flex items-center gap-2",
201
- children: [/* @__PURE__ */ b("input", {
200
+ children: [/* @__PURE__ */ y("input", {
202
201
  type: "url",
203
- value: z,
204
- onChange: (e) => B(e.target.value),
202
+ value: R,
203
+ onChange: (e) => z(e.target.value),
205
204
  onKeyDown: (e) => {
206
- e.key === "Enter" && (e.preventDefault(), Z());
205
+ e.key === "Enter" && (e.preventDefault(), X());
207
206
  },
208
207
  placeholder: "https://example.com/callback",
209
208
  className: "flex-1 rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
210
- }), /* @__PURE__ */ b("button", {
209
+ }), /* @__PURE__ */ y("button", {
211
210
  type: "button",
212
- onClick: Z,
211
+ onClick: X,
213
212
  className: "rounded-md bg-action-primary-bg/10 p-2 text-primary hover:bg-action-primary-bg/20 transition-colors",
214
- children: /* @__PURE__ */ b(g, { size: 16 })
213
+ children: /* @__PURE__ */ y(h, { size: 16 })
215
214
  })]
216
- }), L.length > 0 && /* @__PURE__ */ b("div", {
215
+ }), I.length > 0 && /* @__PURE__ */ y("div", {
217
216
  className: "space-y-2",
218
- children: L.map((e) => /* @__PURE__ */ x("div", {
217
+ children: I.map((e) => /* @__PURE__ */ b("div", {
219
218
  className: "flex items-center gap-2",
220
- children: [/* @__PURE__ */ b("code", {
219
+ children: [/* @__PURE__ */ y("code", {
221
220
  className: "flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono",
222
221
  children: e
223
- }), /* @__PURE__ */ b("button", {
222
+ }), /* @__PURE__ */ y("button", {
224
223
  type: "button",
225
- onClick: () => Q(e),
224
+ onClick: () => Z(e),
226
225
  className: "rounded p-1 text-text-secondary hover:text-status-error-text transition-colors",
227
- children: /* @__PURE__ */ b(v, { size: 14 })
226
+ children: /* @__PURE__ */ y(_, { size: 14 })
228
227
  })]
229
228
  }, e))
230
229
  })]
231
230
  })
232
231
  })]
233
232
  }),
234
- /* @__PURE__ */ x("div", {
233
+ /* @__PURE__ */ b("div", {
235
234
  className: "flex items-center gap-3 pt-4 border-t",
236
- children: [/* @__PURE__ */ x("button", {
235
+ children: [/* @__PURE__ */ b("button", {
237
236
  type: "submit",
238
- disabled: K || !D.trim(),
237
+ disabled: G || !E.trim(),
239
238
  className: t("inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors", "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90", "disabled:opacity-50 disabled:cursor-not-allowed"),
240
- children: [/* @__PURE__ */ b(_, { size: 16 }), K ? E("devportal.creating", "Creating...") : E("devportal.createOAuthApp", "Create OAuth App")]
241
- }), /* @__PURE__ */ x("button", {
239
+ children: [/* @__PURE__ */ y(g, { size: 16 }), G ? T("devportal.creating", "Creating...") : T("devportal.createOAuthApp", "Create OAuth App")]
240
+ }), /* @__PURE__ */ b("button", {
242
241
  type: "button",
243
- onClick: () => J("/oauth"),
242
+ onClick: () => q("/oauth"),
244
243
  className: "inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-bg-sunken transition-colors",
245
- children: [/* @__PURE__ */ b(y, { size: 16 }), E("devportal.cancel", "Cancel")]
244
+ children: [/* @__PURE__ */ y(v, { size: 16 }), T("devportal.cancel", "Cancel")]
246
245
  })]
247
246
  })
248
247
  ]
@@ -251,6 +250,6 @@ var C = () => {
251
250
  });
252
251
  };
253
252
  //#endregion
254
- export { C as CreateOAuthClientPage };
253
+ export { S as CreateOAuthClientPage };
255
254
 
256
255
  //# sourceMappingURL=CreateOAuthClientPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateOAuthClientPage.js","names":[],"sources":["../../../src/devportal/pages/CreateOAuthClientPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport { Save, X, Plus, Trash2 } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { OptionalFields } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n SelectField,\n TextareaField,\n} from \"../components/FormField\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\nimport { useCreateAuthAppMutation, getErrorMessage } from \"../hooks\";\n\n/**\n * Create OAuth App page\n *\n * Creates a new App in auth-svc (replaces devportal-svc CreateOAuthClient).\n * Shows the client secret once after creation.\n */\nexport const CreateOAuthClientPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const [name, setName] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [type, setType] = useState<string>(\"CONFIDENTIAL\");\n const [scopes, setScopes] = useState<string[]>([]);\n const [newScope, setNewScope] = useState(\"\");\n const [redirectUris, setRedirectUris] = useState<string[]>([]);\n const [newUri, setNewUri] = useState(\"\");\n\n const [createdSecret, setCreatedSecret] = useState<string | null>(null);\n const [createdAppId, setCreatedAppId] = useState<string | null>(null);\n\n const [createApp, { loading, error }] = useCreateAuthAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleAddScope = () => {\n const trimmed = newScope.trim();\n if (trimmed && !scopes.includes(trimmed)) {\n setScopes([...scopes, trimmed]);\n setNewScope(\"\");\n }\n };\n\n const handleRemoveScope = (scope: string) => {\n setScopes(scopes.filter((s) => s !== scope));\n };\n\n const handleAddUri = () => {\n const trimmed = newUri.trim();\n if (trimmed && !redirectUris.includes(trimmed)) {\n setRedirectUris([...redirectUris, trimmed]);\n setNewUri(\"\");\n }\n };\n\n const handleRemoveUri = (uri: string) => {\n setRedirectUris(redirectUris.filter((u) => u !== uri));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!name.trim()) return;\n\n try {\n const result = await createApp({\n variables: {\n input: {\n name: name.trim(),\n description: description.trim() || undefined,\n type,\n scopes,\n redirectUris,\n },\n },\n });\n\n const secret = result.data?.createApp?.clientSecret;\n const appId = result.data?.createApp?.app?.id;\n if (secret) {\n setCreatedSecret(secret);\n setCreatedAppId(appId || null);\n }\n } catch {\n // error handled by Apollo\n }\n };\n\n // Success — show the secret\n if (createdSecret) {\n return (\n <PageLayout\n title={tr(\"devportal.appCreated\", \"App Created!\")}\n description={tr(\n \"devportal.appCreatedDescription\",\n \"Save the client secret below. It will not be shown again.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToOAuthApps\", \"Back to OAuth Apps\")}\n >\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-6\">\n <h3 className=\"font-medium text-status-success-text\">\n {tr(\"devportal.oauthAppCreated\", \"Your OAuth App has been created\")}\n </h3>\n <div className=\"mt-4 space-y-3\">\n <div>\n <label className=\"text-xs font-medium text-status-success-text\">\n {tr(\"devportal.clientSecret\", \"Client Secret\")}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded border bg-bg-surface px-3 py-2 text-sm font-mono break-all\">\n {createdSecret}\n </code>\n <button\n onClick={async () => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(createdSecret);\n void nativeNotify(ok ? \"success\" : \"error\");\n }}\n className=\"rounded bg-status-success-bg-subtle px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle transition-colors\"\n >\n {tr(\"devportal.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n <p className=\"text-sm text-status-success-text\">\n {tr(\n \"devportal.storeSecretSecurely\",\n \"Store this secret securely. You will not be able to see it again.\",\n )}\n </p>\n </div>\n <div className=\"mt-6 flex gap-3\">\n {createdAppId && (\n <button\n onClick={() => handleNavigate(`/oauth/${createdAppId}`)}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n {tr(\"devportal.viewAppDetails\", \"View App Details\")}\n </button>\n )}\n <button\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"devportal.backToOAuthApps\", \"Back to OAuth Apps\")}\n </button>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_CREATE}>\n <PageLayout\n title={tr(\"devportal.createOAuthApp\", \"Create OAuth App\")}\n description={tr(\n \"devportal.createOAuthAppDescription\",\n \"Register a new OAuth application for authentication\",\n )}\n purpose={tr(\n \"devportal.createOAuthAppPurpose\",\n \"Register an OAuth app so an external service can let users sign in with their account and call the API on their behalf. Set its redirect URIs and request only the scopes it needs — you will receive a client ID and secret to finish the integration.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToOAuthApps\", \"Back to OAuth Apps\")}\n >\n <form onSubmit={handleSubmit} className=\"space-y-6 max-w-2xl\">\n {error && (\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-4\">\n <p className=\"text-sm text-status-error-text\">\n {getErrorMessage(error)}\n </p>\n </div>\n )}\n\n <PageSection\n title={tr(\"devportal.basicInformation\", \"Basic Information\")}\n >\n <InputField\n label={tr(\"devportal.appName\", \"App Name\")}\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={tr(\n \"devportal.myOAuthAppPlaceholder\",\n \"My OAuth App\",\n )}\n required\n />\n <TextareaField\n label={tr(\"devportal.description\", \"Description\")}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={tr(\n \"devportal.appDescriptionPlaceholder\",\n \"Brief description of what this app does...\",\n )}\n />\n <SelectField\n label={tr(\"devportal.appType\", \"App Type\")}\n value={type}\n onChange={(e) => setType(e.target.value)}\n options={[\n {\n value: \"SERVICE\",\n label: tr(\"devportal.appTypeService\", \"Service (M2M)\"),\n },\n {\n value: \"INTEGRATION\",\n label: tr(\"devportal.appTypeIntegration\", \"Integration\"),\n },\n { value: \"BOT\", label: tr(\"devportal.appTypeBot\", \"Bot\") },\n {\n value: \"WEB_APP\",\n label: tr(\"devportal.appTypeWebApp\", \"Web App\"),\n },\n {\n value: \"AUTOMATION\",\n label: tr(\"devportal.appTypeAutomation\", \"Automation\"),\n },\n ]}\n />\n </PageSection>\n\n {/* Advanced: grant types / PKCE-required toggles / scope tuning / redirect URIs — collapse the long-tail knobs */}\n <OptionalFields\n title={tr(\"devportal.advancedOAuthSettings\", \"Advanced settings\")}\n description={tr(\n \"devportal.advancedOAuthSettingsDescription\",\n \"Advanced grant types, PKCE-required toggles, scope tuning, and redirect URIs.\",\n )}\n >\n <PageSection title={tr(\"devportal.scopes\", \"Scopes\")}>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"text\"\n value={newScope}\n onChange={(e) => setNewScope(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleAddScope();\n }\n }}\n placeholder=\"e.g. workspace:read\"\n className=\"flex-1 rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n <button\n type=\"button\"\n onClick={handleAddScope}\n className=\"rounded-md bg-action-primary-bg/10 p-2 text-primary hover:bg-action-primary-bg/20 transition-colors\"\n >\n <Plus size={16} />\n </button>\n </div>\n {scopes.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {scopes.map((scope) => (\n <span\n key={scope}\n className=\"inline-flex items-center gap-1 rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {scope}\n <button\n type=\"button\"\n onClick={() => handleRemoveScope(scope)}\n className=\"hover:text-status-error-text\"\n >\n <X size={12} />\n </button>\n </span>\n ))}\n </div>\n )}\n </div>\n </PageSection>\n\n <PageSection title={tr(\"devportal.redirectUris\", \"Redirect URIs\")}>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"url\"\n value={newUri}\n onChange={(e) => setNewUri(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleAddUri();\n }\n }}\n placeholder=\"https://example.com/callback\"\n className=\"flex-1 rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n <button\n type=\"button\"\n onClick={handleAddUri}\n className=\"rounded-md bg-action-primary-bg/10 p-2 text-primary hover:bg-action-primary-bg/20 transition-colors\"\n >\n <Plus size={16} />\n </button>\n </div>\n {redirectUris.length > 0 && (\n <div className=\"space-y-2\">\n {redirectUris.map((uri) => (\n <div key={uri} className=\"flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {uri}\n </code>\n <button\n type=\"button\"\n onClick={() => handleRemoveUri(uri)}\n className=\"rounded p-1 text-text-secondary hover:text-status-error-text transition-colors\"\n >\n <Trash2 size={14} />\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n </PageSection>\n </OptionalFields>\n\n {/* Actions */}\n <div className=\"flex items-center gap-3 pt-4 border-t\">\n <button\n type=\"submit\"\n disabled={loading || !name.trim()}\n className={cn(\n \"inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors\",\n \"bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90\",\n \"disabled:opacity-50 disabled:cursor-not-allowed\",\n )}\n >\n <Save size={16} />\n {loading\n ? tr(\"devportal.creating\", \"Creating...\")\n : tr(\"devportal.createOAuthApp\", \"Create OAuth App\")}\n </button>\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-bg-sunken transition-colors\"\n >\n <X size={16} />\n {tr(\"devportal.cancel\", \"Cancel\")}\n </button>\n </div>\n </form>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"CreateOAuthClientPage.js","names":[],"sources":["../../../src/devportal/pages/CreateOAuthClientPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport { Save, X, Plus, Trash2 } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { OptionalFields } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n SelectField,\n TextareaField,\n} from \"../components/FormField\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\nimport { useCreateAuthAppMutation, getErrorMessage } from \"../hooks\";\n\n/**\n * Create OAuth App page\n *\n * Creates a new App in auth-svc (replaces devportal-svc CreateOAuthClient).\n * Shows the client secret once after creation.\n */\nexport const CreateOAuthClientPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const [name, setName] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [type, setType] = useState<string>(\"CONFIDENTIAL\");\n const [scopes, setScopes] = useState<string[]>([]);\n const [newScope, setNewScope] = useState(\"\");\n const [redirectUris, setRedirectUris] = useState<string[]>([]);\n const [newUri, setNewUri] = useState(\"\");\n\n const [createdSecret, setCreatedSecret] = useState<string | null>(null);\n const [createdAppId, setCreatedAppId] = useState<string | null>(null);\n\n const [createApp, { loading, error }] = useCreateAuthAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleAddScope = () => {\n const trimmed = newScope.trim();\n if (trimmed && !scopes.includes(trimmed)) {\n setScopes([...scopes, trimmed]);\n setNewScope(\"\");\n }\n };\n\n const handleRemoveScope = (scope: string) => {\n setScopes(scopes.filter((s) => s !== scope));\n };\n\n const handleAddUri = () => {\n const trimmed = newUri.trim();\n if (trimmed && !redirectUris.includes(trimmed)) {\n setRedirectUris([...redirectUris, trimmed]);\n setNewUri(\"\");\n }\n };\n\n const handleRemoveUri = (uri: string) => {\n setRedirectUris(redirectUris.filter((u) => u !== uri));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!name.trim()) return;\n\n try {\n const result = await createApp({\n variables: {\n input: {\n name: name.trim(),\n description: description.trim() || undefined,\n type,\n scopes,\n redirectUris,\n },\n },\n });\n\n const secret = result.data?.createApp?.clientSecret;\n const appId = result.data?.createApp?.app?.id;\n if (secret) {\n setCreatedSecret(secret);\n setCreatedAppId(appId || null);\n }\n } catch {\n // error handled by Apollo\n }\n };\n\n // Success — show the secret\n if (createdSecret) {\n return (\n <PageLayout\n title={tr(\"devportal.appCreated\", \"App Created!\")}\n description={tr(\n \"devportal.appCreatedDescription\",\n \"Save the client secret below. It will not be shown again.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToOAuthApps\", \"Back to OAuth Apps\")}\n >\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-6\">\n <h3 className=\"font-medium text-status-success-text\">\n {tr(\"devportal.oauthAppCreated\", \"Your OAuth App has been created\")}\n </h3>\n <div className=\"mt-4 space-y-3\">\n <div>\n <label className=\"text-xs font-medium text-status-success-text\">\n {tr(\"devportal.clientSecret\", \"Client Secret\")}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded border bg-bg-surface px-3 py-2 text-sm font-mono break-all\">\n {createdSecret}\n </code>\n <button\n onClick={async () => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(createdSecret);\n void nativeNotify(ok ? \"success\" : \"error\");\n }}\n className=\"rounded bg-status-success-bg-subtle px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle transition-colors\"\n >\n {tr(\"devportal.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n <p className=\"text-sm text-status-success-text\">\n {tr(\n \"devportal.storeSecretSecurely\",\n \"Store this secret securely. You will not be able to see it again.\",\n )}\n </p>\n </div>\n <div className=\"mt-6 flex gap-3\">\n {createdAppId && (\n <button\n onClick={() => handleNavigate(`/oauth/${createdAppId}`)}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n {tr(\"devportal.viewAppDetails\", \"View App Details\")}\n </button>\n )}\n <button\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"devportal.backToOAuthApps\", \"Back to OAuth Apps\")}\n </button>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={tr(\"devportal.createOAuthApp\", \"Create OAuth App\")}\n description={tr(\n \"devportal.createOAuthAppDescription\",\n \"Register a new OAuth application for authentication\",\n )}\n purpose={tr(\n \"devportal.createOAuthAppPurpose\",\n \"Register an OAuth app so an external service can let users sign in with their account and call the API on their behalf. Set its redirect URIs and request only the scopes it needs — you will receive a client ID and secret to finish the integration.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToOAuthApps\", \"Back to OAuth Apps\")}\n >\n <form onSubmit={handleSubmit} className=\"space-y-6 max-w-2xl\">\n {error && (\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-4\">\n <p className=\"text-sm text-status-error-text\">\n {getErrorMessage(error)}\n </p>\n </div>\n )}\n\n <PageSection\n title={tr(\"devportal.basicInformation\", \"Basic Information\")}\n >\n <InputField\n label={tr(\"devportal.appName\", \"App Name\")}\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={tr(\n \"devportal.myOAuthAppPlaceholder\",\n \"My OAuth App\",\n )}\n required\n />\n <TextareaField\n label={tr(\"devportal.description\", \"Description\")}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={tr(\n \"devportal.appDescriptionPlaceholder\",\n \"Brief description of what this app does...\",\n )}\n />\n <SelectField\n label={tr(\"devportal.appType\", \"App Type\")}\n value={type}\n onChange={(e) => setType(e.target.value)}\n options={[\n {\n value: \"SERVICE\",\n label: tr(\"devportal.appTypeService\", \"Service (M2M)\"),\n },\n {\n value: \"INTEGRATION\",\n label: tr(\"devportal.appTypeIntegration\", \"Integration\"),\n },\n { value: \"BOT\", label: tr(\"devportal.appTypeBot\", \"Bot\") },\n {\n value: \"WEB_APP\",\n label: tr(\"devportal.appTypeWebApp\", \"Web App\"),\n },\n {\n value: \"AUTOMATION\",\n label: tr(\"devportal.appTypeAutomation\", \"Automation\"),\n },\n ]}\n />\n </PageSection>\n\n {/* Advanced: grant types / PKCE-required toggles / scope tuning / redirect URIs — collapse the long-tail knobs */}\n <OptionalFields\n title={tr(\"devportal.advancedOAuthSettings\", \"Advanced settings\")}\n description={tr(\n \"devportal.advancedOAuthSettingsDescription\",\n \"Advanced grant types, PKCE-required toggles, scope tuning, and redirect URIs.\",\n )}\n >\n <PageSection title={tr(\"devportal.scopes\", \"Scopes\")}>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"text\"\n value={newScope}\n onChange={(e) => setNewScope(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleAddScope();\n }\n }}\n placeholder=\"e.g. workspace:read\"\n className=\"flex-1 rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n <button\n type=\"button\"\n onClick={handleAddScope}\n className=\"rounded-md bg-action-primary-bg/10 p-2 text-primary hover:bg-action-primary-bg/20 transition-colors\"\n >\n <Plus size={16} />\n </button>\n </div>\n {scopes.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {scopes.map((scope) => (\n <span\n key={scope}\n className=\"inline-flex items-center gap-1 rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {scope}\n <button\n type=\"button\"\n onClick={() => handleRemoveScope(scope)}\n className=\"hover:text-status-error-text\"\n >\n <X size={12} />\n </button>\n </span>\n ))}\n </div>\n )}\n </div>\n </PageSection>\n\n <PageSection title={tr(\"devportal.redirectUris\", \"Redirect URIs\")}>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"url\"\n value={newUri}\n onChange={(e) => setNewUri(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleAddUri();\n }\n }}\n placeholder=\"https://example.com/callback\"\n className=\"flex-1 rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n <button\n type=\"button\"\n onClick={handleAddUri}\n className=\"rounded-md bg-action-primary-bg/10 p-2 text-primary hover:bg-action-primary-bg/20 transition-colors\"\n >\n <Plus size={16} />\n </button>\n </div>\n {redirectUris.length > 0 && (\n <div className=\"space-y-2\">\n {redirectUris.map((uri) => (\n <div key={uri} className=\"flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {uri}\n </code>\n <button\n type=\"button\"\n onClick={() => handleRemoveUri(uri)}\n className=\"rounded p-1 text-text-secondary hover:text-status-error-text transition-colors\"\n >\n <Trash2 size={14} />\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n </PageSection>\n </OptionalFields>\n\n {/* Actions */}\n <div className=\"flex items-center gap-3 pt-4 border-t\">\n <button\n type=\"submit\"\n disabled={loading || !name.trim()}\n className={cn(\n \"inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors\",\n \"bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90\",\n \"disabled:opacity-50 disabled:cursor-not-allowed\",\n )}\n >\n <Save size={16} />\n {loading\n ? tr(\"devportal.creating\", \"Creating...\")\n : tr(\"devportal.createOAuthApp\", \"Create OAuth App\")}\n </button>\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-bg-sunken transition-colors\"\n >\n <X size={16} />\n {tr(\"devportal.cancel\", \"Cancel\")}\n </button>\n </div>\n </form>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
@@ -81,7 +81,7 @@ var E = {
81
81
  return k.applicationId || (e.applicationId = H("devportal.createWebhook.errors.appRequired", "Select an application")), k.name.trim() || (e.name = H("devportal.createWebhook.errors.nameRequired", "Name is required")), k.url.trim() ? /^https:\/\//i.test(k.url) || (e.url = H("devportal.createWebhook.errors.urlHttps", "Endpoint URL must use HTTPS")) : e.url = H("devportal.createWebhook.errors.urlRequired", "Endpoint URL is required"), k.events.length === 0 && (e.events = H("devportal.createWebhook.errors.eventsRequired", "Select at least one event")), k.retryEnabled && (k.maxRetries < 1 || k.maxRetries > 10) && (e.maxRetries = H("devportal.createWebhook.errors.retriesRange", "Retry count must be between 1 and 10")), M(e), Object.keys(e).length === 0;
82
82
  };
83
83
  return /* @__PURE__ */ C(f, {
84
- permission: h.WEBHOOK_CREATE,
84
+ authOnly: !0,
85
85
  children: /* @__PURE__ */ C(o, {
86
86
  title: H("devportal.createWebhook.title", "Create Webhook"),
87
87
  description: H("devportal.createWebhook.description", "Set up a real webhook endpoint to receive platform events through the public gateway"),