@burdenoff/microfe-devportal 2026.624.26 → 2026.624.27
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.
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { useDevportal as e } from "../providers/DevportalProvider.js";
|
|
2
2
|
import { LoadingState as t } from "../components/LoadingState.js";
|
|
3
3
|
import { EmptyState as n } from "../components/EmptyState.js";
|
|
4
|
-
import { useDeactivateAppMutation as
|
|
4
|
+
import { useDeactivateAppMutation as r, useDeleteApplicationMutation as i, useGetApplicationQuery as ee, useUpdateApplicationMutation as te } from "../../generated/global-operations.js";
|
|
5
5
|
import { PageLayout as a, PageSection as o } from "../components/PageLayout.js";
|
|
6
6
|
import { APP_TYPE_LABELS as s } from "../utils/constants.js";
|
|
7
|
-
import { StatusBadge as
|
|
8
|
-
import { nativeImpact as
|
|
9
|
-
import { CheckboxField as
|
|
10
|
-
import { ConfirmDialog as
|
|
11
|
-
import { PermissionGuard as
|
|
7
|
+
import { StatusBadge as ne } from "../components/StatusBadge.js";
|
|
8
|
+
import { nativeImpact as re, nativeNotify as c } from "../../utils/nativeBridge.js";
|
|
9
|
+
import { CheckboxField as l, InputField as u, SelectField as d, TagInput as f, TextareaField as p } from "../components/FormField.js";
|
|
10
|
+
import { ConfirmDialog as m } from "../components/ConfirmDialog.js";
|
|
11
|
+
import { PermissionGuard as ie } from "../components/PermissionGuard.js";
|
|
12
12
|
import "../components/index.js";
|
|
13
|
-
import { DEVPORTAL_PERMISSIONS as
|
|
14
|
-
import { useDevportalPermission as
|
|
15
|
-
import { useEffect as
|
|
16
|
-
import { useI18n as
|
|
17
|
-
import { AlertCircle as
|
|
13
|
+
import { DEVPORTAL_PERMISSIONS as h } from "../constants/permissions.js";
|
|
14
|
+
import { useDevportalPermission as g } from "../hooks/usePermission.js";
|
|
15
|
+
import { useEffect as _, useState as v } from "react";
|
|
16
|
+
import { useI18n as y } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
17
|
+
import { AlertCircle as b, AlertTriangle as x, AppWindow as S, Archive as C, Power as w, Save as ae, Send as oe, Trash2 as se } from "lucide-react";
|
|
18
18
|
import { useParams as ce } from "react-router-dom";
|
|
19
|
-
import { Fragment as
|
|
19
|
+
import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
20
20
|
//#region src/devportal/pages/EditApplicationPage.tsx
|
|
21
21
|
var le = Object.entries(s).map(([e, t]) => ({
|
|
22
22
|
value: e,
|
|
@@ -109,21 +109,21 @@ function fe(e) {
|
|
|
109
109
|
updatedAt: e.updatedAt
|
|
110
110
|
} : null;
|
|
111
111
|
}
|
|
112
|
-
var
|
|
113
|
-
let { navigate: s, basePath:
|
|
114
|
-
let n =
|
|
112
|
+
var O = () => {
|
|
113
|
+
let { navigate: s, basePath: O } = e(), { appId: k } = ce(), { t: A } = y(), { allowed: j } = g(h.APP_UPDATE), { allowed: M } = g(h.APP_DELETE), N = (e, t) => {
|
|
114
|
+
let n = A(e);
|
|
115
115
|
return n === e ? t : n;
|
|
116
|
-
}, [
|
|
117
|
-
variables: { id:
|
|
118
|
-
skip: !
|
|
119
|
-
}), [
|
|
120
|
-
|
|
121
|
-
let e =
|
|
122
|
-
if (!
|
|
116
|
+
}, [P, F] = v(!1), [I, L] = v({}), [R, z] = v(!1), [B, V] = v(!1), [pe, H] = v(!1), [U, W] = v(!1), { data: G, loading: me, error: K } = ee({
|
|
117
|
+
variables: { id: k },
|
|
118
|
+
skip: !k
|
|
119
|
+
}), [q] = te(), [he] = i(), [ge] = r(), J = fe(G?.application);
|
|
120
|
+
_(() => {
|
|
121
|
+
let e = J?.name;
|
|
122
|
+
if (!k || !e) return;
|
|
123
123
|
let t = window.__breadcrumbRegistry;
|
|
124
|
-
return t?.register(
|
|
125
|
-
}, [
|
|
126
|
-
let [
|
|
124
|
+
return t?.register(k, e), () => t?.unregister(k);
|
|
125
|
+
}, [k, J?.name]);
|
|
126
|
+
let [Y, X] = v({
|
|
127
127
|
name: "",
|
|
128
128
|
slug: "",
|
|
129
129
|
shortDescription: "",
|
|
@@ -141,377 +141,372 @@ var k = () => {
|
|
|
141
141
|
githubUrl: "",
|
|
142
142
|
requiresApproval: !1
|
|
143
143
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
name:
|
|
147
|
-
slug:
|
|
148
|
-
shortDescription:
|
|
149
|
-
description:
|
|
150
|
-
appType:
|
|
151
|
-
visibility:
|
|
152
|
-
category:
|
|
153
|
-
tags:
|
|
154
|
-
keywords:
|
|
155
|
-
websiteUrl:
|
|
156
|
-
documentationUrl:
|
|
157
|
-
supportUrl:
|
|
158
|
-
privacyPolicyUrl:
|
|
159
|
-
termsOfServiceUrl:
|
|
160
|
-
githubUrl:
|
|
161
|
-
requiresApproval:
|
|
162
|
-
}),
|
|
163
|
-
}, [
|
|
164
|
-
let
|
|
165
|
-
s?.(`${
|
|
166
|
-
},
|
|
167
|
-
|
|
144
|
+
_(() => {
|
|
145
|
+
J && (X({
|
|
146
|
+
name: J.name,
|
|
147
|
+
slug: J.slug,
|
|
148
|
+
shortDescription: J.shortDescription || "",
|
|
149
|
+
description: J.description || "",
|
|
150
|
+
appType: J.appType,
|
|
151
|
+
visibility: J.visibility,
|
|
152
|
+
category: J.category || "",
|
|
153
|
+
tags: J.tags,
|
|
154
|
+
keywords: J.keywords,
|
|
155
|
+
websiteUrl: J.websiteUrl || "",
|
|
156
|
+
documentationUrl: J.documentationUrl || "",
|
|
157
|
+
supportUrl: J.supportUrl || "",
|
|
158
|
+
privacyPolicyUrl: J.privacyPolicyUrl || "",
|
|
159
|
+
termsOfServiceUrl: J.termsOfServiceUrl || "",
|
|
160
|
+
githubUrl: J.githubUrl || "",
|
|
161
|
+
requiresApproval: J.requiresApproval
|
|
162
|
+
}), W(!1));
|
|
163
|
+
}, [G?.application]);
|
|
164
|
+
let Z = (e) => {
|
|
165
|
+
s?.(`${O}${e}`);
|
|
166
|
+
}, Q = (e, t) => {
|
|
167
|
+
X((n) => ({
|
|
168
168
|
...n,
|
|
169
169
|
[e]: t
|
|
170
|
-
})),
|
|
170
|
+
})), W(!0), I[e] && L((t) => ({
|
|
171
171
|
...t,
|
|
172
172
|
[e]: void 0
|
|
173
173
|
}));
|
|
174
|
-
},
|
|
174
|
+
}, $ = () => {
|
|
175
175
|
let e = {};
|
|
176
|
-
return
|
|
177
|
-
},
|
|
178
|
-
if (e.preventDefault(), !(
|
|
179
|
-
|
|
176
|
+
return Y.name.trim() ? Y.name.length < 3 ? e.name = N("devportal.appNameMinLength", "Name must be at least 3 characters") : Y.name.length > 100 && (e.name = N("devportal.appNameMaxLength", "Name must be less than 100 characters")) : e.name = N("devportal.appNameRequired", "Application name is required"), Y.slug.trim() ? /^[a-z0-9-]+$/.test(Y.slug) || (e.slug = N("devportal.slugInvalidChars", "Slug can only contain lowercase letters, numbers, and hyphens")) : e.slug = N("devportal.slugRequired", "Slug is required"), Y.shortDescription.trim() ? Y.shortDescription.length > 200 && (e.shortDescription = N("devportal.shortDescriptionMaxLength", "Short description must be less than 200 characters")) : e.shortDescription = N("devportal.shortDescriptionRequired", "Short description is required"), Y.appType || (e.appType = N("devportal.appTypeRequired", "Application type is required")), Y.category || (e.category = N("devportal.categoryRequired", "Category is required")), L(e), Object.keys(e).length === 0;
|
|
177
|
+
}, _e = async (e) => {
|
|
178
|
+
if (e.preventDefault(), !(!$() || !J)) {
|
|
179
|
+
F(!0);
|
|
180
180
|
try {
|
|
181
|
-
await
|
|
182
|
-
id:
|
|
181
|
+
await q({ variables: {
|
|
182
|
+
id: J.id,
|
|
183
183
|
input: {
|
|
184
|
-
name:
|
|
185
|
-
shortDescription:
|
|
186
|
-
description:
|
|
187
|
-
appType:
|
|
188
|
-
visibility:
|
|
189
|
-
category:
|
|
190
|
-
tags:
|
|
191
|
-
keywords:
|
|
192
|
-
websiteUrl:
|
|
193
|
-
documentationUrl:
|
|
194
|
-
supportUrl:
|
|
195
|
-
privacyPolicyUrl:
|
|
196
|
-
termsOfServiceUrl:
|
|
197
|
-
githubUrl:
|
|
184
|
+
name: Y.name,
|
|
185
|
+
shortDescription: Y.shortDescription,
|
|
186
|
+
description: Y.description,
|
|
187
|
+
appType: Y.appType,
|
|
188
|
+
visibility: Y.visibility,
|
|
189
|
+
category: Y.category,
|
|
190
|
+
tags: Y.tags,
|
|
191
|
+
keywords: Y.keywords,
|
|
192
|
+
websiteUrl: Y.websiteUrl || null,
|
|
193
|
+
documentationUrl: Y.documentationUrl || null,
|
|
194
|
+
supportUrl: Y.supportUrl || null,
|
|
195
|
+
privacyPolicyUrl: Y.privacyPolicyUrl || null,
|
|
196
|
+
termsOfServiceUrl: Y.termsOfServiceUrl || null,
|
|
197
|
+
githubUrl: Y.githubUrl || null
|
|
198
198
|
}
|
|
199
|
-
} }),
|
|
199
|
+
} }), W(!1);
|
|
200
200
|
} catch (e) {
|
|
201
201
|
console.error("Failed to update application:", e);
|
|
202
202
|
} finally {
|
|
203
|
-
|
|
203
|
+
F(!1);
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
|
-
},
|
|
207
|
-
if (
|
|
208
|
-
|
|
206
|
+
}, ve = async () => {
|
|
207
|
+
if (J) {
|
|
208
|
+
re("medium");
|
|
209
209
|
try {
|
|
210
|
-
await he({ variables: { id:
|
|
210
|
+
await he({ variables: { id: J.id } }), c("success"), Z("/apps");
|
|
211
211
|
} catch (e) {
|
|
212
|
-
|
|
212
|
+
c("error"), console.error("Failed to delete application:", e);
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
-
},
|
|
216
|
-
if (
|
|
217
|
-
await
|
|
218
|
-
id:
|
|
215
|
+
}, ye = async () => {
|
|
216
|
+
if (J) try {
|
|
217
|
+
await q({ variables: {
|
|
218
|
+
id: J.id,
|
|
219
219
|
input: { visibility: "PRIVATE" }
|
|
220
|
-
} }),
|
|
220
|
+
} }), V(!1);
|
|
221
221
|
} catch (e) {
|
|
222
222
|
console.error("Failed to deprecate application:", e);
|
|
223
223
|
}
|
|
224
|
-
},
|
|
225
|
-
if (
|
|
226
|
-
await
|
|
224
|
+
}, be = async () => {
|
|
225
|
+
if (J) try {
|
|
226
|
+
await ge({ variables: { id: J.id } }), H(!1), Z("/apps");
|
|
227
227
|
} catch (e) {
|
|
228
228
|
console.error("Failed to deactivate application:", e);
|
|
229
229
|
}
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
I(!0), await ge({ variables: { id: Y.id } });
|
|
233
|
-
} catch (e) {
|
|
234
|
-
console.error("Failed to submit for review:", e);
|
|
235
|
-
} finally {
|
|
236
|
-
I(!1);
|
|
237
|
-
}
|
|
230
|
+
}, xe = () => {
|
|
231
|
+
J && s?.(`${O}/apps/${J.id}/publish`);
|
|
238
232
|
};
|
|
239
|
-
if (me) return /* @__PURE__ */
|
|
240
|
-
if (
|
|
241
|
-
title:
|
|
242
|
-
backLink: `${
|
|
243
|
-
backLabel:
|
|
244
|
-
children: /* @__PURE__ */
|
|
233
|
+
if (me) return /* @__PURE__ */ E(t, { message: N("devportal.loadingApplication", "Loading application...") });
|
|
234
|
+
if (K) return /* @__PURE__ */ E(a, {
|
|
235
|
+
title: N("devportal.error", "Error"),
|
|
236
|
+
backLink: `${O}/apps`,
|
|
237
|
+
backLabel: N("devportal.backToApplications", "Back to Applications"),
|
|
238
|
+
children: /* @__PURE__ */ D("div", {
|
|
245
239
|
className: "flex flex-col items-center justify-center py-12 text-center",
|
|
246
240
|
children: [
|
|
247
|
-
/* @__PURE__ */
|
|
241
|
+
/* @__PURE__ */ E(b, {
|
|
248
242
|
size: 48,
|
|
249
243
|
className: "text-destructive mb-4"
|
|
250
244
|
}),
|
|
251
|
-
/* @__PURE__ */
|
|
245
|
+
/* @__PURE__ */ E("h3", {
|
|
252
246
|
className: "text-lg font-semibold mb-2",
|
|
253
|
-
children:
|
|
247
|
+
children: N("devportal.failedToLoadApplication", "Failed to load application")
|
|
254
248
|
}),
|
|
255
|
-
/* @__PURE__ */
|
|
249
|
+
/* @__PURE__ */ E("p", {
|
|
256
250
|
className: "text-sm text-muted-foreground",
|
|
257
|
-
children:
|
|
251
|
+
children: K.message
|
|
258
252
|
})
|
|
259
253
|
]
|
|
260
254
|
})
|
|
261
255
|
});
|
|
262
|
-
if (!
|
|
263
|
-
title:
|
|
264
|
-
backLink: `${
|
|
265
|
-
backLabel:
|
|
266
|
-
children: /* @__PURE__ */
|
|
267
|
-
icon: /* @__PURE__ */
|
|
268
|
-
title:
|
|
269
|
-
description:
|
|
256
|
+
if (!J) return /* @__PURE__ */ E(a, {
|
|
257
|
+
title: N("devportal.notFound", "Not Found"),
|
|
258
|
+
backLink: `${O}/apps`,
|
|
259
|
+
backLabel: N("devportal.backToApplications", "Back to Applications"),
|
|
260
|
+
children: /* @__PURE__ */ E(n, {
|
|
261
|
+
icon: /* @__PURE__ */ E(S, { size: 48 }),
|
|
262
|
+
title: N("devportal.applicationNotFound", "Application not found"),
|
|
263
|
+
description: N("devportal.applicationNotFoundDescription", "The application you're looking for doesn't exist or you don't have access to it.")
|
|
270
264
|
})
|
|
271
265
|
});
|
|
272
|
-
let
|
|
273
|
-
return /* @__PURE__ */
|
|
274
|
-
permission:
|
|
275
|
-
children: /* @__PURE__ */
|
|
276
|
-
title: `${
|
|
277
|
-
description:
|
|
278
|
-
backLink: `${
|
|
279
|
-
backLabel:
|
|
280
|
-
actions: /* @__PURE__ */
|
|
266
|
+
let Se = J.status === "DRAFT" || J.status === "REJECTED", Ce = J.status === "PUBLISHED", we = J.status === "ACTIVE" || J.status === "PUBLISHED";
|
|
267
|
+
return /* @__PURE__ */ E(ie, {
|
|
268
|
+
permission: h.APP_UPDATE,
|
|
269
|
+
children: /* @__PURE__ */ D(a, {
|
|
270
|
+
title: `${N("devportal.editAppTitlePrefix", "Edit:")} ${J.name}`,
|
|
271
|
+
description: N("devportal.editAppDescription", "Update your application settings"),
|
|
272
|
+
backLink: `${O}/apps/${J.id}`,
|
|
273
|
+
backLabel: N("devportal.backToApplication", "Back to Application"),
|
|
274
|
+
actions: /* @__PURE__ */ E("div", {
|
|
281
275
|
className: "flex items-center gap-2",
|
|
282
|
-
children: /* @__PURE__ */
|
|
283
|
-
status:
|
|
276
|
+
children: /* @__PURE__ */ E(ne, {
|
|
277
|
+
status: J.status,
|
|
284
278
|
type: "app"
|
|
285
279
|
})
|
|
286
280
|
}),
|
|
287
281
|
children: [
|
|
288
|
-
/* @__PURE__ */
|
|
289
|
-
onSubmit:
|
|
282
|
+
/* @__PURE__ */ D("form", {
|
|
283
|
+
onSubmit: _e,
|
|
290
284
|
className: "space-y-8 max-w-3xl",
|
|
291
285
|
children: [
|
|
292
|
-
|
|
286
|
+
J.status === "PUBLISHED" && /* @__PURE__ */ D("div", {
|
|
293
287
|
className: "rounded-lg border border-border-subtle bg-status-warning-bg-subtle p-4 flex gap-3",
|
|
294
|
-
children: [/* @__PURE__ */
|
|
288
|
+
children: [/* @__PURE__ */ E(x, {
|
|
295
289
|
size: 20,
|
|
296
290
|
className: "text-status-warning-text flex-shrink-0 mt-0.5"
|
|
297
|
-
}), /* @__PURE__ */
|
|
291
|
+
}), /* @__PURE__ */ D("div", {
|
|
298
292
|
className: "text-sm text-status-warning-text",
|
|
299
|
-
children: [/* @__PURE__ */
|
|
293
|
+
children: [/* @__PURE__ */ E("p", {
|
|
300
294
|
className: "font-medium",
|
|
301
|
-
children:
|
|
302
|
-
}), /* @__PURE__ */
|
|
295
|
+
children: N("devportal.appIsPublished", "This application is published")
|
|
296
|
+
}), /* @__PURE__ */ E("p", {
|
|
303
297
|
className: "mt-1 text-status-warning-text",
|
|
304
|
-
children:
|
|
298
|
+
children: N("devportal.publishedAppChangesWarning", "Changes to published apps may require re-review. Major changes will put the app back into review status.")
|
|
305
299
|
})]
|
|
306
300
|
})]
|
|
307
301
|
}),
|
|
308
|
-
/* @__PURE__ */
|
|
309
|
-
title:
|
|
310
|
-
description:
|
|
311
|
-
children: /* @__PURE__ */
|
|
302
|
+
/* @__PURE__ */ E(o, {
|
|
303
|
+
title: N("devportal.basicInformation", "Basic Information"),
|
|
304
|
+
description: N("devportal.basicInformationDescription", "Core details about your application"),
|
|
305
|
+
children: /* @__PURE__ */ D("div", {
|
|
312
306
|
className: "space-y-4",
|
|
313
307
|
children: [
|
|
314
|
-
/* @__PURE__ */
|
|
315
|
-
label:
|
|
316
|
-
value:
|
|
317
|
-
onChange: (e) =>
|
|
318
|
-
placeholder:
|
|
308
|
+
/* @__PURE__ */ E(u, {
|
|
309
|
+
label: N("devportal.applicationName", "Application Name"),
|
|
310
|
+
value: Y.name,
|
|
311
|
+
onChange: (e) => Q("name", e.target.value),
|
|
312
|
+
placeholder: N("devportal.applicationNamePlaceholder", "My Awesome App"),
|
|
319
313
|
required: !0,
|
|
320
|
-
error:
|
|
314
|
+
error: I.name
|
|
321
315
|
}),
|
|
322
|
-
/* @__PURE__ */
|
|
323
|
-
label:
|
|
324
|
-
value:
|
|
325
|
-
onChange: (e) =>
|
|
326
|
-
placeholder:
|
|
316
|
+
/* @__PURE__ */ E(u, {
|
|
317
|
+
label: N("devportal.slug", "Slug"),
|
|
318
|
+
value: Y.slug,
|
|
319
|
+
onChange: (e) => Q("slug", e.target.value.toLowerCase()),
|
|
320
|
+
placeholder: N("devportal.slugPlaceholder", "my-awesome-app"),
|
|
327
321
|
required: !0,
|
|
328
|
-
error:
|
|
329
|
-
hint:
|
|
322
|
+
error: I.slug,
|
|
323
|
+
hint: N("devportal.slugChangeWarning", "Changing the slug may break existing integrations")
|
|
330
324
|
}),
|
|
331
|
-
/* @__PURE__ */
|
|
332
|
-
label:
|
|
333
|
-
value:
|
|
334
|
-
onChange: (e) =>
|
|
335
|
-
placeholder:
|
|
325
|
+
/* @__PURE__ */ E(p, {
|
|
326
|
+
label: N("devportal.shortDescription", "Short Description"),
|
|
327
|
+
value: Y.shortDescription,
|
|
328
|
+
onChange: (e) => Q("shortDescription", e.target.value),
|
|
329
|
+
placeholder: N("devportal.shortDescriptionPlaceholder", "A brief description of what your app does"),
|
|
336
330
|
required: !0,
|
|
337
|
-
error:
|
|
338
|
-
hint: `${
|
|
331
|
+
error: I.shortDescription,
|
|
332
|
+
hint: `${Y.shortDescription.length}/200 ${N("devportal.characters", "characters")}`,
|
|
339
333
|
rows: 2
|
|
340
334
|
}),
|
|
341
|
-
/* @__PURE__ */
|
|
342
|
-
label:
|
|
343
|
-
value:
|
|
344
|
-
onChange: (e) =>
|
|
345
|
-
placeholder:
|
|
335
|
+
/* @__PURE__ */ E(p, {
|
|
336
|
+
label: N("devportal.fullDescription", "Full Description"),
|
|
337
|
+
value: Y.description,
|
|
338
|
+
onChange: (e) => Q("description", e.target.value),
|
|
339
|
+
placeholder: N("devportal.fullDescriptionPlaceholder", "Detailed description of your application, features, and use cases..."),
|
|
346
340
|
rows: 6,
|
|
347
|
-
hint:
|
|
341
|
+
hint: N("devportal.markdownSupported", "Markdown formatting is supported")
|
|
348
342
|
})
|
|
349
343
|
]
|
|
350
344
|
})
|
|
351
345
|
}),
|
|
352
|
-
/* @__PURE__ */
|
|
353
|
-
title:
|
|
354
|
-
description:
|
|
346
|
+
/* @__PURE__ */ D(o, {
|
|
347
|
+
title: N("devportal.classification", "Classification"),
|
|
348
|
+
description: N("devportal.classificationDescription", "Categorize your application"),
|
|
355
349
|
children: [
|
|
356
|
-
/* @__PURE__ */
|
|
350
|
+
/* @__PURE__ */ D("div", {
|
|
357
351
|
className: "grid gap-4 sm:grid-cols-2",
|
|
358
352
|
children: [
|
|
359
|
-
/* @__PURE__ */
|
|
360
|
-
label:
|
|
361
|
-
value:
|
|
362
|
-
onChange: (e) =>
|
|
353
|
+
/* @__PURE__ */ E(d, {
|
|
354
|
+
label: N("devportal.applicationType", "Application Type"),
|
|
355
|
+
value: Y.appType,
|
|
356
|
+
onChange: (e) => Q("appType", e.target.value),
|
|
363
357
|
options: le,
|
|
364
358
|
required: !0,
|
|
365
|
-
error:
|
|
359
|
+
error: I.appType
|
|
366
360
|
}),
|
|
367
|
-
/* @__PURE__ */
|
|
368
|
-
label:
|
|
369
|
-
value:
|
|
370
|
-
onChange: (e) =>
|
|
361
|
+
/* @__PURE__ */ E(d, {
|
|
362
|
+
label: N("devportal.category", "Category"),
|
|
363
|
+
value: Y.category,
|
|
364
|
+
onChange: (e) => Q("category", e.target.value),
|
|
371
365
|
options: de,
|
|
372
366
|
required: !0,
|
|
373
|
-
error:
|
|
367
|
+
error: I.category
|
|
374
368
|
}),
|
|
375
|
-
/* @__PURE__ */
|
|
376
|
-
label:
|
|
377
|
-
value:
|
|
378
|
-
onChange: (e) =>
|
|
369
|
+
/* @__PURE__ */ E(d, {
|
|
370
|
+
label: N("devportal.visibility", "Visibility"),
|
|
371
|
+
value: Y.visibility,
|
|
372
|
+
onChange: (e) => Q("visibility", e.target.value),
|
|
379
373
|
options: ue,
|
|
380
|
-
hint:
|
|
374
|
+
hint: N("devportal.visibilityHint", "Controls who can see this app once published. Public apps still require admin review and approval before appearing in the store.")
|
|
381
375
|
})
|
|
382
376
|
]
|
|
383
377
|
}),
|
|
384
|
-
/* @__PURE__ */
|
|
385
|
-
label:
|
|
386
|
-
value:
|
|
387
|
-
onChange: (e) =>
|
|
388
|
-
placeholder:
|
|
378
|
+
/* @__PURE__ */ E(f, {
|
|
379
|
+
label: N("devportal.tags", "Tags"),
|
|
380
|
+
value: Y.tags,
|
|
381
|
+
onChange: (e) => Q("tags", e),
|
|
382
|
+
placeholder: N("devportal.addTagsPlaceholder", "Add tags (press Enter)")
|
|
389
383
|
}),
|
|
390
|
-
/* @__PURE__ */
|
|
391
|
-
label:
|
|
392
|
-
value:
|
|
393
|
-
onChange: (e) =>
|
|
394
|
-
placeholder:
|
|
384
|
+
/* @__PURE__ */ E(f, {
|
|
385
|
+
label: N("devportal.keywords", "Keywords"),
|
|
386
|
+
value: Y.keywords,
|
|
387
|
+
onChange: (e) => Q("keywords", e),
|
|
388
|
+
placeholder: N("devportal.addKeywordsPlaceholder", "Add keywords (press Enter)")
|
|
395
389
|
})
|
|
396
390
|
]
|
|
397
391
|
}),
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
title:
|
|
400
|
-
description:
|
|
401
|
-
children: /* @__PURE__ */
|
|
392
|
+
/* @__PURE__ */ E(o, {
|
|
393
|
+
title: N("devportal.links", "Links"),
|
|
394
|
+
description: N("devportal.linksDescription", "External resources for your application"),
|
|
395
|
+
children: /* @__PURE__ */ D("div", {
|
|
402
396
|
className: "grid gap-4 sm:grid-cols-2",
|
|
403
397
|
children: [
|
|
404
|
-
/* @__PURE__ */
|
|
405
|
-
label:
|
|
398
|
+
/* @__PURE__ */ E(u, {
|
|
399
|
+
label: N("devportal.websiteUrl", "Website URL"),
|
|
406
400
|
type: "url",
|
|
407
|
-
value:
|
|
408
|
-
onChange: (e) =>
|
|
409
|
-
placeholder:
|
|
401
|
+
value: Y.websiteUrl,
|
|
402
|
+
onChange: (e) => Q("websiteUrl", e.target.value),
|
|
403
|
+
placeholder: N("devportal.websiteUrlPlaceholder", "https://example.com")
|
|
410
404
|
}),
|
|
411
|
-
/* @__PURE__ */
|
|
412
|
-
label:
|
|
405
|
+
/* @__PURE__ */ E(u, {
|
|
406
|
+
label: N("devportal.documentationUrl", "Documentation URL"),
|
|
413
407
|
type: "url",
|
|
414
|
-
value:
|
|
415
|
-
onChange: (e) =>
|
|
416
|
-
placeholder:
|
|
408
|
+
value: Y.documentationUrl,
|
|
409
|
+
onChange: (e) => Q("documentationUrl", e.target.value),
|
|
410
|
+
placeholder: N("devportal.documentationUrlPlaceholder", "https://docs.example.com")
|
|
417
411
|
}),
|
|
418
|
-
/* @__PURE__ */
|
|
419
|
-
label:
|
|
412
|
+
/* @__PURE__ */ E(u, {
|
|
413
|
+
label: N("devportal.supportUrl", "Support URL"),
|
|
420
414
|
type: "url",
|
|
421
|
-
value:
|
|
422
|
-
onChange: (e) =>
|
|
423
|
-
placeholder:
|
|
415
|
+
value: Y.supportUrl,
|
|
416
|
+
onChange: (e) => Q("supportUrl", e.target.value),
|
|
417
|
+
placeholder: N("devportal.supportUrlPlaceholder", "https://support.example.com")
|
|
424
418
|
}),
|
|
425
|
-
/* @__PURE__ */
|
|
426
|
-
label:
|
|
419
|
+
/* @__PURE__ */ E(u, {
|
|
420
|
+
label: N("devportal.githubUrl", "GitHub URL"),
|
|
427
421
|
type: "url",
|
|
428
|
-
value:
|
|
429
|
-
onChange: (e) =>
|
|
430
|
-
placeholder:
|
|
422
|
+
value: Y.githubUrl,
|
|
423
|
+
onChange: (e) => Q("githubUrl", e.target.value),
|
|
424
|
+
placeholder: N("devportal.githubUrlPlaceholder", "https://github.com/org/repo")
|
|
431
425
|
}),
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
label:
|
|
426
|
+
/* @__PURE__ */ E(u, {
|
|
427
|
+
label: N("devportal.privacyPolicyUrl", "Privacy Policy URL"),
|
|
434
428
|
type: "url",
|
|
435
|
-
value:
|
|
436
|
-
onChange: (e) =>
|
|
437
|
-
placeholder:
|
|
429
|
+
value: Y.privacyPolicyUrl,
|
|
430
|
+
onChange: (e) => Q("privacyPolicyUrl", e.target.value),
|
|
431
|
+
placeholder: N("devportal.privacyPolicyUrlPlaceholder", "https://example.com/privacy")
|
|
438
432
|
}),
|
|
439
|
-
/* @__PURE__ */
|
|
440
|
-
label:
|
|
433
|
+
/* @__PURE__ */ E(u, {
|
|
434
|
+
label: N("devportal.termsOfServiceUrl", "Terms of Service URL"),
|
|
441
435
|
type: "url",
|
|
442
|
-
value:
|
|
443
|
-
onChange: (e) =>
|
|
444
|
-
placeholder:
|
|
436
|
+
value: Y.termsOfServiceUrl,
|
|
437
|
+
onChange: (e) => Q("termsOfServiceUrl", e.target.value),
|
|
438
|
+
placeholder: N("devportal.termsOfServiceUrlPlaceholder", "https://example.com/terms")
|
|
445
439
|
})
|
|
446
440
|
]
|
|
447
441
|
})
|
|
448
442
|
}),
|
|
449
|
-
/* @__PURE__ */
|
|
450
|
-
title:
|
|
451
|
-
description:
|
|
452
|
-
children: /* @__PURE__ */
|
|
443
|
+
/* @__PURE__ */ E(o, {
|
|
444
|
+
title: N("devportal.settings", "Settings"),
|
|
445
|
+
description: N("devportal.settingsDescription", "Additional configuration options"),
|
|
446
|
+
children: /* @__PURE__ */ E("div", {
|
|
453
447
|
className: "space-y-4",
|
|
454
|
-
children: /* @__PURE__ */
|
|
455
|
-
label:
|
|
456
|
-
description:
|
|
457
|
-
checked:
|
|
458
|
-
onChange: (e) =>
|
|
448
|
+
children: /* @__PURE__ */ E(l, {
|
|
449
|
+
label: N("devportal.requireWorkspaceAdminApproval", "Require workspace admin approval"),
|
|
450
|
+
description: N("devportal.requireWorkspaceAdminApprovalDescription", "When enabled, workspace admins must approve installations before users can access this app"),
|
|
451
|
+
checked: Y.requiresApproval,
|
|
452
|
+
onChange: (e) => Q("requiresApproval", e.target.checked)
|
|
459
453
|
})
|
|
460
454
|
})
|
|
461
455
|
}),
|
|
462
|
-
/* @__PURE__ */
|
|
456
|
+
/* @__PURE__ */ D("div", {
|
|
463
457
|
className: "flex flex-col gap-4 border-t pt-6",
|
|
464
|
-
children: [/* @__PURE__ */
|
|
458
|
+
children: [/* @__PURE__ */ D("div", {
|
|
465
459
|
className: "flex items-center justify-between",
|
|
466
|
-
children: [/* @__PURE__ */
|
|
460
|
+
children: [/* @__PURE__ */ E("div", {
|
|
467
461
|
className: "flex items-center gap-2",
|
|
468
|
-
children:
|
|
462
|
+
children: Se && /* @__PURE__ */ D("button", {
|
|
469
463
|
type: "button",
|
|
470
|
-
onClick:
|
|
471
|
-
disabled:
|
|
464
|
+
onClick: xe,
|
|
465
|
+
disabled: U,
|
|
466
|
+
title: U ? "Save your changes first" : void 0,
|
|
472
467
|
className: "inline-flex items-center gap-2 rounded-md border border-primary bg-primary/10 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/20 transition-colors disabled:opacity-50",
|
|
473
|
-
children: [/* @__PURE__ */
|
|
468
|
+
children: [/* @__PURE__ */ E(oe, { size: 16 }), N("devportal.submitForReview", "Submit for Review")]
|
|
474
469
|
})
|
|
475
|
-
}), /* @__PURE__ */
|
|
470
|
+
}), /* @__PURE__ */ E("button", {
|
|
476
471
|
type: "submit",
|
|
477
|
-
disabled:
|
|
478
|
-
"aria-disabled": !
|
|
472
|
+
disabled: P || !U || !j,
|
|
473
|
+
"aria-disabled": !j,
|
|
479
474
|
className: "inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50",
|
|
480
|
-
children:
|
|
475
|
+
children: P ? /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ E("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" }), N("devportal.saving", "Saving...")] }) : /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ E(ae, { size: 16 }), N("devportal.saveChanges", "Save Changes")] })
|
|
481
476
|
})]
|
|
482
|
-
}), /* @__PURE__ */
|
|
477
|
+
}), /* @__PURE__ */ D("div", {
|
|
483
478
|
className: "rounded-lg border border-border-subtle bg-status-error-bg-subtle p-4",
|
|
484
479
|
children: [
|
|
485
|
-
/* @__PURE__ */
|
|
480
|
+
/* @__PURE__ */ E("h3", {
|
|
486
481
|
className: "text-sm font-medium text-status-error-text",
|
|
487
|
-
children:
|
|
482
|
+
children: N("devportal.dangerZone", "Danger Zone")
|
|
488
483
|
}),
|
|
489
|
-
/* @__PURE__ */
|
|
484
|
+
/* @__PURE__ */ E("p", {
|
|
490
485
|
className: "mt-1 text-sm text-status-error-text",
|
|
491
|
-
children:
|
|
486
|
+
children: N("devportal.dangerZoneWarning", "These actions are irreversible. Please proceed with caution.")
|
|
492
487
|
}),
|
|
493
|
-
/* @__PURE__ */
|
|
488
|
+
/* @__PURE__ */ D("div", {
|
|
494
489
|
className: "mt-4 flex gap-3",
|
|
495
490
|
children: [
|
|
496
|
-
|
|
491
|
+
Ce && /* @__PURE__ */ D("button", {
|
|
497
492
|
type: "button",
|
|
498
|
-
onClick: () =>
|
|
493
|
+
onClick: () => V(!0),
|
|
499
494
|
className: "inline-flex items-center gap-2 rounded-md border border-accent-orange bg-bg-surface px-3 py-1.5 text-sm font-medium text-accent-orange hover:bg-accent-orange-subtle transition-colors",
|
|
500
|
-
children: [/* @__PURE__ */
|
|
495
|
+
children: [/* @__PURE__ */ E(C, { size: 14 }), N("devportal.deprecateApp", "Deprecate App")]
|
|
501
496
|
}),
|
|
502
|
-
|
|
497
|
+
we && /* @__PURE__ */ D("button", {
|
|
503
498
|
type: "button",
|
|
504
|
-
onClick: () =>
|
|
499
|
+
onClick: () => H(!0),
|
|
505
500
|
className: "inline-flex items-center gap-2 rounded-md border border-accent-orange bg-bg-surface px-3 py-1.5 text-sm font-medium text-accent-orange hover:bg-accent-orange-subtle transition-colors",
|
|
506
|
-
children: [/* @__PURE__ */
|
|
501
|
+
children: [/* @__PURE__ */ E(w, { size: 14 }), N("devportal.deactivateApp", "Deactivate App")]
|
|
507
502
|
}),
|
|
508
|
-
/* @__PURE__ */
|
|
503
|
+
/* @__PURE__ */ D("button", {
|
|
509
504
|
type: "button",
|
|
510
|
-
onClick: () =>
|
|
511
|
-
disabled: !
|
|
512
|
-
"aria-disabled": !
|
|
505
|
+
onClick: () => z(!0),
|
|
506
|
+
disabled: !M,
|
|
507
|
+
"aria-disabled": !M,
|
|
513
508
|
className: "inline-flex items-center gap-2 rounded-md border border-status-error-bg bg-bg-surface px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50",
|
|
514
|
-
children: [/* @__PURE__ */
|
|
509
|
+
children: [/* @__PURE__ */ E(se, { size: 14 }), N("devportal.deleteApp", "Delete App")]
|
|
515
510
|
})
|
|
516
511
|
]
|
|
517
512
|
})
|
|
@@ -520,38 +515,38 @@ var k = () => {
|
|
|
520
515
|
})
|
|
521
516
|
]
|
|
522
517
|
}),
|
|
523
|
-
/* @__PURE__ */
|
|
524
|
-
open:
|
|
525
|
-
onOpenChange:
|
|
526
|
-
title:
|
|
527
|
-
description:
|
|
528
|
-
confirmLabel:
|
|
518
|
+
/* @__PURE__ */ E(m, {
|
|
519
|
+
open: R,
|
|
520
|
+
onOpenChange: z,
|
|
521
|
+
title: N("devportal.deleteApplication", "Delete Application"),
|
|
522
|
+
description: N("devportal.deleteApplicationConfirm", `Are you sure you want to delete "${J.name}"? This action cannot be undone. All OAuth clients, API keys, webhooks, and analytics data will be permanently deleted.`),
|
|
523
|
+
confirmLabel: N("devportal.deleteApplication", "Delete Application"),
|
|
529
524
|
variant: "destructive",
|
|
530
|
-
onConfirm:
|
|
525
|
+
onConfirm: ve
|
|
531
526
|
}),
|
|
532
|
-
/* @__PURE__ */
|
|
533
|
-
open:
|
|
534
|
-
onOpenChange:
|
|
535
|
-
title:
|
|
536
|
-
description:
|
|
537
|
-
confirmLabel:
|
|
527
|
+
/* @__PURE__ */ E(m, {
|
|
528
|
+
open: B,
|
|
529
|
+
onOpenChange: V,
|
|
530
|
+
title: N("devportal.deprecateApplication", "Deprecate Application"),
|
|
531
|
+
description: N("devportal.deprecateApplicationConfirm", `Are you sure you want to deprecate "${J.name}"? Existing users will still be able to use the app, but it will no longer be visible in the marketplace and new installations will be disabled.`),
|
|
532
|
+
confirmLabel: N("devportal.deprecateApplication", "Deprecate Application"),
|
|
538
533
|
variant: "warning",
|
|
539
|
-
onConfirm:
|
|
534
|
+
onConfirm: ye
|
|
540
535
|
}),
|
|
541
|
-
/* @__PURE__ */
|
|
536
|
+
/* @__PURE__ */ E(m, {
|
|
542
537
|
open: pe,
|
|
543
|
-
onOpenChange:
|
|
544
|
-
title:
|
|
545
|
-
description:
|
|
546
|
-
confirmLabel:
|
|
538
|
+
onOpenChange: H,
|
|
539
|
+
title: N("devportal.deactivateApplication", "Deactivate Application"),
|
|
540
|
+
description: N("devportal.deactivateApplicationConfirm", `Are you sure you want to deactivate "${J.name}"? This will revoke all active tokens and disable the app from the auth-svc layer. The app will no longer be able to authenticate or act on behalf of users.`),
|
|
541
|
+
confirmLabel: N("devportal.deactivateApplication", "Deactivate Application"),
|
|
547
542
|
variant: "destructive",
|
|
548
|
-
onConfirm:
|
|
543
|
+
onConfirm: be
|
|
549
544
|
})
|
|
550
545
|
]
|
|
551
546
|
})
|
|
552
547
|
});
|
|
553
548
|
};
|
|
554
549
|
//#endregion
|
|
555
|
-
export {
|
|
550
|
+
export { O as EditApplicationPage };
|
|
556
551
|
|
|
557
552
|
//# sourceMappingURL=EditApplicationPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditApplicationPage.js","names":[],"sources":["../../../src/devportal/pages/EditApplicationPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { useParams } from \"react-router-dom\";\nimport {\n Save,\n Trash2,\n AlertTriangle,\n Archive,\n Send,\n AlertCircle,\n AppWindow,\n Power,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n TextareaField,\n SelectField,\n TagInput,\n CheckboxField,\n} from \"../components/FormField\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type { Application, AppType, AppVisibility, AppStatus } from \"../types\";\nimport { APP_TYPE_LABELS } from \"../utils/constants\";\nimport {\n useGetApplicationQuery,\n useUpdateApplicationMutation,\n useDeleteApplicationMutation,\n useSubmitApplicationMutation,\n useDeactivateAppMutation,\n} from \"../../generated/global-operations\";\n\ninterface EditApplicationFormData {\n name: string;\n slug: string;\n shortDescription: string;\n description: string;\n appType: AppType;\n visibility: AppVisibility;\n category: string;\n tags: string[];\n keywords: string[];\n websiteUrl: string;\n documentationUrl: string;\n supportUrl: string;\n privacyPolicyUrl: string;\n termsOfServiceUrl: string;\n githubUrl: string;\n requiresApproval: boolean;\n}\n\ninterface FormErrors {\n name?: string;\n slug?: string;\n shortDescription?: string;\n appType?: string;\n category?: string;\n}\n\nconst APP_TYPE_OPTIONS = Object.entries(APP_TYPE_LABELS).map(\n ([value, label]) => ({\n value,\n label,\n }),\n);\n\nconst VISIBILITY_OPTIONS = [\n { value: \"PUBLIC\", label: \"Public - Visible to everyone\" },\n { value: \"PRIVATE\", label: \"Private - Only visible to you\" },\n { value: \"UNLISTED\", label: \"Unlisted - Accessible via direct link\" },\n { value: \"INTERNAL\", label: \"Internal - Only visible within organization\" },\n];\n\nconst CATEGORY_OPTIONS = [\n { value: \"ai\", label: \"AI & Automation\" },\n { value: \"integration\", label: \"Action in an App\" },\n { value: \"data\", label: \"Data & Transform\" },\n { value: \"flow\", label: \"Flow & Logic\" },\n { value: \"core\", label: \"Core\" },\n { value: \"communication\", label: \"Communication\" },\n { value: \"trigger\", label: \"Triggers\" },\n];\n\n/**\n * Helper to safely map GraphQL response to Application type\n */\nfunction mapToApplication(\n data: NonNullable<\n ReturnType<typeof useGetApplicationQuery>[\"data\"]\n >[\"application\"],\n): Application | null {\n if (!data) return null;\n return {\n id: data.id,\n name: data.name,\n slug: data.slug,\n shortDescription: data.shortDescription || undefined,\n description: data.description || undefined,\n appType: data.appType,\n status: data.status,\n visibility: data.visibility,\n tenantId: data.tenantId,\n developerId: data.developerId,\n developerOrganizationId: data.developerOrganizationId || undefined,\n category: data.category || undefined,\n tags: data.tags || [],\n keywords: data.keywords || [],\n iconUrl: data.iconUrl || undefined,\n websiteUrl: data.websiteUrl || undefined,\n documentationUrl: data.documentationUrl || undefined,\n supportUrl: data.supportUrl || undefined,\n privacyPolicyUrl: data.privacyPolicyUrl || undefined,\n termsOfServiceUrl: data.termsOfServiceUrl || undefined,\n githubUrl: data.githubUrl || undefined,\n pricingType: data.pricingType || undefined,\n installCount: data.installCount,\n activeInstallCount: data.activeInstallCount,\n averageRating: data.averageRating ?? undefined,\n reviewCount: data.reviewCount,\n submittedAt: data.submittedAt || undefined,\n publishedAt: data.publishedAt || undefined,\n lastReviewedAt: data.lastReviewedAt || undefined,\n reviewStatus: data.reviewStatus,\n reviewNotes: data.reviewNotes || undefined,\n reviewedBy: data.reviewedBy || undefined,\n isFeatured: data.isFeatured,\n isVerified: data.isVerified,\n requiresApproval: data.requiresApproval,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n };\n}\n\n/**\n * Edit application page — wired to real GraphQL mutations.\n */\nexport const EditApplicationPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { appId } = useParams<{ appId: string }>();\n const { t } = useI18n();\n const { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_UPDATE,\n );\n const { allowed: canDelete } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_DELETE,\n );\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [errors, setErrors] = useState<FormErrors>({});\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [showDeprecateDialog, setShowDeprecateDialog] = useState(false);\n const [showDeactivateDialog, setShowDeactivateDialog] = useState(false);\n const [hasChanges, setHasChanges] = useState(false);\n\n // ---------------------------------------------------------------------------\n // GraphQL queries & mutations\n // ---------------------------------------------------------------------------\n const {\n data,\n loading,\n error: queryError,\n } = useGetApplicationQuery({\n variables: { id: appId! },\n skip: !appId,\n });\n\n const [updateApplication] = useUpdateApplicationMutation();\n const [deleteApplication] = useDeleteApplicationMutation();\n const [submitApplication] = useSubmitApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n // ---------------------------------------------------------------------------\n // Derive application from query data\n // ---------------------------------------------------------------------------\n const app = mapToApplication(data?.application);\n\n useEffect(() => {\n const name = app?.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, app?.name]);\n\n // ---------------------------------------------------------------------------\n // Form state — initialised from fetched app once available\n // ---------------------------------------------------------------------------\n const [formData, setFormData] = useState<EditApplicationFormData>({\n name: \"\",\n slug: \"\",\n shortDescription: \"\",\n description: \"\",\n appType: \"WEB_APP\",\n visibility: \"PUBLIC\",\n category: \"\",\n tags: [],\n keywords: [],\n websiteUrl: \"\",\n documentationUrl: \"\",\n supportUrl: \"\",\n privacyPolicyUrl: \"\",\n termsOfServiceUrl: \"\",\n githubUrl: \"\",\n requiresApproval: false,\n });\n\n useEffect(() => {\n if (app) {\n setFormData({\n name: app.name,\n slug: app.slug,\n shortDescription: app.shortDescription || \"\",\n description: app.description || \"\",\n appType: app.appType,\n visibility: app.visibility,\n category: app.category || \"\",\n tags: app.tags,\n keywords: app.keywords,\n websiteUrl: app.websiteUrl || \"\",\n documentationUrl: app.documentationUrl || \"\",\n supportUrl: app.supportUrl || \"\",\n privacyPolicyUrl: app.privacyPolicyUrl || \"\",\n termsOfServiceUrl: app.termsOfServiceUrl || \"\",\n githubUrl: app.githubUrl || \"\",\n requiresApproval: app.requiresApproval,\n });\n setHasChanges(false);\n }\n // Re-sync form when the underlying application data changes (e.g. after\n // a refetch triggered by a mutation). We intentionally depend on\n // `data?.application` rather than the derived `app` object so that the\n // effect fires when the query cache updates.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data?.application]);\n\n // ---------------------------------------------------------------------------\n // Handlers\n // ---------------------------------------------------------------------------\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleChange = (\n field: keyof EditApplicationFormData,\n value: string | string[] | boolean,\n ) => {\n setFormData((prev) => ({ ...prev, [field]: value }));\n setHasChanges(true);\n if (errors[field as keyof FormErrors]) {\n setErrors((prev) => ({ ...prev, [field]: undefined }));\n }\n };\n\n const validateForm = (): boolean => {\n const newErrors: FormErrors = {};\n\n if (!formData.name.trim()) {\n newErrors.name = tr(\n \"devportal.appNameRequired\",\n \"Application name is required\",\n );\n } else if (formData.name.length < 3) {\n newErrors.name = tr(\n \"devportal.appNameMinLength\",\n \"Name must be at least 3 characters\",\n );\n } else if (formData.name.length > 100) {\n newErrors.name = tr(\n \"devportal.appNameMaxLength\",\n \"Name must be less than 100 characters\",\n );\n }\n\n if (!formData.slug.trim()) {\n newErrors.slug = tr(\"devportal.slugRequired\", \"Slug is required\");\n } else if (!/^[a-z0-9-]+$/.test(formData.slug)) {\n newErrors.slug = tr(\n \"devportal.slugInvalidChars\",\n \"Slug can only contain lowercase letters, numbers, and hyphens\",\n );\n }\n\n if (!formData.shortDescription.trim()) {\n newErrors.shortDescription = tr(\n \"devportal.shortDescriptionRequired\",\n \"Short description is required\",\n );\n } else if (formData.shortDescription.length > 200) {\n newErrors.shortDescription = tr(\n \"devportal.shortDescriptionMaxLength\",\n \"Short description must be less than 200 characters\",\n );\n }\n\n if (!formData.appType) {\n newErrors.appType = tr(\n \"devportal.appTypeRequired\",\n \"Application type is required\",\n );\n }\n\n if (!formData.category) {\n newErrors.category = tr(\n \"devportal.categoryRequired\",\n \"Category is required\",\n );\n }\n\n setErrors(newErrors);\n return Object.keys(newErrors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm() || !app) {\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n name: formData.name,\n shortDescription: formData.shortDescription,\n description: formData.description,\n appType: formData.appType,\n visibility: formData.visibility,\n category: formData.category,\n tags: formData.tags,\n keywords: formData.keywords,\n websiteUrl: formData.websiteUrl || null,\n documentationUrl: formData.documentationUrl || null,\n supportUrl: formData.supportUrl || null,\n privacyPolicyUrl: formData.privacyPolicyUrl || null,\n termsOfServiceUrl: formData.termsOfServiceUrl || null,\n githubUrl: formData.githubUrl || null,\n },\n },\n });\n setHasChanges(false);\n } catch (err) {\n console.error(\"Failed to update application:\", err);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleDelete = async () => {\n if (!app) return;\n void nativeImpact(\"medium\");\n try {\n await deleteApplication({\n variables: { id: app.id },\n });\n void nativeNotify(\"success\");\n handleNavigate(\"/apps\");\n } catch (err) {\n void nativeNotify(\"error\");\n console.error(\"Failed to delete application:\", err);\n }\n };\n\n const handleDeprecate = async () => {\n if (!app) return;\n try {\n // Deprecate is modelled as a status transition via update. The backend\n // treats a visibility change to PRIVATE + status mutation or a dedicated\n // deprecation endpoint. Here we use submitApplication with a status note\n // as the deprecate action since there is no separate `deprecateApplication`\n // mutation. If a dedicated mutation is added later, swap it in here.\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n visibility: \"PRIVATE\",\n },\n },\n });\n setShowDeprecateDialog(false);\n } catch (err) {\n console.error(\"Failed to deprecate application:\", err);\n }\n };\n\n const handleDeactivate = async () => {\n if (!app) return;\n try {\n await deactivateApp({\n variables: { id: app.id },\n });\n setShowDeactivateDialog(false);\n handleNavigate(\"/apps\");\n } catch (err) {\n console.error(\"Failed to deactivate application:\", err);\n }\n };\n\n const handleSubmitForReview = async () => {\n if (!app) return;\n try {\n setIsSubmitting(true);\n await submitApplication({\n variables: { id: app.id },\n });\n } catch (err) {\n console.error(\"Failed to submit for review:\", err);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // ---------------------------------------------------------------------------\n // Loading / Error / Not-found states\n // ---------------------------------------------------------------------------\n if (loading) {\n return (\n <LoadingState\n message={tr(\"devportal.loadingApplication\", \"Loading application...\")}\n />\n );\n }\n\n if (queryError) {\n return (\n <PageLayout\n title={tr(\"devportal.error\", \"Error\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertCircle size={48} className=\"text-destructive mb-4\" />\n <h3 className=\"text-lg font-semibold mb-2\">\n {tr(\n \"devportal.failedToLoadApplication\",\n \"Failed to load application\",\n )}\n </h3>\n <p className=\"text-sm text-muted-foreground\">{queryError.message}</p>\n </div>\n </PageLayout>\n );\n }\n\n if (!app) {\n return (\n <PageLayout\n title={tr(\"devportal.notFound\", \"Not Found\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <EmptyState\n icon={<AppWindow size={48} />}\n title={tr(\"devportal.applicationNotFound\", \"Application not found\")}\n description={tr(\n \"devportal.applicationNotFoundDescription\",\n \"The application you're looking for doesn't exist or you don't have access to it.\",\n )}\n />\n </PageLayout>\n );\n }\n\n // ---------------------------------------------------------------------------\n // Derived flags\n // ---------------------------------------------------------------------------\n const canSubmitForReview =\n app.status === \"DRAFT\" || app.status === \"REJECTED\";\n const canDeprecate = app.status === \"PUBLISHED\";\n const canDeactivate = app.status === \"ACTIVE\" || app.status === \"PUBLISHED\";\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_UPDATE}>\n <PageLayout\n title={`${tr(\"devportal.editAppTitlePrefix\", \"Edit:\")} ${app.name}`}\n description={tr(\n \"devportal.editAppDescription\",\n \"Update your application settings\",\n )}\n backLink={`${basePath}/apps/${app.id}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n actions={\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={app.status} type=\"app\" />\n </div>\n }\n >\n <form onSubmit={handleSubmit} className=\"space-y-8 max-w-3xl\">\n {/* Status banner for published apps */}\n {app.status === \"PUBLISHED\" && (\n <div className=\"rounded-lg border border-border-subtle bg-status-warning-bg-subtle p-4 flex gap-3\">\n <AlertTriangle\n size={20}\n className=\"text-status-warning-text flex-shrink-0 mt-0.5\"\n />\n <div className=\"text-sm text-status-warning-text\">\n <p className=\"font-medium\">\n {tr(\n \"devportal.appIsPublished\",\n \"This application is published\",\n )}\n </p>\n <p className=\"mt-1 text-status-warning-text\">\n {tr(\n \"devportal.publishedAppChangesWarning\",\n \"Changes to published apps may require re-review. Major changes will put the app back into review status.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {/* Basic Information */}\n <PageSection\n title={tr(\"devportal.basicInformation\", \"Basic Information\")}\n description={tr(\n \"devportal.basicInformationDescription\",\n \"Core details about your application\",\n )}\n >\n <div className=\"space-y-4\">\n <InputField\n label={tr(\"devportal.applicationName\", \"Application Name\")}\n value={formData.name}\n onChange={(e) => handleChange(\"name\", e.target.value)}\n placeholder={tr(\n \"devportal.applicationNamePlaceholder\",\n \"My Awesome App\",\n )}\n required\n error={errors.name}\n />\n\n <InputField\n label={tr(\"devportal.slug\", \"Slug\")}\n value={formData.slug}\n onChange={(e) =>\n handleChange(\"slug\", e.target.value.toLowerCase())\n }\n placeholder={tr(\"devportal.slugPlaceholder\", \"my-awesome-app\")}\n required\n error={errors.slug}\n hint={tr(\n \"devportal.slugChangeWarning\",\n \"Changing the slug may break existing integrations\",\n )}\n />\n\n <TextareaField\n label={tr(\"devportal.shortDescription\", \"Short Description\")}\n value={formData.shortDescription}\n onChange={(e) =>\n handleChange(\"shortDescription\", e.target.value)\n }\n placeholder={tr(\n \"devportal.shortDescriptionPlaceholder\",\n \"A brief description of what your app does\",\n )}\n required\n error={errors.shortDescription}\n hint={`${formData.shortDescription.length}/200 ${tr(\"devportal.characters\", \"characters\")}`}\n rows={2}\n />\n\n <TextareaField\n label={tr(\"devportal.fullDescription\", \"Full Description\")}\n value={formData.description}\n onChange={(e) => handleChange(\"description\", e.target.value)}\n placeholder={tr(\n \"devportal.fullDescriptionPlaceholder\",\n \"Detailed description of your application, features, and use cases...\",\n )}\n rows={6}\n hint={tr(\n \"devportal.markdownSupported\",\n \"Markdown formatting is supported\",\n )}\n />\n </div>\n </PageSection>\n\n {/* Classification */}\n <PageSection\n title={tr(\"devportal.classification\", \"Classification\")}\n description={tr(\n \"devportal.classificationDescription\",\n \"Categorize your application\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <SelectField\n label={tr(\"devportal.applicationType\", \"Application Type\")}\n value={formData.appType}\n onChange={(e) => handleChange(\"appType\", e.target.value)}\n options={APP_TYPE_OPTIONS}\n required\n error={errors.appType}\n />\n\n <SelectField\n label={tr(\"devportal.category\", \"Category\")}\n value={formData.category}\n onChange={(e) => handleChange(\"category\", e.target.value)}\n options={CATEGORY_OPTIONS}\n required\n error={errors.category}\n />\n\n <SelectField\n label={tr(\"devportal.visibility\", \"Visibility\")}\n value={formData.visibility}\n onChange={(e) =>\n handleChange(\"visibility\", e.target.value as AppVisibility)\n }\n options={VISIBILITY_OPTIONS}\n hint={tr(\n \"devportal.visibilityHint\",\n \"Controls who can see this app once published. Public apps still require admin review and approval before appearing in the store.\",\n )}\n />\n </div>\n\n <TagInput\n label={tr(\"devportal.tags\", \"Tags\")}\n value={formData.tags}\n onChange={(tags) => handleChange(\"tags\", tags)}\n placeholder={tr(\n \"devportal.addTagsPlaceholder\",\n \"Add tags (press Enter)\",\n )}\n />\n\n <TagInput\n label={tr(\"devportal.keywords\", \"Keywords\")}\n value={formData.keywords}\n onChange={(keywords) => handleChange(\"keywords\", keywords)}\n placeholder={tr(\n \"devportal.addKeywordsPlaceholder\",\n \"Add keywords (press Enter)\",\n )}\n />\n </PageSection>\n\n {/* URLs */}\n <PageSection\n title={tr(\"devportal.links\", \"Links\")}\n description={tr(\n \"devportal.linksDescription\",\n \"External resources for your application\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.websiteUrl\", \"Website URL\")}\n type=\"url\"\n value={formData.websiteUrl}\n onChange={(e) => handleChange(\"websiteUrl\", e.target.value)}\n placeholder={tr(\n \"devportal.websiteUrlPlaceholder\",\n \"https://example.com\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.documentationUrl\", \"Documentation URL\")}\n type=\"url\"\n value={formData.documentationUrl}\n onChange={(e) =>\n handleChange(\"documentationUrl\", e.target.value)\n }\n placeholder={tr(\n \"devportal.documentationUrlPlaceholder\",\n \"https://docs.example.com\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.supportUrl\", \"Support URL\")}\n type=\"url\"\n value={formData.supportUrl}\n onChange={(e) => handleChange(\"supportUrl\", e.target.value)}\n placeholder={tr(\n \"devportal.supportUrlPlaceholder\",\n \"https://support.example.com\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.githubUrl\", \"GitHub URL\")}\n type=\"url\"\n value={formData.githubUrl}\n onChange={(e) => handleChange(\"githubUrl\", e.target.value)}\n placeholder={tr(\n \"devportal.githubUrlPlaceholder\",\n \"https://github.com/org/repo\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.privacyPolicyUrl\", \"Privacy Policy URL\")}\n type=\"url\"\n value={formData.privacyPolicyUrl}\n onChange={(e) =>\n handleChange(\"privacyPolicyUrl\", e.target.value)\n }\n placeholder={tr(\n \"devportal.privacyPolicyUrlPlaceholder\",\n \"https://example.com/privacy\",\n )}\n />\n\n <InputField\n label={tr(\n \"devportal.termsOfServiceUrl\",\n \"Terms of Service URL\",\n )}\n type=\"url\"\n value={formData.termsOfServiceUrl}\n onChange={(e) =>\n handleChange(\"termsOfServiceUrl\", e.target.value)\n }\n placeholder={tr(\n \"devportal.termsOfServiceUrlPlaceholder\",\n \"https://example.com/terms\",\n )}\n />\n </div>\n </PageSection>\n\n {/* Settings */}\n <PageSection\n title={tr(\"devportal.settings\", \"Settings\")}\n description={tr(\n \"devportal.settingsDescription\",\n \"Additional configuration options\",\n )}\n >\n <div className=\"space-y-4\">\n <CheckboxField\n label={tr(\n \"devportal.requireWorkspaceAdminApproval\",\n \"Require workspace admin approval\",\n )}\n description={tr(\n \"devportal.requireWorkspaceAdminApprovalDescription\",\n \"When enabled, workspace admins must approve installations before users can access this app\",\n )}\n checked={formData.requiresApproval}\n onChange={(e) =>\n handleChange(\"requiresApproval\", e.target.checked)\n }\n />\n </div>\n </PageSection>\n\n {/* Actions */}\n <div className=\"flex flex-col gap-4 border-t pt-6\">\n {/* Primary actions */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n {canSubmitForReview && (\n <button\n type=\"button\"\n onClick={handleSubmitForReview}\n disabled={isSubmitting || hasChanges}\n className=\"inline-flex items-center gap-2 rounded-md border border-primary bg-primary/10 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/20 transition-colors disabled:opacity-50\"\n >\n <Send size={16} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </button>\n )}\n </div>\n <button\n type=\"submit\"\n disabled={isSubmitting || !hasChanges || !canUpdate}\n aria-disabled={!canUpdate}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {isSubmitting ? (\n <>\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n {tr(\"devportal.saving\", \"Saving...\")}\n </>\n ) : (\n <>\n <Save size={16} />\n {tr(\"devportal.saveChanges\", \"Save Changes\")}\n </>\n )}\n </button>\n </div>\n\n {/* Danger zone */}\n <div className=\"rounded-lg border border-border-subtle bg-status-error-bg-subtle p-4\">\n <h3 className=\"text-sm font-medium text-status-error-text\">\n {tr(\"devportal.dangerZone\", \"Danger Zone\")}\n </h3>\n <p className=\"mt-1 text-sm text-status-error-text\">\n {tr(\n \"devportal.dangerZoneWarning\",\n \"These actions are irreversible. Please proceed with caution.\",\n )}\n </p>\n <div className=\"mt-4 flex gap-3\">\n {canDeprecate && (\n <button\n type=\"button\"\n onClick={() => setShowDeprecateDialog(true)}\n className=\"inline-flex items-center gap-2 rounded-md border border-accent-orange bg-bg-surface px-3 py-1.5 text-sm font-medium text-accent-orange hover:bg-accent-orange-subtle transition-colors\"\n >\n <Archive size={14} />\n {tr(\"devportal.deprecateApp\", \"Deprecate App\")}\n </button>\n )}\n {canDeactivate && (\n <button\n type=\"button\"\n onClick={() => setShowDeactivateDialog(true)}\n className=\"inline-flex items-center gap-2 rounded-md border border-accent-orange bg-bg-surface px-3 py-1.5 text-sm font-medium text-accent-orange hover:bg-accent-orange-subtle transition-colors\"\n >\n <Power size={14} />\n {tr(\"devportal.deactivateApp\", \"Deactivate App\")}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => setShowDeleteDialog(true)}\n disabled={!canDelete}\n aria-disabled={!canDelete}\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg bg-bg-surface px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50\"\n >\n <Trash2 size={14} />\n {tr(\"devportal.deleteApp\", \"Delete App\")}\n </button>\n </div>\n </div>\n </div>\n </form>\n\n {/* Delete confirmation dialog */}\n <ConfirmDialog\n open={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n title={tr(\"devportal.deleteApplication\", \"Delete Application\")}\n description={tr(\n \"devportal.deleteApplicationConfirm\",\n `Are you sure you want to delete \"${app.name}\"? This action cannot be undone. All OAuth clients, API keys, webhooks, and analytics data will be permanently deleted.`,\n )}\n confirmLabel={tr(\"devportal.deleteApplication\", \"Delete Application\")}\n variant=\"destructive\"\n onConfirm={handleDelete}\n />\n\n {/* Deprecate confirmation dialog */}\n <ConfirmDialog\n open={showDeprecateDialog}\n onOpenChange={setShowDeprecateDialog}\n title={tr(\"devportal.deprecateApplication\", \"Deprecate Application\")}\n description={tr(\n \"devportal.deprecateApplicationConfirm\",\n `Are you sure you want to deprecate \"${app.name}\"? Existing users will still be able to use the app, but it will no longer be visible in the marketplace and new installations will be disabled.`,\n )}\n confirmLabel={tr(\n \"devportal.deprecateApplication\",\n \"Deprecate Application\",\n )}\n variant=\"warning\"\n onConfirm={handleDeprecate}\n />\n\n {/* Deactivate confirmation dialog */}\n <ConfirmDialog\n open={showDeactivateDialog}\n onOpenChange={setShowDeactivateDialog}\n title={tr(\n \"devportal.deactivateApplication\",\n \"Deactivate Application\",\n )}\n description={tr(\n \"devportal.deactivateApplicationConfirm\",\n `Are you sure you want to deactivate \"${app.name}\"? This will revoke all active tokens and disable the app from the auth-svc layer. The app will no longer be able to authenticate or act on behalf of users.`,\n )}\n confirmLabel={tr(\n \"devportal.deactivateApplication\",\n \"Deactivate Application\",\n )}\n variant=\"destructive\"\n onConfirm={handleDeactivate}\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EditApplicationPage.js","names":[],"sources":["../../../src/devportal/pages/EditApplicationPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { useParams } from \"react-router-dom\";\nimport {\n Save,\n Trash2,\n AlertTriangle,\n Archive,\n Send,\n AlertCircle,\n AppWindow,\n Power,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n TextareaField,\n SelectField,\n TagInput,\n CheckboxField,\n} from \"../components/FormField\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type { Application, AppType, AppVisibility, AppStatus } from \"../types\";\nimport { APP_TYPE_LABELS } from \"../utils/constants\";\nimport {\n useGetApplicationQuery,\n useUpdateApplicationMutation,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n} from \"../../generated/global-operations\";\n\ninterface EditApplicationFormData {\n name: string;\n slug: string;\n shortDescription: string;\n description: string;\n appType: AppType;\n visibility: AppVisibility;\n category: string;\n tags: string[];\n keywords: string[];\n websiteUrl: string;\n documentationUrl: string;\n supportUrl: string;\n privacyPolicyUrl: string;\n termsOfServiceUrl: string;\n githubUrl: string;\n requiresApproval: boolean;\n}\n\ninterface FormErrors {\n name?: string;\n slug?: string;\n shortDescription?: string;\n appType?: string;\n category?: string;\n}\n\nconst APP_TYPE_OPTIONS = Object.entries(APP_TYPE_LABELS).map(\n ([value, label]) => ({\n value,\n label,\n }),\n);\n\nconst VISIBILITY_OPTIONS = [\n { value: \"PUBLIC\", label: \"Public - Visible to everyone\" },\n { value: \"PRIVATE\", label: \"Private - Only visible to you\" },\n { value: \"UNLISTED\", label: \"Unlisted - Accessible via direct link\" },\n { value: \"INTERNAL\", label: \"Internal - Only visible within organization\" },\n];\n\nconst CATEGORY_OPTIONS = [\n { value: \"ai\", label: \"AI & Automation\" },\n { value: \"integration\", label: \"Action in an App\" },\n { value: \"data\", label: \"Data & Transform\" },\n { value: \"flow\", label: \"Flow & Logic\" },\n { value: \"core\", label: \"Core\" },\n { value: \"communication\", label: \"Communication\" },\n { value: \"trigger\", label: \"Triggers\" },\n];\n\n/**\n * Helper to safely map GraphQL response to Application type\n */\nfunction mapToApplication(\n data: NonNullable<\n ReturnType<typeof useGetApplicationQuery>[\"data\"]\n >[\"application\"],\n): Application | null {\n if (!data) return null;\n return {\n id: data.id,\n name: data.name,\n slug: data.slug,\n shortDescription: data.shortDescription || undefined,\n description: data.description || undefined,\n appType: data.appType,\n status: data.status,\n visibility: data.visibility,\n tenantId: data.tenantId,\n developerId: data.developerId,\n developerOrganizationId: data.developerOrganizationId || undefined,\n category: data.category || undefined,\n tags: data.tags || [],\n keywords: data.keywords || [],\n iconUrl: data.iconUrl || undefined,\n websiteUrl: data.websiteUrl || undefined,\n documentationUrl: data.documentationUrl || undefined,\n supportUrl: data.supportUrl || undefined,\n privacyPolicyUrl: data.privacyPolicyUrl || undefined,\n termsOfServiceUrl: data.termsOfServiceUrl || undefined,\n githubUrl: data.githubUrl || undefined,\n pricingType: data.pricingType || undefined,\n installCount: data.installCount,\n activeInstallCount: data.activeInstallCount,\n averageRating: data.averageRating ?? undefined,\n reviewCount: data.reviewCount,\n submittedAt: data.submittedAt || undefined,\n publishedAt: data.publishedAt || undefined,\n lastReviewedAt: data.lastReviewedAt || undefined,\n reviewStatus: data.reviewStatus,\n reviewNotes: data.reviewNotes || undefined,\n reviewedBy: data.reviewedBy || undefined,\n isFeatured: data.isFeatured,\n isVerified: data.isVerified,\n requiresApproval: data.requiresApproval,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n };\n}\n\n/**\n * Edit application page — wired to real GraphQL mutations.\n */\nexport const EditApplicationPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { appId } = useParams<{ appId: string }>();\n const { t } = useI18n();\n const { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_UPDATE,\n );\n const { allowed: canDelete } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_DELETE,\n );\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [errors, setErrors] = useState<FormErrors>({});\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [showDeprecateDialog, setShowDeprecateDialog] = useState(false);\n const [showDeactivateDialog, setShowDeactivateDialog] = useState(false);\n const [hasChanges, setHasChanges] = useState(false);\n\n // ---------------------------------------------------------------------------\n // GraphQL queries & mutations\n // ---------------------------------------------------------------------------\n const {\n data,\n loading,\n error: queryError,\n } = useGetApplicationQuery({\n variables: { id: appId! },\n skip: !appId,\n });\n\n const [updateApplication] = useUpdateApplicationMutation();\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n // ---------------------------------------------------------------------------\n // Derive application from query data\n // ---------------------------------------------------------------------------\n const app = mapToApplication(data?.application);\n\n useEffect(() => {\n const name = app?.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, app?.name]);\n\n // ---------------------------------------------------------------------------\n // Form state — initialised from fetched app once available\n // ---------------------------------------------------------------------------\n const [formData, setFormData] = useState<EditApplicationFormData>({\n name: \"\",\n slug: \"\",\n shortDescription: \"\",\n description: \"\",\n appType: \"WEB_APP\",\n visibility: \"PUBLIC\",\n category: \"\",\n tags: [],\n keywords: [],\n websiteUrl: \"\",\n documentationUrl: \"\",\n supportUrl: \"\",\n privacyPolicyUrl: \"\",\n termsOfServiceUrl: \"\",\n githubUrl: \"\",\n requiresApproval: false,\n });\n\n useEffect(() => {\n if (app) {\n setFormData({\n name: app.name,\n slug: app.slug,\n shortDescription: app.shortDescription || \"\",\n description: app.description || \"\",\n appType: app.appType,\n visibility: app.visibility,\n category: app.category || \"\",\n tags: app.tags,\n keywords: app.keywords,\n websiteUrl: app.websiteUrl || \"\",\n documentationUrl: app.documentationUrl || \"\",\n supportUrl: app.supportUrl || \"\",\n privacyPolicyUrl: app.privacyPolicyUrl || \"\",\n termsOfServiceUrl: app.termsOfServiceUrl || \"\",\n githubUrl: app.githubUrl || \"\",\n requiresApproval: app.requiresApproval,\n });\n setHasChanges(false);\n }\n // Re-sync form when the underlying application data changes (e.g. after\n // a refetch triggered by a mutation). We intentionally depend on\n // `data?.application` rather than the derived `app` object so that the\n // effect fires when the query cache updates.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data?.application]);\n\n // ---------------------------------------------------------------------------\n // Handlers\n // ---------------------------------------------------------------------------\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleChange = (\n field: keyof EditApplicationFormData,\n value: string | string[] | boolean,\n ) => {\n setFormData((prev) => ({ ...prev, [field]: value }));\n setHasChanges(true);\n if (errors[field as keyof FormErrors]) {\n setErrors((prev) => ({ ...prev, [field]: undefined }));\n }\n };\n\n const validateForm = (): boolean => {\n const newErrors: FormErrors = {};\n\n if (!formData.name.trim()) {\n newErrors.name = tr(\n \"devportal.appNameRequired\",\n \"Application name is required\",\n );\n } else if (formData.name.length < 3) {\n newErrors.name = tr(\n \"devportal.appNameMinLength\",\n \"Name must be at least 3 characters\",\n );\n } else if (formData.name.length > 100) {\n newErrors.name = tr(\n \"devportal.appNameMaxLength\",\n \"Name must be less than 100 characters\",\n );\n }\n\n if (!formData.slug.trim()) {\n newErrors.slug = tr(\"devportal.slugRequired\", \"Slug is required\");\n } else if (!/^[a-z0-9-]+$/.test(formData.slug)) {\n newErrors.slug = tr(\n \"devportal.slugInvalidChars\",\n \"Slug can only contain lowercase letters, numbers, and hyphens\",\n );\n }\n\n if (!formData.shortDescription.trim()) {\n newErrors.shortDescription = tr(\n \"devportal.shortDescriptionRequired\",\n \"Short description is required\",\n );\n } else if (formData.shortDescription.length > 200) {\n newErrors.shortDescription = tr(\n \"devportal.shortDescriptionMaxLength\",\n \"Short description must be less than 200 characters\",\n );\n }\n\n if (!formData.appType) {\n newErrors.appType = tr(\n \"devportal.appTypeRequired\",\n \"Application type is required\",\n );\n }\n\n if (!formData.category) {\n newErrors.category = tr(\n \"devportal.categoryRequired\",\n \"Category is required\",\n );\n }\n\n setErrors(newErrors);\n return Object.keys(newErrors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm() || !app) {\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n name: formData.name,\n shortDescription: formData.shortDescription,\n description: formData.description,\n appType: formData.appType,\n visibility: formData.visibility,\n category: formData.category,\n tags: formData.tags,\n keywords: formData.keywords,\n websiteUrl: formData.websiteUrl || null,\n documentationUrl: formData.documentationUrl || null,\n supportUrl: formData.supportUrl || null,\n privacyPolicyUrl: formData.privacyPolicyUrl || null,\n termsOfServiceUrl: formData.termsOfServiceUrl || null,\n githubUrl: formData.githubUrl || null,\n },\n },\n });\n setHasChanges(false);\n } catch (err) {\n console.error(\"Failed to update application:\", err);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleDelete = async () => {\n if (!app) return;\n void nativeImpact(\"medium\");\n try {\n await deleteApplication({\n variables: { id: app.id },\n });\n void nativeNotify(\"success\");\n handleNavigate(\"/apps\");\n } catch (err) {\n void nativeNotify(\"error\");\n console.error(\"Failed to delete application:\", err);\n }\n };\n\n const handleDeprecate = async () => {\n if (!app) return;\n try {\n // Deprecate is modelled as a status transition via update. The backend\n // treats a visibility change to PRIVATE + status mutation or a dedicated\n // deprecation endpoint. Here we use submitApplication with a status note\n // as the deprecate action since there is no separate `deprecateApplication`\n // mutation. If a dedicated mutation is added later, swap it in here.\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n visibility: \"PRIVATE\",\n },\n },\n });\n setShowDeprecateDialog(false);\n } catch (err) {\n console.error(\"Failed to deprecate application:\", err);\n }\n };\n\n const handleDeactivate = async () => {\n if (!app) return;\n try {\n await deactivateApp({\n variables: { id: app.id },\n });\n setShowDeactivateDialog(false);\n handleNavigate(\"/apps\");\n } catch (err) {\n console.error(\"Failed to deactivate application:\", err);\n }\n };\n\n const handleSubmitForReview = () => {\n if (!app) return;\n navigate?.(`${basePath}/apps/${app.id}/publish`);\n };\n\n // ---------------------------------------------------------------------------\n // Loading / Error / Not-found states\n // ---------------------------------------------------------------------------\n if (loading) {\n return (\n <LoadingState\n message={tr(\"devportal.loadingApplication\", \"Loading application...\")}\n />\n );\n }\n\n if (queryError) {\n return (\n <PageLayout\n title={tr(\"devportal.error\", \"Error\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertCircle size={48} className=\"text-destructive mb-4\" />\n <h3 className=\"text-lg font-semibold mb-2\">\n {tr(\n \"devportal.failedToLoadApplication\",\n \"Failed to load application\",\n )}\n </h3>\n <p className=\"text-sm text-muted-foreground\">{queryError.message}</p>\n </div>\n </PageLayout>\n );\n }\n\n if (!app) {\n return (\n <PageLayout\n title={tr(\"devportal.notFound\", \"Not Found\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <EmptyState\n icon={<AppWindow size={48} />}\n title={tr(\"devportal.applicationNotFound\", \"Application not found\")}\n description={tr(\n \"devportal.applicationNotFoundDescription\",\n \"The application you're looking for doesn't exist or you don't have access to it.\",\n )}\n />\n </PageLayout>\n );\n }\n\n // ---------------------------------------------------------------------------\n // Derived flags\n // ---------------------------------------------------------------------------\n const canSubmitForReview =\n app.status === \"DRAFT\" || app.status === \"REJECTED\";\n const canDeprecate = app.status === \"PUBLISHED\";\n const canDeactivate = app.status === \"ACTIVE\" || app.status === \"PUBLISHED\";\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_UPDATE}>\n <PageLayout\n title={`${tr(\"devportal.editAppTitlePrefix\", \"Edit:\")} ${app.name}`}\n description={tr(\n \"devportal.editAppDescription\",\n \"Update your application settings\",\n )}\n backLink={`${basePath}/apps/${app.id}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n actions={\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={app.status} type=\"app\" />\n </div>\n }\n >\n <form onSubmit={handleSubmit} className=\"space-y-8 max-w-3xl\">\n {/* Status banner for published apps */}\n {app.status === \"PUBLISHED\" && (\n <div className=\"rounded-lg border border-border-subtle bg-status-warning-bg-subtle p-4 flex gap-3\">\n <AlertTriangle\n size={20}\n className=\"text-status-warning-text flex-shrink-0 mt-0.5\"\n />\n <div className=\"text-sm text-status-warning-text\">\n <p className=\"font-medium\">\n {tr(\n \"devportal.appIsPublished\",\n \"This application is published\",\n )}\n </p>\n <p className=\"mt-1 text-status-warning-text\">\n {tr(\n \"devportal.publishedAppChangesWarning\",\n \"Changes to published apps may require re-review. Major changes will put the app back into review status.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {/* Basic Information */}\n <PageSection\n title={tr(\"devportal.basicInformation\", \"Basic Information\")}\n description={tr(\n \"devportal.basicInformationDescription\",\n \"Core details about your application\",\n )}\n >\n <div className=\"space-y-4\">\n <InputField\n label={tr(\"devportal.applicationName\", \"Application Name\")}\n value={formData.name}\n onChange={(e) => handleChange(\"name\", e.target.value)}\n placeholder={tr(\n \"devportal.applicationNamePlaceholder\",\n \"My Awesome App\",\n )}\n required\n error={errors.name}\n />\n\n <InputField\n label={tr(\"devportal.slug\", \"Slug\")}\n value={formData.slug}\n onChange={(e) =>\n handleChange(\"slug\", e.target.value.toLowerCase())\n }\n placeholder={tr(\"devportal.slugPlaceholder\", \"my-awesome-app\")}\n required\n error={errors.slug}\n hint={tr(\n \"devportal.slugChangeWarning\",\n \"Changing the slug may break existing integrations\",\n )}\n />\n\n <TextareaField\n label={tr(\"devportal.shortDescription\", \"Short Description\")}\n value={formData.shortDescription}\n onChange={(e) =>\n handleChange(\"shortDescription\", e.target.value)\n }\n placeholder={tr(\n \"devportal.shortDescriptionPlaceholder\",\n \"A brief description of what your app does\",\n )}\n required\n error={errors.shortDescription}\n hint={`${formData.shortDescription.length}/200 ${tr(\"devportal.characters\", \"characters\")}`}\n rows={2}\n />\n\n <TextareaField\n label={tr(\"devportal.fullDescription\", \"Full Description\")}\n value={formData.description}\n onChange={(e) => handleChange(\"description\", e.target.value)}\n placeholder={tr(\n \"devportal.fullDescriptionPlaceholder\",\n \"Detailed description of your application, features, and use cases...\",\n )}\n rows={6}\n hint={tr(\n \"devportal.markdownSupported\",\n \"Markdown formatting is supported\",\n )}\n />\n </div>\n </PageSection>\n\n {/* Classification */}\n <PageSection\n title={tr(\"devportal.classification\", \"Classification\")}\n description={tr(\n \"devportal.classificationDescription\",\n \"Categorize your application\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <SelectField\n label={tr(\"devportal.applicationType\", \"Application Type\")}\n value={formData.appType}\n onChange={(e) => handleChange(\"appType\", e.target.value)}\n options={APP_TYPE_OPTIONS}\n required\n error={errors.appType}\n />\n\n <SelectField\n label={tr(\"devportal.category\", \"Category\")}\n value={formData.category}\n onChange={(e) => handleChange(\"category\", e.target.value)}\n options={CATEGORY_OPTIONS}\n required\n error={errors.category}\n />\n\n <SelectField\n label={tr(\"devportal.visibility\", \"Visibility\")}\n value={formData.visibility}\n onChange={(e) =>\n handleChange(\"visibility\", e.target.value as AppVisibility)\n }\n options={VISIBILITY_OPTIONS}\n hint={tr(\n \"devportal.visibilityHint\",\n \"Controls who can see this app once published. Public apps still require admin review and approval before appearing in the store.\",\n )}\n />\n </div>\n\n <TagInput\n label={tr(\"devportal.tags\", \"Tags\")}\n value={formData.tags}\n onChange={(tags) => handleChange(\"tags\", tags)}\n placeholder={tr(\n \"devportal.addTagsPlaceholder\",\n \"Add tags (press Enter)\",\n )}\n />\n\n <TagInput\n label={tr(\"devportal.keywords\", \"Keywords\")}\n value={formData.keywords}\n onChange={(keywords) => handleChange(\"keywords\", keywords)}\n placeholder={tr(\n \"devportal.addKeywordsPlaceholder\",\n \"Add keywords (press Enter)\",\n )}\n />\n </PageSection>\n\n {/* URLs */}\n <PageSection\n title={tr(\"devportal.links\", \"Links\")}\n description={tr(\n \"devportal.linksDescription\",\n \"External resources for your application\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.websiteUrl\", \"Website URL\")}\n type=\"url\"\n value={formData.websiteUrl}\n onChange={(e) => handleChange(\"websiteUrl\", e.target.value)}\n placeholder={tr(\n \"devportal.websiteUrlPlaceholder\",\n \"https://example.com\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.documentationUrl\", \"Documentation URL\")}\n type=\"url\"\n value={formData.documentationUrl}\n onChange={(e) =>\n handleChange(\"documentationUrl\", e.target.value)\n }\n placeholder={tr(\n \"devportal.documentationUrlPlaceholder\",\n \"https://docs.example.com\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.supportUrl\", \"Support URL\")}\n type=\"url\"\n value={formData.supportUrl}\n onChange={(e) => handleChange(\"supportUrl\", e.target.value)}\n placeholder={tr(\n \"devportal.supportUrlPlaceholder\",\n \"https://support.example.com\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.githubUrl\", \"GitHub URL\")}\n type=\"url\"\n value={formData.githubUrl}\n onChange={(e) => handleChange(\"githubUrl\", e.target.value)}\n placeholder={tr(\n \"devportal.githubUrlPlaceholder\",\n \"https://github.com/org/repo\",\n )}\n />\n\n <InputField\n label={tr(\"devportal.privacyPolicyUrl\", \"Privacy Policy URL\")}\n type=\"url\"\n value={formData.privacyPolicyUrl}\n onChange={(e) =>\n handleChange(\"privacyPolicyUrl\", e.target.value)\n }\n placeholder={tr(\n \"devportal.privacyPolicyUrlPlaceholder\",\n \"https://example.com/privacy\",\n )}\n />\n\n <InputField\n label={tr(\n \"devportal.termsOfServiceUrl\",\n \"Terms of Service URL\",\n )}\n type=\"url\"\n value={formData.termsOfServiceUrl}\n onChange={(e) =>\n handleChange(\"termsOfServiceUrl\", e.target.value)\n }\n placeholder={tr(\n \"devportal.termsOfServiceUrlPlaceholder\",\n \"https://example.com/terms\",\n )}\n />\n </div>\n </PageSection>\n\n {/* Settings */}\n <PageSection\n title={tr(\"devportal.settings\", \"Settings\")}\n description={tr(\n \"devportal.settingsDescription\",\n \"Additional configuration options\",\n )}\n >\n <div className=\"space-y-4\">\n <CheckboxField\n label={tr(\n \"devportal.requireWorkspaceAdminApproval\",\n \"Require workspace admin approval\",\n )}\n description={tr(\n \"devportal.requireWorkspaceAdminApprovalDescription\",\n \"When enabled, workspace admins must approve installations before users can access this app\",\n )}\n checked={formData.requiresApproval}\n onChange={(e) =>\n handleChange(\"requiresApproval\", e.target.checked)\n }\n />\n </div>\n </PageSection>\n\n {/* Actions */}\n <div className=\"flex flex-col gap-4 border-t pt-6\">\n {/* Primary actions */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n {canSubmitForReview && (\n <button\n type=\"button\"\n onClick={handleSubmitForReview}\n disabled={hasChanges}\n title={hasChanges ? \"Save your changes first\" : undefined}\n className=\"inline-flex items-center gap-2 rounded-md border border-primary bg-primary/10 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/20 transition-colors disabled:opacity-50\"\n >\n <Send size={16} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </button>\n )}\n </div>\n <button\n type=\"submit\"\n disabled={isSubmitting || !hasChanges || !canUpdate}\n aria-disabled={!canUpdate}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {isSubmitting ? (\n <>\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n {tr(\"devportal.saving\", \"Saving...\")}\n </>\n ) : (\n <>\n <Save size={16} />\n {tr(\"devportal.saveChanges\", \"Save Changes\")}\n </>\n )}\n </button>\n </div>\n\n {/* Danger zone */}\n <div className=\"rounded-lg border border-border-subtle bg-status-error-bg-subtle p-4\">\n <h3 className=\"text-sm font-medium text-status-error-text\">\n {tr(\"devportal.dangerZone\", \"Danger Zone\")}\n </h3>\n <p className=\"mt-1 text-sm text-status-error-text\">\n {tr(\n \"devportal.dangerZoneWarning\",\n \"These actions are irreversible. Please proceed with caution.\",\n )}\n </p>\n <div className=\"mt-4 flex gap-3\">\n {canDeprecate && (\n <button\n type=\"button\"\n onClick={() => setShowDeprecateDialog(true)}\n className=\"inline-flex items-center gap-2 rounded-md border border-accent-orange bg-bg-surface px-3 py-1.5 text-sm font-medium text-accent-orange hover:bg-accent-orange-subtle transition-colors\"\n >\n <Archive size={14} />\n {tr(\"devportal.deprecateApp\", \"Deprecate App\")}\n </button>\n )}\n {canDeactivate && (\n <button\n type=\"button\"\n onClick={() => setShowDeactivateDialog(true)}\n className=\"inline-flex items-center gap-2 rounded-md border border-accent-orange bg-bg-surface px-3 py-1.5 text-sm font-medium text-accent-orange hover:bg-accent-orange-subtle transition-colors\"\n >\n <Power size={14} />\n {tr(\"devportal.deactivateApp\", \"Deactivate App\")}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => setShowDeleteDialog(true)}\n disabled={!canDelete}\n aria-disabled={!canDelete}\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg bg-bg-surface px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50\"\n >\n <Trash2 size={14} />\n {tr(\"devportal.deleteApp\", \"Delete App\")}\n </button>\n </div>\n </div>\n </div>\n </form>\n\n {/* Delete confirmation dialog */}\n <ConfirmDialog\n open={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n title={tr(\"devportal.deleteApplication\", \"Delete Application\")}\n description={tr(\n \"devportal.deleteApplicationConfirm\",\n `Are you sure you want to delete \"${app.name}\"? This action cannot be undone. All OAuth clients, API keys, webhooks, and analytics data will be permanently deleted.`,\n )}\n confirmLabel={tr(\"devportal.deleteApplication\", \"Delete Application\")}\n variant=\"destructive\"\n onConfirm={handleDelete}\n />\n\n {/* Deprecate confirmation dialog */}\n <ConfirmDialog\n open={showDeprecateDialog}\n onOpenChange={setShowDeprecateDialog}\n title={tr(\"devportal.deprecateApplication\", \"Deprecate Application\")}\n description={tr(\n \"devportal.deprecateApplicationConfirm\",\n `Are you sure you want to deprecate \"${app.name}\"? Existing users will still be able to use the app, but it will no longer be visible in the marketplace and new installations will be disabled.`,\n )}\n confirmLabel={tr(\n \"devportal.deprecateApplication\",\n \"Deprecate Application\",\n )}\n variant=\"warning\"\n onConfirm={handleDeprecate}\n />\n\n {/* Deactivate confirmation dialog */}\n <ConfirmDialog\n open={showDeactivateDialog}\n onOpenChange={setShowDeactivateDialog}\n title={tr(\n \"devportal.deactivateApplication\",\n \"Deactivate Application\",\n )}\n description={tr(\n \"devportal.deactivateApplicationConfirm\",\n `Are you sure you want to deactivate \"${app.name}\"? This will revoke all active tokens and disable the app from the auth-svc layer. The app will no longer be able to authenticate or act on behalf of users.`,\n )}\n confirmLabel={tr(\n \"devportal.deactivateApplication\",\n \"Deactivate Application\",\n )}\n variant=\"destructive\"\n onConfirm={handleDeactivate}\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|