@burdenoff/microfe-devportal 2026.1113.1 → 2026.1113.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/devportal/DevportalRoot.js +65 -119
  2. package/dist/devportal/DevportalRoot.js.map +1 -1
  3. package/dist/devportal/components/AppCard.js +4 -4
  4. package/dist/devportal/components/DeveloperSettingsHub.d.ts +6 -0
  5. package/dist/devportal/components/DeveloperSettingsHub.js +59 -0
  6. package/dist/devportal/components/DeveloperSettingsHub.js.map +1 -0
  7. package/dist/devportal/components/SectionNav.d.ts +1 -1
  8. package/dist/devportal/components/SectionNav.js +60 -36
  9. package/dist/devportal/components/SectionNav.js.map +1 -1
  10. package/dist/devportal/pages/AnalyticsDashboardPage.js +186 -179
  11. package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
  12. package/dist/devportal/pages/ApiKeysPage.js +113 -111
  13. package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
  14. package/dist/devportal/pages/AppLogsPage.js +80 -84
  15. package/dist/devportal/pages/AppLogsPage.js.map +1 -1
  16. package/dist/devportal/pages/ApplicationDetailPage.js +529 -504
  17. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  18. package/dist/devportal/pages/ApplicationsPage.js +68 -67
  19. package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
  20. package/dist/devportal/pages/CreateApiKeyPage.js +163 -166
  21. package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
  22. package/dist/devportal/pages/CreateOAuthClientPage.js +134 -130
  23. package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
  24. package/dist/devportal/pages/DelegationsPage.js +11 -11
  25. package/dist/devportal/pages/DocumentationPage.js +100 -94
  26. package/dist/devportal/pages/DocumentationPage.js.map +1 -1
  27. package/dist/devportal/pages/EditApplicationPage.js +379 -377
  28. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  29. package/dist/devportal/pages/InvitationDecisionPage.js +83 -79
  30. package/dist/devportal/pages/InvitationDecisionPage.js.map +1 -1
  31. package/dist/devportal/pages/OAuthClientDetailPage.js +76 -76
  32. package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
  33. package/dist/devportal/pages/OAuthClientsPage.js +126 -124
  34. package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
  35. package/dist/devportal/pages/OrganizationDetailPage.js +19 -19
  36. package/dist/devportal/pages/OrganizationMembersPage.js +223 -204
  37. package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
  38. package/dist/devportal/pages/ResourcesPage.d.ts +6 -0
  39. package/dist/devportal/pages/ResourcesPage.js +171 -155
  40. package/dist/devportal/pages/ResourcesPage.js.map +1 -1
  41. package/dist/devportal/pages/SellerDashboardPage.js +13 -13
  42. package/dist/devportal/pages/SellerItemsPage.js +4 -4
  43. package/dist/devportal/pages/SettingsPage.js +330 -315
  44. package/dist/devportal/pages/SettingsPage.js.map +1 -1
  45. package/dist/devportal/pages/SetupPage.js +5 -5
  46. package/dist/devportal/pages/WebhookDetailPage.js +6 -6
  47. package/dist/devportal/pages/WebhooksPage.js +39 -39
  48. package/dist/devportal/pages/WebhooksPage.js.map +1 -1
  49. package/dist/devportal/utils/appDetailTabs.d.ts +73 -0
  50. package/dist/devportal/utils/appDetailTabs.js +62 -0
  51. package/dist/devportal/utils/appDetailTabs.js.map +1 -0
  52. package/dist/devportal/utils/developerNav.d.ts +39 -0
  53. package/dist/devportal/utils/developerNav.js +304 -0
  54. package/dist/devportal/utils/developerNav.js.map +1 -0
  55. package/package.json +2 -2
@@ -3,26 +3,27 @@ import { AppCard as t } from "../components/AppCard.js";
3
3
  import { EmptyState as n } from "../components/EmptyState.js";
4
4
  import { useDeactivateApplicationMutation as r, useGetApplicationsQuery as ee } from "../../generated/global-operations.js";
5
5
  import { getErrorMessage as te } from "../hooks/useGraphQL.js";
6
- import { ConfirmDialog as ne } from "../components/ConfirmDialog.js";
7
- import { SelectionCheckbox as i } from "../components/SelectionCheckbox.js";
8
- import { useDevportal as re } from "../providers/DevportalProvider.js";
6
+ import { ConfirmDialog as i } from "../components/ConfirmDialog.js";
7
+ import { SelectionCheckbox as a } from "../components/SelectionCheckbox.js";
8
+ import { useDevportal as ne, useIsFluidgridsVariant as re } from "../providers/DevportalProvider.js";
9
+ import { DEACTIVATE_COPY as o } from "../utils/appDetailTabs.js";
9
10
  import "../components/index.js";
10
- import { DEVPORTAL_PERMISSIONS as a } from "../constants/permissions.js";
11
- import { useTr as ie } from "../utils/i18n.js";
12
- import { PermissionGuard as ae } from "../components/PermissionGuard.js";
13
- import { APP_STATUS_COLORS as oe, APP_TYPE_LABELS as o } from "../utils/constants.js";
14
- import { useDevportalPermission as s } from "../hooks/usePermission.js";
11
+ import { DEVPORTAL_PERMISSIONS as s } from "../constants/permissions.js";
12
+ import { PermissionGuard as ie } from "../components/PermissionGuard.js";
13
+ import { useTr as ae } from "../utils/i18n.js";
14
+ import { useDevportalPermission as c } from "../hooks/usePermission.js";
15
+ import { APP_STATUS_COLORS as l, APP_TYPE_LABELS as u } from "../utils/constants.js";
15
16
  import "../hooks/index.js";
16
- import { StoreImage as c } from "../components/StoreImage.js";
17
- import { useMemo as l, useState as u } from "react";
18
- import { AlertCircle as se, AppWindow as d, Archive as ce, Grid as f, List as p, Loader2 as le, Plus as m, Search as h } from "lucide-react";
17
+ import { StoreImage as oe } from "../components/StoreImage.js";
18
+ import { useMemo as d, useState as f } from "react";
19
+ import { AlertCircle as se, AppWindow as p, Archive as m, Grid as ce, List as le, Loader2 as ue, Plus as h, Search as de } from "lucide-react";
19
20
  import { jsx as g, jsxs as _ } from "react/jsx-runtime";
20
- import { EmphasisPanel as ue, GlassCard as v } from "@burdenoff/fe-libs/ui";
21
+ import { EmphasisPanel as fe, GlassCard as v } from "@burdenoff/fe-libs/ui";
21
22
  // src/devportal/pages/ApplicationsPage.tsx
22
- function de(e, t, n) {
23
+ function y(e, t, n) {
23
24
  return `${e} ${t} application${t === 1 ? "" : "s"}${n > 0 ? ` • ${n} failed` : ""}`;
24
25
  }
25
- function y({ status: e, tr: t }) {
26
+ function b({ status: e, tr: t }) {
26
27
  return /* @__PURE__ */ g("span", {
27
28
  className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${{
28
29
  ACTIVE: "bg-status-success-bg-subtle text-status-success-text",
@@ -41,7 +42,7 @@ function y({ status: e, tr: t }) {
41
42
  children: e === "INACTIVE" || e === "REVOKED" ? t("devportal.status.deactivated", "Deactivated") : e.replace(/_/g, " ")
42
43
  });
43
44
  }
44
- function b(e) {
45
+ function x(e) {
45
46
  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;
46
47
  return {
47
48
  id: e.id,
@@ -87,26 +88,26 @@ function b(e) {
87
88
  updatedAt: e.updatedAt
88
89
  };
89
90
  }
90
- var x = () => {
91
- let { navigate: x, basePath: S, activeOrgId: C } = re(), w = ie(), T = s(a.APP_CREATE), E = s(a.APP_UPDATE), [D, O] = u("list"), [k, fe] = u(""), [A, j] = u(""), [M, N] = u(""), [P, F] = u(/* @__PURE__ */ new Set()), [I, L] = u(null), [R, z] = u(null), { data: B, loading: pe, error: V, refetch: H } = ee({
91
+ var S = () => {
92
+ let { navigate: S, basePath: pe, activeOrgId: C } = ne(), w = ae(), T = re(), E = c(s.APP_CREATE), D = c(s.APP_UPDATE), [O, k] = f("list"), [A, me] = f(""), [j, he] = f(""), [M, N] = f(""), [P, F] = f(/* @__PURE__ */ new Set()), [I, L] = f(null), [R, z] = f(null), { data: B, loading: ge, error: V, refetch: H } = ee({
92
93
  variables: {
93
94
  limit: 50,
94
95
  offset: 0,
95
- status: A || void 0,
96
+ status: j || void 0,
96
97
  organizationId: C ?? void 0
97
98
  },
98
99
  fetchPolicy: "cache-and-network"
99
- }), U = l(() => B?.applications?.edges?.map((e) => b(e.node)) ?? [], [B?.applications?.edges]), [me] = r(), W = (e) => {
100
- x?.(`${S}${e}`);
100
+ }), U = d(() => B?.applications?.edges?.map((e) => x(e.node)) ?? [], [B?.applications?.edges]), [_e] = r(), W = (e) => {
101
+ S?.(`${pe}${e}`);
101
102
  }, G = U.filter((e) => {
102
- let t = !C || e.developerOrganizationId === C, n = !k || e.name.toLowerCase().includes(k.toLowerCase()) || e.shortDescription?.toLowerCase().includes(k.toLowerCase()), r = !M || e.appType === M;
103
+ let t = !C || e.developerOrganizationId === C, n = !A || e.name.toLowerCase().includes(A.toLowerCase()) || e.shortDescription?.toLowerCase().includes(A.toLowerCase()), r = !M || e.appType === M;
103
104
  return t && n && r;
104
- }), K = l(() => ({
105
+ }), K = d(() => ({
105
106
  total: B?.applications?.totalCount ?? G.length,
106
107
  active: G.filter((e) => e.status === "ACTIVE").length,
107
108
  draft: G.filter((e) => e.status === "DRAFT").length,
108
109
  published: G.filter((e) => e.status === "PUBLISHED").length
109
- }), [G, B?.applications?.totalCount]), q = l(() => U.filter((e) => P.has(e.id)), [U, P]), J = l(() => q.filter((e) => e.status !== "INACTIVE" && e.status !== "REVOKED"), [q]), Y = G.length > 0 && G.every((e) => P.has(e.id)), X = G.some((e) => P.has(e.id)) && !Y, Z = (e, t) => {
110
+ }), [G, B?.applications?.totalCount]), q = d(() => U.filter((e) => P.has(e.id)), [U, P]), J = d(() => q.filter((e) => e.status !== "INACTIVE" && e.status !== "REVOKED"), [q]), Y = G.length > 0 && G.every((e) => P.has(e.id)), X = G.some((e) => P.has(e.id)) && !Y, Z = (e, t) => {
110
111
  F((n) => {
111
112
  let r = new Set(n);
112
113
  return t ? r.add(e) : r.delete(e), r;
@@ -119,12 +120,12 @@ var x = () => {
119
120
  }), n;
120
121
  });
121
122
  }, $ = () => F(/* @__PURE__ */ new Set());
122
- return pe && !B ? /* @__PURE__ */ g(e, {
123
+ return ge && !B ? /* @__PURE__ */ g(e, {
123
124
  title: w("devportal.myApplications", "My Applications"),
124
125
  description: w("devportal.manageYourApps", "Manage your developer applications"),
125
126
  children: /* @__PURE__ */ _("div", {
126
127
  className: "flex items-center justify-center py-12",
127
- children: [/* @__PURE__ */ g(le, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ g("span", {
128
+ children: [/* @__PURE__ */ g(ue, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ g("span", {
128
129
  className: "ml-2 text-text-secondary",
129
130
  children: w("devportal.loadingApplications", "Loading applications...")
130
131
  })]
@@ -151,7 +152,7 @@ var x = () => {
151
152
  })
152
153
  ]
153
154
  })
154
- }) : /* @__PURE__ */ g(ae, {
155
+ }) : /* @__PURE__ */ g(ie, {
155
156
  authOnly: !0,
156
157
  children: /* @__PURE__ */ _(e, {
157
158
  title: w("devportal.myApplications", "My Applications"),
@@ -159,11 +160,11 @@ var x = () => {
159
160
  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."),
160
161
  actions: /* @__PURE__ */ _("button", {
161
162
  onClick: () => W("/apps/new"),
162
- disabled: !T.allowed,
163
- "aria-disabled": !T.allowed,
164
- title: T.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
163
+ disabled: !E.allowed,
164
+ "aria-disabled": !E.allowed,
165
+ title: E.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
165
166
  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",
166
- children: [/* @__PURE__ */ g(m, {
167
+ children: [/* @__PURE__ */ g(h, {
167
168
  size: 16,
168
169
  "aria-hidden": "true"
169
170
  }), w("devportal.createApp", "Create App")]
@@ -176,25 +177,25 @@ var x = () => {
176
177
  children: [
177
178
  /* @__PURE__ */ _("div", {
178
179
  className: "relative flex-1 max-w-md",
179
- children: [/* @__PURE__ */ g(h, {
180
+ children: [/* @__PURE__ */ g(de, {
180
181
  size: 16,
181
182
  className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary"
182
183
  }), /* @__PURE__ */ g("input", {
183
184
  type: "text",
184
185
  placeholder: w("devportal.searchApplications", "Search applications..."),
185
- value: k,
186
- onChange: (e) => fe(e.target.value),
186
+ value: A,
187
+ onChange: (e) => me(e.target.value),
187
188
  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"
188
189
  })]
189
190
  }),
190
191
  /* @__PURE__ */ _("select", {
191
- value: A,
192
- onChange: (e) => j(e.target.value),
192
+ value: j,
193
+ onChange: (e) => he(e.target.value),
193
194
  className: "rounded-md border bg-bg-surface px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
194
195
  children: [/* @__PURE__ */ g("option", {
195
196
  value: "",
196
197
  children: w("devportal.allStatus", "All Status")
197
- }), Object.keys(oe).map((e) => /* @__PURE__ */ g("option", {
198
+ }), Object.keys(l).map((e) => /* @__PURE__ */ g("option", {
198
199
  value: e,
199
200
  children: w(`devportal.appStatus.${e}`, e.replace(/_/g, " "))
200
201
  }, e))]
@@ -206,7 +207,7 @@ var x = () => {
206
207
  children: [/* @__PURE__ */ g("option", {
207
208
  value: "",
208
209
  children: w("devportal.allTypes", "All Types")
209
- }), Object.entries(o).map(([e, t]) => /* @__PURE__ */ g("option", {
210
+ }), Object.entries(u).map(([e, t]) => /* @__PURE__ */ g("option", {
210
211
  value: e,
211
212
  children: t
212
213
  }, e))]
@@ -215,19 +216,19 @@ var x = () => {
215
216
  }), /* @__PURE__ */ _("div", {
216
217
  className: "flex items-center gap-1 rounded-md border p-1",
217
218
  children: [/* @__PURE__ */ g("button", {
218
- onClick: () => O("grid"),
219
- className: `rounded p-1.5 ${D === "grid" ? "bg-bg-sunken" : "hover:bg-bg-sunken/50"}`,
219
+ onClick: () => k("grid"),
220
+ className: `rounded p-1.5 ${O === "grid" ? "bg-bg-sunken" : "hover:bg-bg-sunken/50"}`,
220
221
  title: w("devportal.gridView", "Grid view"),
221
- children: /* @__PURE__ */ g(f, { size: 16 })
222
+ children: /* @__PURE__ */ g(ce, { size: 16 })
222
223
  }), /* @__PURE__ */ g("button", {
223
- onClick: () => O("list"),
224
- className: `rounded p-1.5 ${D === "list" ? "bg-bg-sunken" : "hover:bg-bg-sunken/50"}`,
224
+ onClick: () => k("list"),
225
+ className: `rounded p-1.5 ${O === "list" ? "bg-bg-sunken" : "hover:bg-bg-sunken/50"}`,
225
226
  title: w("devportal.tableView", "Table view"),
226
- children: /* @__PURE__ */ g(p, { size: 16 })
227
+ children: /* @__PURE__ */ g(le, { size: 16 })
227
228
  })]
228
229
  })]
229
230
  }),
230
- /* @__PURE__ */ g(ue, {
231
+ /* @__PURE__ */ g(fe, {
231
232
  className: "mt-4",
232
233
  children: /* @__PURE__ */ _("div", {
233
234
  className: "grid grid-cols-2 gap-4 sm:grid-cols-4",
@@ -298,7 +299,7 @@ var x = () => {
298
299
  className: "flex flex-wrap items-center gap-3",
299
300
  children: [/* @__PURE__ */ _("div", {
300
301
  className: "flex items-center gap-2",
301
- children: [/* @__PURE__ */ g(i, {
302
+ children: [/* @__PURE__ */ g(a, {
302
303
  checked: Y,
303
304
  indeterminate: X,
304
305
  onChange: Q,
@@ -323,12 +324,12 @@ var x = () => {
323
324
  ]
324
325
  }), /* @__PURE__ */ _("button", {
325
326
  onClick: () => L("deactivate"),
326
- disabled: J.length === 0 || !E.allowed,
327
- "aria-disabled": J.length === 0 || !E.allowed,
328
- title: E.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
327
+ disabled: J.length === 0 || !D.allowed,
328
+ "aria-disabled": J.length === 0 || !D.allowed,
329
+ title: D.allowed ? void 0 : w("devportal.common.noPermission", "You do not have permission to perform this action"),
329
330
  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",
330
331
  children: [
331
- /* @__PURE__ */ g(ce, {
332
+ /* @__PURE__ */ g(m, {
332
333
  size: 16,
333
334
  "aria-hidden": "true"
334
335
  }),
@@ -347,7 +348,7 @@ var x = () => {
347
348
  G.length === 1 ? w("devportal.applicationFound", "application found") : w("devportal.applicationsFound", "applications found")
348
349
  ]
349
350
  }),
350
- G.length > 0 ? D === "grid" ? /* @__PURE__ */ g("div", {
351
+ G.length > 0 ? O === "grid" ? /* @__PURE__ */ g("div", {
351
352
  className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
352
353
  children: G.map((e) => /* @__PURE__ */ g(t, {
353
354
  app: e,
@@ -363,7 +364,7 @@ var x = () => {
363
364
  children: [
364
365
  /* @__PURE__ */ g("th", {
365
366
  className: "w-10 px-4 py-3",
366
- children: /* @__PURE__ */ g(i, {
367
+ children: /* @__PURE__ */ g(a, {
367
368
  checked: Y,
368
369
  indeterminate: X,
369
370
  onChange: Q,
@@ -395,7 +396,7 @@ var x = () => {
395
396
  children: [
396
397
  /* @__PURE__ */ g("td", {
397
398
  className: "w-10 px-4 py-3",
398
- children: /* @__PURE__ */ g(i, {
399
+ children: /* @__PURE__ */ g(a, {
399
400
  checked: P.has(e.id),
400
401
  onChange: (t) => Z(e.id, t),
401
402
  ariaLabel: w("devportal.selectNamed", "Select {{name}}", { name: e.name })
@@ -406,13 +407,13 @@ var x = () => {
406
407
  children: /* @__PURE__ */ _("button", {
407
408
  onClick: () => W(`/apps/${e.id}`),
408
409
  className: "group flex items-center gap-3 text-left",
409
- children: [/* @__PURE__ */ g(c, {
410
+ children: [/* @__PURE__ */ g(oe, {
410
411
  src: e.iconUrl,
411
412
  alt: "",
412
413
  className: "h-8 w-8 rounded object-cover",
413
414
  fallback: /* @__PURE__ */ g("div", {
414
415
  className: "flex h-8 w-8 items-center justify-center rounded bg-bg-sunken text-text-secondary",
415
- children: /* @__PURE__ */ g(d, { size: 14 })
416
+ children: /* @__PURE__ */ g(p, { size: 14 })
416
417
  })
417
418
  }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
418
419
  className: "font-medium text-text-primary group-hover:text-action-primary-text transition-colors",
@@ -425,14 +426,14 @@ var x = () => {
425
426
  }),
426
427
  /* @__PURE__ */ g("td", {
427
428
  className: "px-4 py-3",
428
- children: /* @__PURE__ */ g(y, {
429
+ children: /* @__PURE__ */ g(b, {
429
430
  status: e.status,
430
431
  tr: w
431
432
  })
432
433
  }),
433
434
  /* @__PURE__ */ g("td", {
434
435
  className: "px-4 py-3 text-text-secondary",
435
- children: o[e.appType] || e.appType
436
+ children: u[e.appType] || e.appType
436
437
  }),
437
438
  /* @__PURE__ */ g("td", {
438
439
  className: "px-4 py-3 text-text-secondary tabular-nums",
@@ -451,32 +452,32 @@ var x = () => {
451
452
  })]
452
453
  })
453
454
  }) : /* @__PURE__ */ g(n, {
454
- illustration: k || A || M ? "empty-search" : "empty-data",
455
- icon: /* @__PURE__ */ g(d, { size: 32 }),
455
+ illustration: A || j || M ? "empty-search" : "empty-data",
456
+ icon: /* @__PURE__ */ g(p, { size: 32 }),
456
457
  title: w("devportal.noApplicationsFound", "No applications found"),
457
- description: k || A || M ? w("devportal.tryAdjustingFilters", "Try adjusting your filters") : w("devportal.createFirstApp", "Create your first application to get started"),
458
- action: !k && !A && !M ? /* @__PURE__ */ _("button", {
458
+ description: A || j || M ? w("devportal.tryAdjustingFilters", "Try adjusting your filters") : w("devportal.createFirstApp", "Create your first application to get started"),
459
+ action: !A && !j && !M ? /* @__PURE__ */ _("button", {
459
460
  onClick: () => W("/apps/new"),
460
461
  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",
461
- children: [/* @__PURE__ */ g(m, { size: 16 }), w("devportal.createApp", "Create App")]
462
+ children: [/* @__PURE__ */ g(h, { size: 16 }), w("devportal.createApp", "Create App")]
462
463
  }) : void 0
463
464
  }),
464
- /* @__PURE__ */ g(ne, {
465
+ /* @__PURE__ */ g(i, {
465
466
  open: I === "deactivate",
466
467
  onOpenChange: (e) => {
467
468
  e || L(null);
468
469
  },
469
470
  onConfirm: async () => {
470
471
  if (J.length === 0) return;
471
- let e = await Promise.allSettled(J.map((e) => me({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
472
+ let e = await Promise.allSettled(J.map((e) => _e({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
472
473
  z({
473
474
  type: n === 0 ? "success" : "error",
474
- message: de(w("devportal.deactivated", "Deactivated"), t, n)
475
+ message: y(w("devportal.deactivated", "Deactivated"), t, n)
475
476
  }), $(), L(null), await H();
476
477
  },
477
478
  title: w("devportal.deactivateSelectedApplications", "Deactivate selected applications"),
478
- description: w("devportal.deactivateSelectedApplicationsDescription", "Deactivate {{count}} selected application(s)? Users and integrations may lose access until these apps are re-enabled.", { count: J.length }),
479
- confirmLabel: w("devportal.deactivate", "Deactivate"),
479
+ description: T ? w(o.bulkDescription.key, o.bulkDescription.fallback, { count: J.length }) : w("devportal.deactivateSelectedApplicationsDescription", "Deactivate {{count}} selected application(s)? Users and integrations may lose access until these apps are re-enabled.", { count: J.length }),
480
+ confirmLabel: T ? w(o.action.key, o.action.fallback) : w("devportal.deactivate", "Deactivate"),
480
481
  cancelLabel: w("devportal.cancel", "Cancel"),
481
482
  variant: "warning"
482
483
  })
@@ -484,6 +485,6 @@ var x = () => {
484
485
  })
485
486
  });
486
487
  };
487
- export { x as ApplicationsPage };
488
+ export { S as ApplicationsPage };
488
489
 
489
490
  //# sourceMappingURL=ApplicationsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationsPage.js","names":["EmptyState","EmptyState$1","formatBulkResult","action","succeeded","failed","StatusBadge","status","tr","mapApplication","screenshots","app","pricingDetails","ApplicationsPage","useDevportal","useTr","createPerm","useDevportalPermission","DEVPORTAL_PERMISSIONS","updatePerm","viewMode","setViewMode","useState","searchQuery","setSearchQuery","statusFilter","setStatusFilter","typeFilter","setTypeFilter","selectedAppIds","setSelectedAppIds","bulkAction","setBulkAction","feedback","setFeedback","useGetApplicationsQuery","activeOrgId","applications","useMemo","data","edge","deactivateApp","useDeactivateApplicationMutation","handleNavigate","basePath","path","filteredApps","matchesOrg","matchesSearch","matchesType","appStats","selectedApps","deactivatableApps","allVisibleSelected","partiallySelected","toggleAppSelection","next","prev","checked","appId","toggleAllVisible","clearSelection","loading","PageLayout","Loader2","error","AlertCircle","getErrorMessage","refetch","PermissionGuard","Plus","Search","APP_STATUS_COLORS","APP_TYPE_LABELS","value","label","Grid","List","EmphasisPanel","GlassCard","SelectionCheckbox","Archive","AppCard","StoreImage","AppWindow","ConfirmDialog","open","results","result"],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard } 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 { useTr } from \"../utils/i18n\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeactivateApplicationMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\nimport { StoreImage } from \"../components/StoreImage\";\n\ntype BulkAction = \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: string,\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\nfunction StatusBadge({\n status,\n tr,\n}: {\n status: AppStatus;\n tr: (key: string, fallback: string) => string;\n}) {\n const colors: Record<string, string> = {\n ACTIVE: \"bg-status-success-bg-subtle text-status-success-text\",\n PUBLISHED: \"bg-status-success-bg-subtle text-status-success-text\",\n DRAFT: \"bg-bg-sunken text-text-secondary\",\n SUBMITTED: \"bg-status-warning-bg-subtle text-status-warning-text\",\n IN_REVIEW: \"bg-status-warning-bg-subtle text-status-warning-text\",\n APPROVED: \"bg-status-success-bg-subtle text-status-success-text\",\n UNLISTED: \"bg-status-warning-bg-subtle text-status-warning-text\",\n REJECTED: \"bg-status-error-bg-subtle text-status-error-text\",\n SUSPENDED: \"bg-status-error-bg-subtle text-status-error-text\",\n INACTIVE: \"bg-bg-sunken text-text-muted\",\n REVOKED: \"bg-status-error-bg-subtle text-status-error-text\",\n DEPRECATED: \"bg-bg-sunken text-text-muted\",\n };\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${colors[status] ?? \"bg-bg-sunken text-text-secondary\"}`}\n >\n {status === \"INACTIVE\" || status === \"REVOKED\"\n ? tr(\"devportal.status.deactivated\", \"Deactivated\")\n : status.replace(/_/g, \" \")}\n </span>\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 tr = useTr();\n const createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"list\");\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 [deactivateApp] = useDeactivateApplicationMutation();\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(\n tr(\"devportal.deactivated\", \"Deactivated\"),\n succeeded,\n failed,\n ),\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 authOnly>\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 scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-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 {tr(\n `devportal.appStatus.${status}`,\n status.replace(/_/g, \" \"),\n )}\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 scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-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={tr(\"devportal.gridView\", \"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={tr(\"devportal.tableView\", \"Table 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 {tr(\"devportal.dismiss\", \"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={tr(\n \"devportal.selectAllVisibleApplications\",\n \"Select all visible applications\",\n )}\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllVisible\", \"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 {tr(\"devportal.clearSelection\", \"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}{\" \"}\n {tr(\"devportal.selectedLower\", \"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 </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n {filteredApps.length}{\" \"}\n {filteredApps.length === 1\n ? tr(\"devportal.applicationFound\", \"application found\")\n : tr(\"devportal.applicationsFound\", \"applications 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=\"overflow-x-auto rounded-lg border border-border-seam\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken text-left\">\n <th className=\"w-10 px-4 py-3\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisible}\n ariaLabel={tr(\"devportal.selectAll\", \"Select all\")}\n />\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.name\", \"Name\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.status\", \"Status\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.type\", \"Type\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.created\", \"Created\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\"></th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-seam\">\n {filteredApps.map((app: Application) => (\n <tr\n key={app.id}\n className={`hover:bg-bg-surface-hover transition-colors ${selectedAppIds.has(app.id) ? \"bg-action-primary-bg/5\" : \"\"}`}\n >\n <td className=\"w-10 px-4 py-3\">\n <SelectionCheckbox\n checked={selectedAppIds.has(app.id)}\n onChange={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n ariaLabel={tr(\n \"devportal.selectNamed\",\n \"Select {{name}}\",\n { name: app.name },\n )}\n />\n </td>\n <td className=\"px-4 py-3\">\n <button\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n className=\"group flex items-center gap-3 text-left\"\n >\n <StoreImage\n src={app.iconUrl}\n alt=\"\"\n className=\"h-8 w-8 rounded object-cover\"\n fallback={\n <div className=\"flex h-8 w-8 items-center justify-center rounded bg-bg-sunken text-text-secondary\">\n <AppWindow size={14} />\n </div>\n }\n />\n <div>\n <p className=\"font-medium text-text-primary group-hover:text-action-primary-text transition-colors\">\n {app.name}\n </p>\n {app.shortDescription && (\n <p className=\"text-xs text-text-secondary line-clamp-1\">\n {app.shortDescription}\n </p>\n )}\n </div>\n </button>\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge status={app.status} tr={tr} />\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {APP_TYPE_LABELS[app.appType] || app.appType}\n </td>\n <td className=\"px-4 py-3 text-text-secondary tabular-nums\">\n {new Date(app.createdAt).toLocaleDateString()}\n </td>\n <td className=\"px-4 py-3 text-right\">\n <button\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.view\", \"View\")}\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\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={tr(\n \"devportal.deactivateSelectedApplications\",\n \"Deactivate selected applications\",\n )}\n description={tr(\n \"devportal.deactivateSelectedApplicationsDescription\",\n \"Deactivate {{count}} selected application(s)? Users and integrations may lose access until these apps are re-enabled.\",\n { count: deactivatableApps.length },\n )}\n confirmLabel={tr(\"devportal.deactivate\", \"Deactivate\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ApplicationsPage.js","names":["EmptyState","EmptyState$1","formatBulkResult","action","succeeded","failed","StatusBadge","status","tr","mapApplication","screenshots","app","pricingDetails","ApplicationsPage","useDevportal","useTr","isFluidgrids","useIsFluidgridsVariant","createPerm","useDevportalPermission","DEVPORTAL_PERMISSIONS","updatePerm","viewMode","setViewMode","useState","searchQuery","setSearchQuery","statusFilter","setStatusFilter","typeFilter","setTypeFilter","selectedAppIds","setSelectedAppIds","bulkAction","setBulkAction","feedback","setFeedback","useGetApplicationsQuery","activeOrgId","applications","useMemo","data","edge","deactivateApp","useDeactivateApplicationMutation","handleNavigate","basePath","path","filteredApps","matchesOrg","matchesSearch","matchesType","appStats","selectedApps","deactivatableApps","allVisibleSelected","partiallySelected","toggleAppSelection","next","prev","checked","appId","toggleAllVisible","clearSelection","loading","PageLayout","Loader2","error","AlertCircle","getErrorMessage","refetch","PermissionGuard","Plus","Search","APP_STATUS_COLORS","APP_TYPE_LABELS","value","label","Grid","List","EmphasisPanel","GlassCard","SelectionCheckbox","Archive","AppCard","StoreImage","AppWindow","ConfirmDialog","open","results","result","DEACTIVATE_COPY"],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport {\n useDevportal,\n useIsFluidgridsVariant,\n} from \"../providers/DevportalProvider\";\nimport { DEACTIVATE_COPY } from \"../utils/appDetailTabs\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useTr } from \"../utils/i18n\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeactivateApplicationMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\nimport { StoreImage } from \"../components/StoreImage\";\n\ntype BulkAction = \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: string,\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\nfunction StatusBadge({\n status,\n tr,\n}: {\n status: AppStatus;\n tr: (key: string, fallback: string) => string;\n}) {\n const colors: Record<string, string> = {\n ACTIVE: \"bg-status-success-bg-subtle text-status-success-text\",\n PUBLISHED: \"bg-status-success-bg-subtle text-status-success-text\",\n DRAFT: \"bg-bg-sunken text-text-secondary\",\n SUBMITTED: \"bg-status-warning-bg-subtle text-status-warning-text\",\n IN_REVIEW: \"bg-status-warning-bg-subtle text-status-warning-text\",\n APPROVED: \"bg-status-success-bg-subtle text-status-success-text\",\n UNLISTED: \"bg-status-warning-bg-subtle text-status-warning-text\",\n REJECTED: \"bg-status-error-bg-subtle text-status-error-text\",\n SUSPENDED: \"bg-status-error-bg-subtle text-status-error-text\",\n INACTIVE: \"bg-bg-sunken text-text-muted\",\n REVOKED: \"bg-status-error-bg-subtle text-status-error-text\",\n DEPRECATED: \"bg-bg-sunken text-text-muted\",\n };\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${colors[status] ?? \"bg-bg-sunken text-text-secondary\"}`}\n >\n {status === \"INACTIVE\" || status === \"REVOKED\"\n ? tr(\"devportal.status.deactivated\", \"Deactivated\")\n : status.replace(/_/g, \" \")}\n </span>\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 tr = useTr();\n const isFluidgrids = useIsFluidgridsVariant();\n const createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"list\");\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 [deactivateApp] = useDeactivateApplicationMutation();\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(\n tr(\"devportal.deactivated\", \"Deactivated\"),\n succeeded,\n failed,\n ),\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 authOnly>\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 scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-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 {tr(\n `devportal.appStatus.${status}`,\n status.replace(/_/g, \" \"),\n )}\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 scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-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={tr(\"devportal.gridView\", \"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={tr(\"devportal.tableView\", \"Table 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 {tr(\"devportal.dismiss\", \"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={tr(\n \"devportal.selectAllVisibleApplications\",\n \"Select all visible applications\",\n )}\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllVisible\", \"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 {tr(\"devportal.clearSelection\", \"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}{\" \"}\n {tr(\"devportal.selectedLower\", \"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 </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n {filteredApps.length}{\" \"}\n {filteredApps.length === 1\n ? tr(\"devportal.applicationFound\", \"application found\")\n : tr(\"devportal.applicationsFound\", \"applications 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=\"overflow-x-auto rounded-lg border border-border-seam\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken text-left\">\n <th className=\"w-10 px-4 py-3\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisible}\n ariaLabel={tr(\"devportal.selectAll\", \"Select all\")}\n />\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.name\", \"Name\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.status\", \"Status\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.type\", \"Type\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\">\n {tr(\"devportal.created\", \"Created\")}\n </th>\n <th className=\"px-4 py-3 font-medium text-text-secondary\"></th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-seam\">\n {filteredApps.map((app: Application) => (\n <tr\n key={app.id}\n className={`hover:bg-bg-surface-hover transition-colors ${selectedAppIds.has(app.id) ? \"bg-action-primary-bg/5\" : \"\"}`}\n >\n <td className=\"w-10 px-4 py-3\">\n <SelectionCheckbox\n checked={selectedAppIds.has(app.id)}\n onChange={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n ariaLabel={tr(\n \"devportal.selectNamed\",\n \"Select {{name}}\",\n { name: app.name },\n )}\n />\n </td>\n <td className=\"px-4 py-3\">\n <button\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n className=\"group flex items-center gap-3 text-left\"\n >\n <StoreImage\n src={app.iconUrl}\n alt=\"\"\n className=\"h-8 w-8 rounded object-cover\"\n fallback={\n <div className=\"flex h-8 w-8 items-center justify-center rounded bg-bg-sunken text-text-secondary\">\n <AppWindow size={14} />\n </div>\n }\n />\n <div>\n <p className=\"font-medium text-text-primary group-hover:text-action-primary-text transition-colors\">\n {app.name}\n </p>\n {app.shortDescription && (\n <p className=\"text-xs text-text-secondary line-clamp-1\">\n {app.shortDescription}\n </p>\n )}\n </div>\n </button>\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge status={app.status} tr={tr} />\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {APP_TYPE_LABELS[app.appType] || app.appType}\n </td>\n <td className=\"px-4 py-3 text-text-secondary tabular-nums\">\n {new Date(app.createdAt).toLocaleDateString()}\n </td>\n <td className=\"px-4 py-3 text-right\">\n <button\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.view\", \"View\")}\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\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={tr(\n \"devportal.deactivateSelectedApplications\",\n \"Deactivate selected applications\",\n )}\n description={\n isFluidgrids\n ? tr(\n DEACTIVATE_COPY.bulkDescription.key,\n DEACTIVATE_COPY.bulkDescription.fallback,\n { count: deactivatableApps.length },\n )\n : tr(\n \"devportal.deactivateSelectedApplicationsDescription\",\n \"Deactivate {{count}} selected application(s)? Users and integrations may lose access until these apps are re-enabled.\",\n { count: deactivatableApps.length },\n )\n }\n confirmLabel={\n isFluidgrids\n ? tr(DEACTIVATE_COPY.action.key, DEACTIVATE_COPY.action.fallback)\n : tr(\"devportal.deactivate\", \"Deactivate\")\n }\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}