@burdenoff/microfe-devportal 2026.629.7 → 2026.629.9

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.
@@ -7,21 +7,21 @@ import { APP_STATUS_COLORS as ne, APP_TYPE_LABELS as re } from "../utils/constan
7
7
  import { SelectionCheckbox as ie } from "../components/SelectionCheckbox.js";
8
8
  import { AppCard as ae, AppListItem as oe } from "../components/AppCard.js";
9
9
  import { ConfirmDialog as a } from "../components/ConfirmDialog.js";
10
- import { PermissionGuard as se } from "../components/PermissionGuard.js";
10
+ import { PermissionGuard as o } from "../components/PermissionGuard.js";
11
11
  import "../components/index.js";
12
- import { DEVPORTAL_PERMISSIONS as o } from "../constants/permissions.js";
13
- import { useDevportalPermission as s } from "../hooks/usePermission.js";
12
+ import { DEVPORTAL_PERMISSIONS as s } from "../constants/permissions.js";
13
+ import { useDevportalPermission as c } from "../hooks/usePermission.js";
14
14
  import "../hooks/index.js";
15
- import { useMemo as c, useState as l } from "react";
16
- import { useI18n as ce } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
17
- import { AlertCircle as u, AppWindow as d, Archive as f, Grid as p, List as m, Loader2 as le, Plus as h, Search as ue, Trash2 as de } from "lucide-react";
18
- import { jsx as g, jsxs as _ } from "react/jsx-runtime";
19
- import { EmphasisPanel as fe, GlassCard as v } from "@burdenoff/fe-libs/ui";
15
+ import { useMemo as l, useState as u } from "react";
16
+ import { useI18n as se } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
17
+ import { AlertCircle as d, AppWindow as f, Archive as p, Grid as m, List as h, Loader2 as ce, Plus as g, Search as le, Trash2 as ue } from "lucide-react";
18
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
19
+ import { EmphasisPanel as de, GlassCard as y } from "@burdenoff/fe-libs/ui";
20
20
  //#region src/devportal/pages/ApplicationsPage.tsx
21
- function y(e, t, n) {
21
+ function b(e, t, n) {
22
22
  return `${e} ${t} application${t === 1 ? "" : "s"}${n > 0 ? ` • ${n} failed` : ""}`;
23
23
  }
24
- function pe(e) {
24
+ function fe(e) {
25
25
  let t = Array.isArray(e.screenshots) ? e.screenshots.length > 0 ? e.screenshots : void 0 : e.screenshots, n = e.pricingDetails && typeof e.pricingDetails == "object" ? e.pricingDetails : void 0;
26
26
  return {
27
27
  id: e.id,
@@ -67,193 +67,194 @@ function pe(e) {
67
67
  updatedAt: e.updatedAt
68
68
  };
69
69
  }
70
- var b = () => {
71
- let { navigate: b, basePath: x, activeOrgId: S } = e(), { t: C } = ce(), w = (e, t) => {
72
- let n = C(e);
70
+ var x = () => {
71
+ let { navigate: x, basePath: S, activeOrgId: C } = e(), { t: pe } = se(), w = (e, t) => {
72
+ let n = pe(e);
73
73
  return n === e ? t : n;
74
- }, T = s(o.APP_CREATE), E = s(o.APP_DELETE), D = s(o.APP_UPDATE), [O, k] = l("grid"), [A, me] = l(""), [j, M] = l(""), [N, P] = l(""), [F, I] = l(/* @__PURE__ */ new Set()), [L, R] = l(null), [z, B] = l(null), { data: V, loading: he, error: H, refetch: U } = ee({
74
+ }, T = c(s.APP_CREATE), E = c(s.APP_DELETE), D = c(s.APP_UPDATE), [O, k] = u("grid"), [A, j] = u(""), [M, N] = u(""), [P, F] = u(""), [I, L] = u(/* @__PURE__ */ new Set()), [R, z] = u(null), [B, V] = u(null), { data: H, loading: me, error: U, refetch: W } = ee({
75
75
  variables: {
76
76
  limit: 50,
77
77
  offset: 0,
78
- status: j || void 0
78
+ status: M || void 0,
79
+ organizationId: C ?? void 0
79
80
  },
80
81
  fetchPolicy: "cache-and-network"
81
- }), W = c(() => V?.applications?.edges?.map((e) => pe(e.node)) ?? [], [V?.applications?.edges]), [ge] = r(), [G] = n(), K = (e) => {
82
- b?.(`${x}${e}`);
83
- }, q = W.filter((e) => {
84
- let t = !S || e.developerOrganizationId === S, n = !A || e.name.toLowerCase().includes(A.toLowerCase()) || e.shortDescription?.toLowerCase().includes(A.toLowerCase()), r = !N || e.appType === N;
82
+ }), G = l(() => H?.applications?.edges?.map((e) => fe(e.node)) ?? [], [H?.applications?.edges]), [he] = r(), [ge] = n(), K = (e) => {
83
+ x?.(`${S}${e}`);
84
+ }, q = G.filter((e) => {
85
+ let t = !C || e.developerOrganizationId === C, n = !A || e.name.toLowerCase().includes(A.toLowerCase()) || e.shortDescription?.toLowerCase().includes(A.toLowerCase()), r = !P || e.appType === P;
85
86
  return t && n && r;
86
- }), J = c(() => ({
87
- total: V?.applications?.totalCount ?? W.length,
88
- active: W.filter((e) => e.status === "ACTIVE").length,
89
- draft: W.filter((e) => e.status === "DRAFT").length,
90
- published: W.filter((e) => e.status === "PUBLISHED").length
91
- }), [W, V?.applications?.totalCount]), Y = c(() => W.filter((e) => F.has(e.id)), [W, F]), X = c(() => Y.filter((e) => e.status !== "INACTIVE" && e.status !== "REVOKED"), [Y]), Z = q.length > 0 && q.every((e) => F.has(e.id)), _e = q.some((e) => F.has(e.id)) && !Z, Q = (e, t) => {
92
- I((n) => {
87
+ }), J = l(() => ({
88
+ total: H?.applications?.totalCount ?? q.length,
89
+ active: q.filter((e) => e.status === "ACTIVE").length,
90
+ draft: q.filter((e) => e.status === "DRAFT").length,
91
+ published: q.filter((e) => e.status === "PUBLISHED").length
92
+ }), [q, H?.applications?.totalCount]), Y = l(() => G.filter((e) => I.has(e.id)), [G, I]), X = l(() => Y.filter((e) => e.status !== "INACTIVE" && e.status !== "REVOKED"), [Y]), Z = q.length > 0 && q.every((e) => I.has(e.id)), _e = q.some((e) => I.has(e.id)) && !Z, Q = (e, t) => {
93
+ L((n) => {
93
94
  let r = new Set(n);
94
95
  return t ? r.add(e) : r.delete(e), r;
95
96
  });
96
97
  }, ve = (e) => {
97
- I((t) => {
98
+ L((t) => {
98
99
  let n = new Set(t);
99
100
  return q.forEach((t) => {
100
101
  e ? n.add(t.id) : n.delete(t.id);
101
102
  }), n;
102
103
  });
103
- }, $ = () => I(/* @__PURE__ */ new Set());
104
- return he && !V ? /* @__PURE__ */ g(i, {
104
+ }, $ = () => L(/* @__PURE__ */ new Set());
105
+ return me && !H ? /* @__PURE__ */ _(i, {
105
106
  title: w("devportal.myApplications", "My Applications"),
106
107
  description: w("devportal.manageYourApps", "Manage your developer applications"),
107
- children: /* @__PURE__ */ _("div", {
108
+ children: /* @__PURE__ */ v("div", {
108
109
  className: "flex items-center justify-center py-12",
109
- children: [/* @__PURE__ */ g(le, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ g("span", {
110
+ children: [/* @__PURE__ */ _(ce, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ _("span", {
110
111
  className: "ml-2 text-text-secondary",
111
112
  children: w("devportal.loadingApplications", "Loading applications...")
112
113
  })]
113
114
  })
114
- }) : H ? /* @__PURE__ */ g(i, {
115
+ }) : U ? /* @__PURE__ */ _(i, {
115
116
  title: w("devportal.myApplications", "My Applications"),
116
117
  description: w("devportal.manageYourApps", "Manage your developer applications"),
117
- children: /* @__PURE__ */ _("div", {
118
+ children: /* @__PURE__ */ v("div", {
118
119
  className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
119
120
  children: [
120
- /* @__PURE__ */ g(u, { className: "mx-auto h-8 w-8 text-status-error-text" }),
121
- /* @__PURE__ */ g("h3", {
121
+ /* @__PURE__ */ _(d, { className: "mx-auto h-8 w-8 text-status-error-text" }),
122
+ /* @__PURE__ */ _("h3", {
122
123
  className: "mt-2 font-medium text-status-error-text",
123
124
  children: w("devportal.failedToLoadApplications", "Failed to load applications")
124
125
  }),
125
- /* @__PURE__ */ g("p", {
126
+ /* @__PURE__ */ _("p", {
126
127
  className: "mt-1 text-sm text-text-secondary",
127
- children: te(H)
128
+ children: te(U)
128
129
  }),
129
- /* @__PURE__ */ g("button", {
130
- onClick: () => U(),
130
+ /* @__PURE__ */ _("button", {
131
+ onClick: () => W(),
131
132
  className: "mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
132
133
  children: w("devportal.tryAgain", "Try Again")
133
134
  })
134
135
  ]
135
136
  })
136
- }) : /* @__PURE__ */ g(se, {
137
- permission: o.APP_READ,
138
- children: /* @__PURE__ */ _(i, {
137
+ }) : /* @__PURE__ */ _(o, {
138
+ permission: s.APP_READ,
139
+ children: /* @__PURE__ */ v(i, {
139
140
  title: w("devportal.myApplications", "My Applications"),
140
141
  description: w("devportal.manageYourApps", "Manage your developer applications"),
141
142
  purpose: w("devportal.applicationsPurpose", "Applications are the integrations you build on the platform — OAuth apps, store listings, and API consumers. Create one here to get client credentials, request scopes, and ship to the marketplace."),
142
- actions: /* @__PURE__ */ _("button", {
143
+ actions: /* @__PURE__ */ v("button", {
143
144
  onClick: () => K("/apps/new"),
144
145
  disabled: !T.allowed,
145
146
  "aria-disabled": !T.allowed,
146
147
  title: T.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
147
148
  className: "inline-flex items-center gap-2 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 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
148
- children: [/* @__PURE__ */ g(h, {
149
+ children: [/* @__PURE__ */ _(g, {
149
150
  size: 16,
150
151
  "aria-hidden": "true"
151
152
  }), w("devportal.createApp", "Create App")]
152
153
  }),
153
154
  children: [
154
- /* @__PURE__ */ _("div", {
155
+ /* @__PURE__ */ v("div", {
155
156
  className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
156
- children: [/* @__PURE__ */ _("div", {
157
+ children: [/* @__PURE__ */ v("div", {
157
158
  className: "flex flex-1 items-center gap-4",
158
159
  children: [
159
- /* @__PURE__ */ _("div", {
160
+ /* @__PURE__ */ v("div", {
160
161
  className: "relative flex-1 max-w-md",
161
- children: [/* @__PURE__ */ g(ue, {
162
+ children: [/* @__PURE__ */ _(le, {
162
163
  size: 16,
163
164
  className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary"
164
- }), /* @__PURE__ */ g("input", {
165
+ }), /* @__PURE__ */ _("input", {
165
166
  type: "text",
166
167
  placeholder: w("devportal.searchApplications", "Search applications..."),
167
168
  value: A,
168
- onChange: (e) => me(e.target.value),
169
+ onChange: (e) => j(e.target.value),
169
170
  className: "w-full rounded-md border bg-bg-surface pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
170
171
  })]
171
172
  }),
172
- /* @__PURE__ */ _("select", {
173
- value: j,
174
- onChange: (e) => M(e.target.value),
173
+ /* @__PURE__ */ v("select", {
174
+ value: M,
175
+ onChange: (e) => N(e.target.value),
175
176
  className: "rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
176
- children: [/* @__PURE__ */ g("option", {
177
+ children: [/* @__PURE__ */ _("option", {
177
178
  value: "",
178
179
  children: w("devportal.allStatus", "All Status")
179
- }), Object.keys(ne).map((e) => /* @__PURE__ */ g("option", {
180
+ }), Object.keys(ne).map((e) => /* @__PURE__ */ _("option", {
180
181
  value: e,
181
182
  children: e.replace(/_/g, " ")
182
183
  }, e))]
183
184
  }),
184
- /* @__PURE__ */ _("select", {
185
- value: N,
186
- onChange: (e) => P(e.target.value),
185
+ /* @__PURE__ */ v("select", {
186
+ value: P,
187
+ onChange: (e) => F(e.target.value),
187
188
  className: "rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
188
- children: [/* @__PURE__ */ g("option", {
189
+ children: [/* @__PURE__ */ _("option", {
189
190
  value: "",
190
191
  children: w("devportal.allTypes", "All Types")
191
- }), Object.entries(re).map(([e, t]) => /* @__PURE__ */ g("option", {
192
+ }), Object.entries(re).map(([e, t]) => /* @__PURE__ */ _("option", {
192
193
  value: e,
193
194
  children: t
194
195
  }, e))]
195
196
  })
196
197
  ]
197
- }), /* @__PURE__ */ _("div", {
198
+ }), /* @__PURE__ */ v("div", {
198
199
  className: "flex items-center gap-1 rounded-md border p-1",
199
- children: [/* @__PURE__ */ g("button", {
200
+ children: [/* @__PURE__ */ _("button", {
200
201
  onClick: () => k("grid"),
201
202
  className: `rounded p-1.5 ${O === "grid" ? "bg-bg-sunken" : "hover:bg-bg-sunken/50"}`,
202
203
  title: "Grid view",
203
- children: /* @__PURE__ */ g(p, { size: 16 })
204
- }), /* @__PURE__ */ g("button", {
204
+ children: /* @__PURE__ */ _(m, { size: 16 })
205
+ }), /* @__PURE__ */ _("button", {
205
206
  onClick: () => k("list"),
206
207
  className: `rounded p-1.5 ${O === "list" ? "bg-bg-sunken" : "hover:bg-bg-sunken/50"}`,
207
208
  title: "List view",
208
- children: /* @__PURE__ */ g(m, { size: 16 })
209
+ children: /* @__PURE__ */ _(h, { size: 16 })
209
210
  })]
210
211
  })]
211
212
  }),
212
- /* @__PURE__ */ g(fe, {
213
+ /* @__PURE__ */ _(de, {
213
214
  className: "mt-4",
214
- children: /* @__PURE__ */ _("div", {
215
+ children: /* @__PURE__ */ v("div", {
215
216
  className: "grid grid-cols-2 gap-4 sm:grid-cols-4",
216
217
  children: [
217
- /* @__PURE__ */ _(v, {
218
+ /* @__PURE__ */ v(y, {
218
219
  treatment: "metric",
219
220
  className: "p-4",
220
- children: [/* @__PURE__ */ g("p", {
221
+ children: [/* @__PURE__ */ _("p", {
221
222
  className: "text-sm text-text-secondary",
222
223
  children: w("devportal.totalApps", "Total Apps")
223
- }), /* @__PURE__ */ g("p", {
224
+ }), /* @__PURE__ */ _("p", {
224
225
  className: "mt-1 text-2xl font-semibold tabular-nums",
225
226
  children: J.total
226
227
  })]
227
228
  }),
228
- /* @__PURE__ */ _(v, {
229
+ /* @__PURE__ */ v(y, {
229
230
  treatment: "metric",
230
231
  className: "p-4",
231
- children: [/* @__PURE__ */ g("p", {
232
+ children: [/* @__PURE__ */ _("p", {
232
233
  className: "text-sm text-status-success-text",
233
234
  children: w("devportal.active", "Active")
234
- }), /* @__PURE__ */ g("p", {
235
+ }), /* @__PURE__ */ _("p", {
235
236
  className: "mt-1 text-2xl font-semibold tabular-nums",
236
237
  children: J.active
237
238
  })]
238
239
  }),
239
- /* @__PURE__ */ _(v, {
240
+ /* @__PURE__ */ v(y, {
240
241
  treatment: "metric",
241
242
  className: "p-4",
242
- children: [/* @__PURE__ */ g("p", {
243
+ children: [/* @__PURE__ */ _("p", {
243
244
  className: "text-sm text-text-secondary",
244
245
  children: w("devportal.published", "Published")
245
- }), /* @__PURE__ */ g("p", {
246
+ }), /* @__PURE__ */ _("p", {
246
247
  className: "mt-1 text-2xl font-semibold tabular-nums",
247
248
  children: J.published
248
249
  })]
249
250
  }),
250
- /* @__PURE__ */ _(v, {
251
+ /* @__PURE__ */ v(y, {
251
252
  treatment: "metric",
252
253
  className: "p-4",
253
- children: [/* @__PURE__ */ g("p", {
254
+ children: [/* @__PURE__ */ _("p", {
254
255
  className: "text-sm text-text-secondary",
255
256
  children: w("devportal.draft", "Draft")
256
- }), /* @__PURE__ */ g("p", {
257
+ }), /* @__PURE__ */ _("p", {
257
258
  className: "mt-1 text-2xl font-semibold tabular-nums",
258
259
  children: J.draft
259
260
  })]
@@ -261,54 +262,54 @@ var b = () => {
261
262
  ]
262
263
  })
263
264
  }),
264
- z && /* @__PURE__ */ g("div", {
265
- className: `rounded-lg border px-4 py-3 text-sm ${z.type === "success" ? "border-border-subtle bg-status-success-bg-subtle text-status-success-text" : "border-status-error-border/40 bg-status-error-bg/10 text-status-error-text"}`,
266
- children: /* @__PURE__ */ _("div", {
265
+ B && /* @__PURE__ */ _("div", {
266
+ className: `rounded-lg border px-4 py-3 text-sm ${B.type === "success" ? "border-border-subtle bg-status-success-bg-subtle text-status-success-text" : "border-status-error-border/40 bg-status-error-bg/10 text-status-error-text"}`,
267
+ children: /* @__PURE__ */ v("div", {
267
268
  className: "flex items-center justify-between gap-3",
268
- children: [/* @__PURE__ */ g("span", { children: z.message }), /* @__PURE__ */ g("button", {
269
- onClick: () => B(null),
269
+ children: [/* @__PURE__ */ _("span", { children: B.message }), /* @__PURE__ */ _("button", {
270
+ onClick: () => V(null),
270
271
  className: "text-xs font-medium underline underline-offset-2",
271
272
  children: "Dismiss"
272
273
  })]
273
274
  })
274
275
  }),
275
- q.length > 0 && /* @__PURE__ */ g("div", {
276
+ q.length > 0 && /* @__PURE__ */ _("div", {
276
277
  className: "rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-pop)]",
277
- children: /* @__PURE__ */ _("div", {
278
+ children: /* @__PURE__ */ v("div", {
278
279
  className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",
279
- children: [/* @__PURE__ */ _("div", {
280
+ children: [/* @__PURE__ */ v("div", {
280
281
  className: "flex flex-wrap items-center gap-3",
281
- children: [/* @__PURE__ */ _("div", {
282
+ children: [/* @__PURE__ */ v("div", {
282
283
  className: "flex items-center gap-2",
283
- children: [/* @__PURE__ */ g(ie, {
284
+ children: [/* @__PURE__ */ _(ie, {
284
285
  checked: Z,
285
286
  indeterminate: _e,
286
287
  onChange: ve,
287
288
  ariaLabel: "Select all visible applications"
288
- }), /* @__PURE__ */ g("span", {
289
+ }), /* @__PURE__ */ _("span", {
289
290
  className: "text-sm font-medium",
290
291
  children: "Select all visible"
291
292
  })]
292
- }), F.size > 0 && /* @__PURE__ */ g("button", {
293
+ }), I.size > 0 && /* @__PURE__ */ _("button", {
293
294
  onClick: $,
294
295
  className: "text-sm text-text-secondary hover:text-text-primary",
295
296
  children: "Clear selection"
296
297
  })]
297
- }), /* @__PURE__ */ _("div", {
298
+ }), /* @__PURE__ */ v("div", {
298
299
  className: "flex flex-wrap items-center gap-2",
299
300
  children: [
300
- /* @__PURE__ */ _("span", {
301
+ /* @__PURE__ */ v("span", {
301
302
  className: "rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary",
302
- children: [F.size, " selected"]
303
+ children: [I.size, " selected"]
303
304
  }),
304
- /* @__PURE__ */ _("button", {
305
- onClick: () => R("deactivate"),
305
+ /* @__PURE__ */ v("button", {
306
+ onClick: () => z("deactivate"),
306
307
  disabled: X.length === 0 || !D.allowed,
307
308
  "aria-disabled": X.length === 0 || !D.allowed,
308
309
  title: D.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
309
310
  className: "inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
310
311
  children: [
311
- /* @__PURE__ */ g(f, {
312
+ /* @__PURE__ */ _(p, {
312
313
  size: 16,
313
314
  "aria-hidden": "true"
314
315
  }),
@@ -316,14 +317,14 @@ var b = () => {
316
317
  X.length > 0 ? ` (${X.length})` : ""
317
318
  ]
318
319
  }),
319
- /* @__PURE__ */ _("button", {
320
- onClick: () => R("delete"),
320
+ /* @__PURE__ */ v("button", {
321
+ onClick: () => z("delete"),
321
322
  disabled: Y.length === 0 || !E.allowed,
322
323
  "aria-disabled": Y.length === 0 || !E.allowed,
323
324
  title: E.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
324
325
  className: "inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
325
326
  children: [
326
- /* @__PURE__ */ g(de, {
327
+ /* @__PURE__ */ _(ue, {
327
328
  size: 16,
328
329
  "aria-hidden": "true"
329
330
  }),
@@ -335,7 +336,7 @@ var b = () => {
335
336
  })]
336
337
  })
337
338
  }),
338
- /* @__PURE__ */ _("p", {
339
+ /* @__PURE__ */ v("p", {
339
340
  className: "text-sm text-text-secondary",
340
341
  children: [
341
342
  q.length,
@@ -344,43 +345,43 @@ var b = () => {
344
345
  " found"
345
346
  ]
346
347
  }),
347
- q.length > 0 ? O === "grid" ? /* @__PURE__ */ g("div", {
348
+ q.length > 0 ? O === "grid" ? /* @__PURE__ */ _("div", {
348
349
  className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
349
- children: q.map((e) => /* @__PURE__ */ g(ae, {
350
+ children: q.map((e) => /* @__PURE__ */ _(ae, {
350
351
  app: e,
351
- selected: F.has(e.id),
352
+ selected: I.has(e.id),
352
353
  onToggleSelect: (t) => Q(e.id, t)
353
354
  }, e.id))
354
- }) : /* @__PURE__ */ g("div", {
355
+ }) : /* @__PURE__ */ _("div", {
355
356
  className: "space-y-2",
356
- children: q.map((e) => /* @__PURE__ */ g(oe, {
357
+ children: q.map((e) => /* @__PURE__ */ _(oe, {
357
358
  app: e,
358
- selected: F.has(e.id),
359
+ selected: I.has(e.id),
359
360
  onToggleSelect: (t) => Q(e.id, t)
360
361
  }, e.id))
361
- }) : /* @__PURE__ */ g(t, {
362
- illustration: A || j || N ? "empty-search" : "empty-data",
363
- icon: /* @__PURE__ */ g(d, { size: 32 }),
362
+ }) : /* @__PURE__ */ _(t, {
363
+ illustration: A || M || P ? "empty-search" : "empty-data",
364
+ icon: /* @__PURE__ */ _(f, { size: 32 }),
364
365
  title: w("devportal.noApplicationsFound", "No applications found"),
365
- description: A || j || N ? w("devportal.tryAdjustingFilters", "Try adjusting your filters") : w("devportal.createFirstApp", "Create your first application to get started"),
366
- action: !A && !j && !N ? /* @__PURE__ */ _("button", {
366
+ description: A || M || P ? w("devportal.tryAdjustingFilters", "Try adjusting your filters") : w("devportal.createFirstApp", "Create your first application to get started"),
367
+ action: !A && !M && !P ? /* @__PURE__ */ v("button", {
367
368
  onClick: () => K("/apps/new"),
368
369
  className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
369
- children: [/* @__PURE__ */ g(h, { size: 16 }), w("devportal.createApp", "Create App")]
370
+ children: [/* @__PURE__ */ _(g, { size: 16 }), w("devportal.createApp", "Create App")]
370
371
  }) : void 0
371
372
  }),
372
- /* @__PURE__ */ g(a, {
373
- open: L === "deactivate",
373
+ /* @__PURE__ */ _(a, {
374
+ open: R === "deactivate",
374
375
  onOpenChange: (e) => {
375
- e || R(null);
376
+ e || z(null);
376
377
  },
377
378
  onConfirm: async () => {
378
379
  if (X.length === 0) return;
379
- let e = await Promise.allSettled(X.map((e) => G({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
380
- B({
380
+ let e = await Promise.allSettled(X.map((e) => ge({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
381
+ V({
381
382
  type: n === 0 ? "success" : "error",
382
- message: y("Deactivated", t, n)
383
- }), $(), R(null), await U();
383
+ message: b("Deactivated", t, n)
384
+ }), $(), z(null), await W();
384
385
  },
385
386
  title: "Deactivate selected applications",
386
387
  description: `Deactivate ${X.length} selected application${X.length === 1 ? "" : "s"}? Users and integrations may lose access until these apps are re-enabled.`,
@@ -388,18 +389,18 @@ var b = () => {
388
389
  cancelLabel: "Cancel",
389
390
  variant: "warning"
390
391
  }),
391
- /* @__PURE__ */ g(a, {
392
- open: L === "delete",
392
+ /* @__PURE__ */ _(a, {
393
+ open: R === "delete",
393
394
  onOpenChange: (e) => {
394
- e || R(null);
395
+ e || z(null);
395
396
  },
396
397
  onConfirm: async () => {
397
398
  if (Y.length === 0) return;
398
- let e = await Promise.allSettled(Y.map((e) => ge({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
399
- B({
399
+ let e = await Promise.allSettled(Y.map((e) => he({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
400
+ V({
400
401
  type: n === 0 ? "success" : "error",
401
- message: y("Deleted", t, n)
402
- }), $(), R(null), await U();
402
+ message: b("Deleted", t, n)
403
+ }), $(), z(null), await W();
403
404
  },
404
405
  title: "Delete selected applications",
405
406
  description: `Delete ${Y.length} selected application${Y.length === 1 ? "" : "s"}? This cannot be undone.`,
@@ -412,6 +413,6 @@ var b = () => {
412
413
  });
413
414
  };
414
415
  //#endregion
415
- export { b as ApplicationsPage };
416
+ export { x as ApplicationsPage };
416
417
 
417
418
  //# sourceMappingURL=ApplicationsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n Trash2,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard, AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\ntype BulkAction = \"delete\" | \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: \"Deleted\" | \"Deactivated\",\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\n/**\n * Map GraphQL application to local Application type\n */\nfunction mapApplication(app: ApplicationFieldsFragment): Application {\n // Convert screenshots array to Record if needed\n const screenshots = Array.isArray(app.screenshots)\n ? app.screenshots.length > 0\n ? (app.screenshots as unknown as Record<string, unknown>)\n : undefined\n : (app.screenshots as Record<string, unknown> | undefined);\n\n // Convert pricingDetails\n const pricingDetails =\n app.pricingDetails && typeof app.pricingDetails === \"object\"\n ? (app.pricingDetails as Record<string, unknown>)\n : undefined;\n\n return {\n id: app.id,\n name: app.name,\n slug: app.slug,\n description: app.description ?? undefined,\n shortDescription: app.shortDescription ?? undefined,\n appType: app.appType as AppType,\n status: app.status as AppStatus,\n visibility: app.visibility as \"PUBLIC\" | \"PRIVATE\" | \"UNLISTED\",\n category: app.category ?? undefined,\n tags: app.tags ?? [],\n keywords: app.keywords ?? [],\n iconUrl: app.iconUrl ?? undefined,\n bannerUrl: app.bannerUrl ?? undefined,\n screenshots,\n videoUrl: app.videoUrl ?? undefined,\n websiteUrl: app.websiteUrl ?? undefined,\n documentationUrl: app.documentationUrl ?? undefined,\n supportUrl: app.supportUrl ?? undefined,\n privacyPolicyUrl: app.privacyPolicyUrl ?? undefined,\n termsOfServiceUrl: app.termsOfServiceUrl ?? undefined,\n githubUrl: app.githubUrl ?? undefined,\n pricingType: app.pricingType ?? undefined,\n pricingDetails,\n isVerified: app.isVerified,\n isFeatured: app.isFeatured,\n averageRating: app.averageRating ?? undefined,\n reviewCount: app.reviewCount ?? 0,\n installCount: app.installCount ?? 0,\n activeInstallCount: app.activeInstallCount ?? 0,\n requiresApproval: app.requiresApproval,\n reviewStatus: app.reviewStatus ?? undefined,\n reviewNotes: app.reviewNotes ?? undefined,\n reviewedBy: app.reviewedBy ?? undefined,\n lastReviewedAt: app.lastReviewedAt ?? undefined,\n submittedAt: app.submittedAt ?? undefined,\n publishedAt: app.publishedAt ?? undefined,\n developerId: app.developerId,\n developerOrganizationId: app.developerOrganizationId ?? undefined,\n tenantId: app.tenantId,\n createdAt: app.createdAt,\n updatedAt: app.updatedAt,\n };\n}\n\n/**\n * Applications listing page\n *\n * Displays all applications for the current developer.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const ApplicationsPage: FC = () => {\n const { navigate, basePath, activeOrgId } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const deletePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_DELETE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [statusFilter, setStatusFilter] = useState<AppStatus | \"\">(\"\");\n const [typeFilter, setTypeFilter] = useState<AppType | \"\">(\"\");\n const [selectedAppIds, setSelectedAppIds] = useState<Set<string>>(new Set());\n const [bulkAction, setBulkAction] = useState<BulkAction>(null);\n const [feedback, setFeedback] = useState<{\n type: \"success\" | \"error\";\n message: string;\n } | null>(null);\n\n // Fetch applications from GraphQL API\n const { data, loading, error, refetch } = useGetApplicationsQuery({\n variables: {\n limit: 50,\n offset: 0,\n status: statusFilter || undefined,\n },\n fetchPolicy: \"cache-and-network\",\n });\n\n const applications: Application[] = useMemo(\n () =>\n data?.applications?.edges?.map(\n (edge: { node: ApplicationFieldsFragment }) =>\n mapApplication(edge.node),\n ) ?? [],\n [data?.applications?.edges],\n );\n\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Client-side filtering: org scope + search + type (status filtered server-side)\n const filteredApps = applications.filter((app: Application) => {\n const matchesOrg =\n !activeOrgId || app.developerOrganizationId === activeOrgId;\n const matchesSearch =\n !searchQuery ||\n app.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n app.shortDescription?.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesType = !typeFilter || app.appType === typeFilter;\n return matchesOrg && matchesSearch && matchesType;\n });\n\n const appStats = useMemo(() => {\n const total = data?.applications?.totalCount ?? applications.length;\n const active = applications.filter(\n (app: Application) => app.status === \"ACTIVE\",\n ).length;\n const draft = applications.filter(\n (app: Application) => app.status === \"DRAFT\",\n ).length;\n const published = applications.filter(\n (app: Application) => app.status === \"PUBLISHED\",\n ).length;\n return { total, active, draft, published };\n }, [applications, data?.applications?.totalCount]);\n\n const selectedApps = useMemo(\n () => applications.filter((app: Application) => selectedAppIds.has(app.id)),\n [applications, selectedAppIds],\n );\n\n const deactivatableApps = useMemo(\n () =>\n selectedApps.filter(\n (app: Application) =>\n app.status !== \"INACTIVE\" && app.status !== \"REVOKED\",\n ),\n [selectedApps],\n );\n\n const allVisibleSelected =\n filteredApps.length > 0 &&\n filteredApps.every((app: Application) => selectedAppIds.has(app.id));\n const partiallySelected =\n filteredApps.some((app: Application) => selectedAppIds.has(app.id)) &&\n !allVisibleSelected;\n\n const toggleAppSelection = (appId: string, checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(appId);\n } else {\n next.delete(appId);\n }\n return next;\n });\n };\n\n const toggleAllVisible = (checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n filteredApps.forEach((app: Application) => {\n if (checked) {\n next.add(app.id);\n } else {\n next.delete(app.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedAppIds(new Set());\n\n const runBulkDeactivate = async () => {\n if (deactivatableApps.length === 0) return;\n\n const results = await Promise.allSettled(\n deactivatableApps.map((app: Application) =>\n deactivateApp({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deactivated\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n const runBulkDelete = async () => {\n if (selectedApps.length === 0) return;\n\n const results = await Promise.allSettled(\n selectedApps.map((app: Application) =>\n deleteApplication({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deleted\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingApplications\", \"Loading applications...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadApplications\",\n \"Failed to load applications\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n purpose={tr(\n \"devportal.applicationsPurpose\",\n \"Applications are the integrations you build on the platform — OAuth apps, store listings, and API consumers. Create one here to get client credentials, request scopes, and ship to the marketplace.\",\n )}\n actions={\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n disabled={!createPerm.allowed}\n aria-disabled={!createPerm.allowed}\n title={\n !createPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 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 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Plus size={16} aria-hidden=\"true\" />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n }\n >\n {/* Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-1 items-center gap-4\">\n {/* Search */}\n <div className=\"relative flex-1 max-w-md\">\n <Search\n size={16}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n />\n <input\n type=\"text\"\n placeholder={tr(\n \"devportal.searchApplications\",\n \"Search applications...\",\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border bg-bg-surface pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n\n {/* Status Filter */}\n <select\n value={statusFilter}\n onChange={(e) =>\n setStatusFilter(e.target.value as AppStatus | \"\")\n }\n className=\"rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\"devportal.allStatus\", \"All Status\")}\n </option>\n {Object.keys(APP_STATUS_COLORS).map((status) => (\n <option key={status} value={status}>\n {status.replace(/_/g, \" \")}\n </option>\n ))}\n </select>\n\n {/* Type Filter */}\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as AppType | \"\")}\n className=\"rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">{tr(\"devportal.allTypes\", \"All Types\")}</option>\n {Object.entries(APP_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <button\n onClick={() => setViewMode(\"grid\")}\n className={`rounded p-1.5 ${viewMode === \"grid\" ? \"bg-bg-sunken\" : \"hover:bg-bg-sunken/50\"}`}\n title=\"Grid view\"\n >\n <Grid size={16} />\n </button>\n <button\n onClick={() => setViewMode(\"list\")}\n className={`rounded p-1.5 ${viewMode === \"list\" ? \"bg-bg-sunken\" : \"hover:bg-bg-sunken/50\"}`}\n title=\"List view\"\n >\n <List size={16} />\n </button>\n </div>\n </div>\n\n {/* Summary Stats — primary emphasis zone */}\n <EmphasisPanel className=\"mt-4\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.totalApps\", \"Total Apps\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.total}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-status-success-text\">\n {tr(\"devportal.active\", \"Active\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.active}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.published\", \"Published\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.published}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.draft\", \"Draft\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.draft}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n\n {feedback && (\n <div\n className={`rounded-lg border px-4 py-3 text-sm ${\n feedback.type === \"success\"\n ? \"border-border-subtle bg-status-success-bg-subtle text-status-success-text\"\n : \"border-status-error-border/40 bg-status-error-bg/10 text-status-error-text\"\n }`}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span>{feedback.message}</span>\n <button\n onClick={() => setFeedback(null)}\n className=\"text-xs font-medium underline underline-offset-2\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {filteredApps.length > 0 && (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-pop)]\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisible}\n ariaLabel=\"Select all visible applications\"\n />\n <span className=\"text-sm font-medium\">\n Select all visible\n </span>\n </div>\n {selectedAppIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedAppIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"deactivate\")}\n disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n aria-disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n title={\n !updatePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Archive size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deactivateSelected\", \"Deactivate Selected\")}\n {deactivatableApps.length > 0\n ? ` (${deactivatableApps.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"delete\")}\n disabled={selectedApps.length === 0 || !deletePerm.allowed}\n aria-disabled={\n selectedApps.length === 0 || !deletePerm.allowed\n }\n title={\n !deletePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deleteSelected\", \"Delete Selected\")}\n {selectedApps.length > 0 ? ` (${selectedApps.length})` : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n {filteredApps.length} application\n {filteredApps.length !== 1 ? \"s\" : \"\"} found\n </p>\n\n {/* Applications */}\n {filteredApps.length > 0 ? (\n viewMode === \"grid\" ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {filteredApps.map((app: Application) => (\n <AppCard\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredApps.map((app: Application) => (\n <AppListItem\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n )\n ) : (\n <EmptyState\n illustration={\n searchQuery || statusFilter || typeFilter\n ? \"empty-search\"\n : \"empty-data\"\n }\n icon={<AppWindow size={32} />}\n title={tr(\"devportal.noApplicationsFound\", \"No applications found\")}\n description={\n searchQuery || statusFilter || typeFilter\n ? tr(\n \"devportal.tryAdjustingFilters\",\n \"Try adjusting your filters\",\n )\n : tr(\n \"devportal.createFirstApp\",\n \"Create your first application to get started\",\n )\n }\n action={\n !searchQuery && !statusFilter && !typeFilter ? (\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : undefined\n }\n />\n )}\n\n <ConfirmDialog\n open={bulkAction === \"deactivate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDeactivate}\n title=\"Deactivate selected applications\"\n description={`Deactivate ${deactivatableApps.length} selected application${deactivatableApps.length === 1 ? \"\" : \"s\"}? Users and integrations may lose access until these apps are re-enabled.`}\n confirmLabel=\"Deactivate\"\n cancelLabel=\"Cancel\"\n variant=\"warning\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"delete\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDelete}\n title=\"Delete selected applications\"\n description={`Delete ${selectedApps.length} selected application${selectedApps.length === 1 ? \"\" : \"s\"}? This cannot be undone.`}\n confirmLabel=\"Delete\"\n cancelLabel=\"Cancel\"\n variant=\"danger\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ApplicationsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n Trash2,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard, AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\ntype BulkAction = \"delete\" | \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: \"Deleted\" | \"Deactivated\",\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\n/**\n * Map GraphQL application to local Application type\n */\nfunction mapApplication(app: ApplicationFieldsFragment): Application {\n // Convert screenshots array to Record if needed\n const screenshots = Array.isArray(app.screenshots)\n ? app.screenshots.length > 0\n ? (app.screenshots as unknown as Record<string, unknown>)\n : undefined\n : (app.screenshots as Record<string, unknown> | undefined);\n\n // Convert pricingDetails\n const pricingDetails =\n app.pricingDetails && typeof app.pricingDetails === \"object\"\n ? (app.pricingDetails as Record<string, unknown>)\n : undefined;\n\n return {\n id: app.id,\n name: app.name,\n slug: app.slug,\n description: app.description ?? undefined,\n shortDescription: app.shortDescription ?? undefined,\n appType: app.appType as AppType,\n status: app.status as AppStatus,\n visibility: app.visibility as \"PUBLIC\" | \"PRIVATE\" | \"UNLISTED\",\n category: app.category ?? undefined,\n tags: app.tags ?? [],\n keywords: app.keywords ?? [],\n iconUrl: app.iconUrl ?? undefined,\n bannerUrl: app.bannerUrl ?? undefined,\n screenshots,\n videoUrl: app.videoUrl ?? undefined,\n websiteUrl: app.websiteUrl ?? undefined,\n documentationUrl: app.documentationUrl ?? undefined,\n supportUrl: app.supportUrl ?? undefined,\n privacyPolicyUrl: app.privacyPolicyUrl ?? undefined,\n termsOfServiceUrl: app.termsOfServiceUrl ?? undefined,\n githubUrl: app.githubUrl ?? undefined,\n pricingType: app.pricingType ?? undefined,\n pricingDetails,\n isVerified: app.isVerified,\n isFeatured: app.isFeatured,\n averageRating: app.averageRating ?? undefined,\n reviewCount: app.reviewCount ?? 0,\n installCount: app.installCount ?? 0,\n activeInstallCount: app.activeInstallCount ?? 0,\n requiresApproval: app.requiresApproval,\n reviewStatus: app.reviewStatus ?? undefined,\n reviewNotes: app.reviewNotes ?? undefined,\n reviewedBy: app.reviewedBy ?? undefined,\n lastReviewedAt: app.lastReviewedAt ?? undefined,\n submittedAt: app.submittedAt ?? undefined,\n publishedAt: app.publishedAt ?? undefined,\n developerId: app.developerId,\n developerOrganizationId: app.developerOrganizationId ?? undefined,\n tenantId: app.tenantId,\n createdAt: app.createdAt,\n updatedAt: app.updatedAt,\n };\n}\n\n/**\n * Applications listing page\n *\n * Displays all applications for the current developer.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const ApplicationsPage: FC = () => {\n const { navigate, basePath, activeOrgId } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const deletePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_DELETE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [statusFilter, setStatusFilter] = useState<AppStatus | \"\">(\"\");\n const [typeFilter, setTypeFilter] = useState<AppType | \"\">(\"\");\n const [selectedAppIds, setSelectedAppIds] = useState<Set<string>>(new Set());\n const [bulkAction, setBulkAction] = useState<BulkAction>(null);\n const [feedback, setFeedback] = useState<{\n type: \"success\" | \"error\";\n message: string;\n } | null>(null);\n\n // Fetch applications from GraphQL API — always scope to active org so\n // totalCount from the server matches what the user actually owns.\n const { data, loading, error, refetch } = useGetApplicationsQuery({\n variables: {\n limit: 50,\n offset: 0,\n status: statusFilter || undefined,\n organizationId: activeOrgId ?? undefined,\n },\n fetchPolicy: \"cache-and-network\",\n });\n\n const applications: Application[] = useMemo(\n () =>\n data?.applications?.edges?.map(\n (edge: { node: ApplicationFieldsFragment }) =>\n mapApplication(edge.node),\n ) ?? [],\n [data?.applications?.edges],\n );\n\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Client-side filtering: org scope + search + type (status filtered server-side)\n const filteredApps = applications.filter((app: Application) => {\n const matchesOrg =\n !activeOrgId || app.developerOrganizationId === activeOrgId;\n const matchesSearch =\n !searchQuery ||\n app.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n app.shortDescription?.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesType = !typeFilter || app.appType === typeFilter;\n return matchesOrg && matchesSearch && matchesType;\n });\n\n const appStats = useMemo(() => {\n // Use filteredApps (org-scoped) for all counts so stats match what's shown.\n const total = data?.applications?.totalCount ?? filteredApps.length;\n const active = filteredApps.filter(\n (app: Application) => app.status === \"ACTIVE\",\n ).length;\n const draft = filteredApps.filter(\n (app: Application) => app.status === \"DRAFT\",\n ).length;\n const published = filteredApps.filter(\n (app: Application) => app.status === \"PUBLISHED\",\n ).length;\n return { total, active, draft, published };\n }, [filteredApps, data?.applications?.totalCount]);\n\n const selectedApps = useMemo(\n () => applications.filter((app: Application) => selectedAppIds.has(app.id)),\n [applications, selectedAppIds],\n );\n\n const deactivatableApps = useMemo(\n () =>\n selectedApps.filter(\n (app: Application) =>\n app.status !== \"INACTIVE\" && app.status !== \"REVOKED\",\n ),\n [selectedApps],\n );\n\n const allVisibleSelected =\n filteredApps.length > 0 &&\n filteredApps.every((app: Application) => selectedAppIds.has(app.id));\n const partiallySelected =\n filteredApps.some((app: Application) => selectedAppIds.has(app.id)) &&\n !allVisibleSelected;\n\n const toggleAppSelection = (appId: string, checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(appId);\n } else {\n next.delete(appId);\n }\n return next;\n });\n };\n\n const toggleAllVisible = (checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n filteredApps.forEach((app: Application) => {\n if (checked) {\n next.add(app.id);\n } else {\n next.delete(app.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedAppIds(new Set());\n\n const runBulkDeactivate = async () => {\n if (deactivatableApps.length === 0) return;\n\n const results = await Promise.allSettled(\n deactivatableApps.map((app: Application) =>\n deactivateApp({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deactivated\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n const runBulkDelete = async () => {\n if (selectedApps.length === 0) return;\n\n const results = await Promise.allSettled(\n selectedApps.map((app: Application) =>\n deleteApplication({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deleted\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingApplications\", \"Loading applications...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadApplications\",\n \"Failed to load applications\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n purpose={tr(\n \"devportal.applicationsPurpose\",\n \"Applications are the integrations you build on the platform — OAuth apps, store listings, and API consumers. Create one here to get client credentials, request scopes, and ship to the marketplace.\",\n )}\n actions={\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n disabled={!createPerm.allowed}\n aria-disabled={!createPerm.allowed}\n title={\n !createPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 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 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Plus size={16} aria-hidden=\"true\" />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n }\n >\n {/* Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-1 items-center gap-4\">\n {/* Search */}\n <div className=\"relative flex-1 max-w-md\">\n <Search\n size={16}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n />\n <input\n type=\"text\"\n placeholder={tr(\n \"devportal.searchApplications\",\n \"Search applications...\",\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border bg-bg-surface pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n\n {/* Status Filter */}\n <select\n value={statusFilter}\n onChange={(e) =>\n setStatusFilter(e.target.value as AppStatus | \"\")\n }\n className=\"rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\"devportal.allStatus\", \"All Status\")}\n </option>\n {Object.keys(APP_STATUS_COLORS).map((status) => (\n <option key={status} value={status}>\n {status.replace(/_/g, \" \")}\n </option>\n ))}\n </select>\n\n {/* Type Filter */}\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as AppType | \"\")}\n className=\"rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">{tr(\"devportal.allTypes\", \"All Types\")}</option>\n {Object.entries(APP_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <button\n onClick={() => setViewMode(\"grid\")}\n className={`rounded p-1.5 ${viewMode === \"grid\" ? \"bg-bg-sunken\" : \"hover:bg-bg-sunken/50\"}`}\n title=\"Grid view\"\n >\n <Grid size={16} />\n </button>\n <button\n onClick={() => setViewMode(\"list\")}\n className={`rounded p-1.5 ${viewMode === \"list\" ? \"bg-bg-sunken\" : \"hover:bg-bg-sunken/50\"}`}\n title=\"List view\"\n >\n <List size={16} />\n </button>\n </div>\n </div>\n\n {/* Summary Stats — primary emphasis zone */}\n <EmphasisPanel className=\"mt-4\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.totalApps\", \"Total Apps\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.total}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-status-success-text\">\n {tr(\"devportal.active\", \"Active\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.active}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.published\", \"Published\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.published}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.draft\", \"Draft\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {appStats.draft}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n\n {feedback && (\n <div\n className={`rounded-lg border px-4 py-3 text-sm ${\n feedback.type === \"success\"\n ? \"border-border-subtle bg-status-success-bg-subtle text-status-success-text\"\n : \"border-status-error-border/40 bg-status-error-bg/10 text-status-error-text\"\n }`}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span>{feedback.message}</span>\n <button\n onClick={() => setFeedback(null)}\n className=\"text-xs font-medium underline underline-offset-2\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {filteredApps.length > 0 && (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-pop)]\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisible}\n ariaLabel=\"Select all visible applications\"\n />\n <span className=\"text-sm font-medium\">\n Select all visible\n </span>\n </div>\n {selectedAppIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedAppIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"deactivate\")}\n disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n aria-disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n title={\n !updatePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Archive size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deactivateSelected\", \"Deactivate Selected\")}\n {deactivatableApps.length > 0\n ? ` (${deactivatableApps.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"delete\")}\n disabled={selectedApps.length === 0 || !deletePerm.allowed}\n aria-disabled={\n selectedApps.length === 0 || !deletePerm.allowed\n }\n title={\n !deletePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deleteSelected\", \"Delete Selected\")}\n {selectedApps.length > 0 ? ` (${selectedApps.length})` : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n {filteredApps.length} application\n {filteredApps.length !== 1 ? \"s\" : \"\"} found\n </p>\n\n {/* Applications */}\n {filteredApps.length > 0 ? (\n viewMode === \"grid\" ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {filteredApps.map((app: Application) => (\n <AppCard\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredApps.map((app: Application) => (\n <AppListItem\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n )\n ) : (\n <EmptyState\n illustration={\n searchQuery || statusFilter || typeFilter\n ? \"empty-search\"\n : \"empty-data\"\n }\n icon={<AppWindow size={32} />}\n title={tr(\"devportal.noApplicationsFound\", \"No applications found\")}\n description={\n searchQuery || statusFilter || typeFilter\n ? tr(\n \"devportal.tryAdjustingFilters\",\n \"Try adjusting your filters\",\n )\n : tr(\n \"devportal.createFirstApp\",\n \"Create your first application to get started\",\n )\n }\n action={\n !searchQuery && !statusFilter && !typeFilter ? (\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : undefined\n }\n />\n )}\n\n <ConfirmDialog\n open={bulkAction === \"deactivate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDeactivate}\n title=\"Deactivate selected applications\"\n description={`Deactivate ${deactivatableApps.length} selected application${deactivatableApps.length === 1 ? \"\" : \"s\"}? Users and integrations may lose access until these apps are re-enabled.`}\n confirmLabel=\"Deactivate\"\n cancelLabel=\"Cancel\"\n variant=\"warning\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"delete\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDelete}\n title=\"Delete selected applications\"\n description={`Delete ${selectedApps.length} selected application${selectedApps.length === 1 ? \"\" : \"s\"}? This cannot be undone.`}\n confirmLabel=\"Delete\"\n cancelLabel=\"Cancel\"\n variant=\"danger\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-devportal",
3
- "version": "2026.629.7",
3
+ "version": "2026.629.9",
4
4
  "description": "Burdenoff Developer Portal Microfrontend - Complete developer operations interface",
5
5
  "type": "module",
6
6
  "files": [