@burdenoff/microfe-devportal 2026.623.5 → 2026.623.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/devportal/DevportalRoutes.js +101 -94
  2. package/dist/devportal/DevportalRoutes.js.map +1 -1
  3. package/dist/devportal/components/SectionNav.js +71 -5
  4. package/dist/devportal/components/SectionNav.js.map +1 -0
  5. package/dist/devportal/components/index.js +1 -1
  6. package/dist/devportal/hooks/useGraphQL.js +1 -1
  7. package/dist/devportal/pages/AdminReviewPage.js +39 -39
  8. package/dist/devportal/pages/AnalyticsDashboardPage.js +54 -54
  9. package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
  10. package/dist/devportal/pages/ApiKeysPage.js +53 -53
  11. package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
  12. package/dist/devportal/pages/AppLogsPage.js +9 -9
  13. package/dist/devportal/pages/ApplicationDetailPage.js +462 -462
  14. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  15. package/dist/devportal/pages/ApplicationVersionsPage.js +120 -120
  16. package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
  17. package/dist/devportal/pages/ApplicationsPage.js +73 -73
  18. package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
  19. package/dist/devportal/pages/CreateApiKeyPage.js +20 -20
  20. package/dist/devportal/pages/CreateApplicationPage.js +32 -32
  21. package/dist/devportal/pages/CreateOAuthClientPage.js +18 -18
  22. package/dist/devportal/pages/CreateOrganizationPage.js +12 -12
  23. package/dist/devportal/pages/CreateWebhookPage.js +23 -23
  24. package/dist/devportal/pages/DashboardPage.js +23 -23
  25. package/dist/devportal/pages/DelegationsPage.js +22 -22
  26. package/dist/devportal/pages/EditApplicationPage.js +283 -283
  27. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  28. package/dist/devportal/pages/ListingPreviewPage.js +9 -9
  29. package/dist/devportal/pages/OAuthClientDetailPage.js +15 -15
  30. package/dist/devportal/pages/OAuthClientsPage.js +14 -14
  31. package/dist/devportal/pages/OrganizationDetailPage.js +84 -84
  32. package/dist/devportal/pages/OrganizationMembersPage.js +260 -260
  33. package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
  34. package/dist/devportal/pages/OrganizationsPage.js +16 -16
  35. package/dist/devportal/pages/PublishPage.js +16 -16
  36. package/dist/devportal/pages/PublisherProfilePage.js +18 -18
  37. package/dist/devportal/pages/RevenueDashboardPage.js +29 -29
  38. package/dist/devportal/pages/SettingsPage.js +17 -17
  39. package/dist/devportal/pages/SetupPage.js +99 -99
  40. package/dist/devportal/pages/SetupPage.js.map +1 -1
  41. package/dist/devportal/pages/WebhookDetailPage.js +143 -143
  42. package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
  43. package/dist/devportal/pages/WebhooksPage.js +133 -133
  44. package/dist/devportal/pages/WebhooksPage.js.map +1 -1
  45. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  import { useDevportal as e } from "../providers/DevportalProvider.js";
2
2
  import { EmptyState as t } from "../components/EmptyState.js";
3
- import { PageLayout as n, PageSection as r } from "../components/PageLayout.js";
4
- import { useApproveApplicationMutation as i, useGetApplicationForReviewQuery as a, useGetApplicationsQuery as o, useRejectApplicationMutation as s } from "../../generated/global-operations.js";
5
- import { PermissionGuard as c } from "../components/PermissionGuard.js";
6
- import { getErrorMessage as l } from "../hooks/useGraphQL.js";
3
+ import { useApproveApplicationMutation as n, useGetApplicationForReviewQuery as r, useGetApplicationsQuery as i, useRejectApplicationMutation as a } from "../../generated/global-operations.js";
4
+ import { getErrorMessage as o } from "../hooks/useGraphQL.js";
5
+ import { PageLayout as s, PageSection as c } from "../components/PageLayout.js";
6
+ import { PermissionGuard as l } from "../components/PermissionGuard.js";
7
7
  import "../components/index.js";
8
8
  import { DEVPORTAL_PERMISSIONS as u } from "../constants/permissions.js";
9
9
  import { useDevportalPermission as d } from "../hooks/usePermission.js";
@@ -24,11 +24,11 @@ var D = ({ manifest: e, tr: t }) => {
24
24
  className: "mt-2 max-h-48 overflow-auto rounded-md bg-muted p-3 text-xs font-mono whitespace-pre-wrap break-all",
25
25
  children: JSON.stringify(e, null, 2)
26
26
  })] });
27
- }, O = ({ app: t, onApprove: n, onReject: r, processing: i }) => {
27
+ }, O = ({ app: t, onApprove: n, onReject: i, processing: a }) => {
28
28
  let { navigate: o, basePath: s } = e(), { t: c } = p(), l = (e, t) => {
29
29
  let n = c(e);
30
30
  return n === e ? t : n;
31
- }, [m, v] = f(!1), [x, C] = f(""), O = d(u.APP_APPROVE), k = d(u.APP_REJECT), { data: A } = a({
31
+ }, [m, v] = f(!1), [x, C] = f(""), O = d(u.APP_APPROVE), k = d(u.APP_REJECT), { data: A } = r({
32
32
  variables: { id: t.id },
33
33
  skip: !m,
34
34
  fetchPolicy: "cache-first"
@@ -224,11 +224,11 @@ var D = ({ manifest: e, tr: t }) => {
224
224
  className: "flex gap-3",
225
225
  children: [/* @__PURE__ */ E("button", {
226
226
  onClick: () => n(t.id, x),
227
- disabled: i || !O.allowed,
228
- "aria-disabled": i || !O.allowed,
227
+ disabled: a || !O.allowed,
228
+ "aria-disabled": a || !O.allowed,
229
229
  title: O.allowed ? void 0 : l("devportal.common.noPermission", "You do not have permission to perform this action"),
230
230
  className: "inline-flex items-center gap-2 rounded-md bg-status-success-bg px-4 py-2 text-sm font-medium text-white hover:bg-status-success-bg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
231
- children: [i ? /* @__PURE__ */ T(S, {
231
+ children: [a ? /* @__PURE__ */ T(S, {
232
232
  size: 14,
233
233
  className: "animate-spin",
234
234
  "aria-hidden": "true"
@@ -237,12 +237,12 @@ var D = ({ manifest: e, tr: t }) => {
237
237
  "aria-hidden": "true"
238
238
  }), l("devportal.approve", "Approve")]
239
239
  }), /* @__PURE__ */ E("button", {
240
- onClick: () => r(t.id, x),
241
- disabled: i || !x.trim() || !k.allowed,
242
- "aria-disabled": i || !x.trim() || !k.allowed,
240
+ onClick: () => i(t.id, x),
241
+ disabled: a || !x.trim() || !k.allowed,
242
+ "aria-disabled": a || !x.trim() || !k.allowed,
243
243
  className: "inline-flex items-center gap-2 rounded-md bg-destructive px-4 py-2 text-sm font-medium text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
244
244
  title: k.allowed ? x.trim() ? void 0 : l("devportal.notesRequiredForRejection", "Notes required for rejection") : l("devportal.common.noPermission", "You do not have permission to perform this action"),
245
- children: [i ? /* @__PURE__ */ T(S, {
245
+ children: [a ? /* @__PURE__ */ T(S, {
246
246
  size: 14,
247
247
  className: "animate-spin",
248
248
  "aria-hidden": "true"
@@ -256,19 +256,19 @@ var D = ({ manifest: e, tr: t }) => {
256
256
  })]
257
257
  });
258
258
  }, k = () => {
259
- let { t: e } = p(), a = (t, n) => {
259
+ let { t: e } = p(), r = (t, n) => {
260
260
  let r = e(t);
261
261
  return r === t ? n : r;
262
262
  }, [d, g] = f(""), [_, y] = f(/* @__PURE__ */ new Set()), [b, x] = f(null), [w, D] = f(null), k = (e) => y((t) => new Set(t).add(e)), A = (e) => y((t) => {
263
263
  let n = new Set(t);
264
264
  return n.delete(e), n;
265
- }), { data: j, loading: M, error: N, refetch: P } = o({
265
+ }), { data: j, loading: M, error: N, refetch: P } = i({
266
266
  variables: {
267
267
  status: "SUBMITTED",
268
268
  limit: 100
269
269
  },
270
270
  fetchPolicy: "cache-and-network"
271
- }), [F] = i(), [I] = s(), L = j?.applications?.edges?.map((e) => e.node) ?? [], R = d ? L.filter((e) => e.name.toLowerCase().includes(d.toLowerCase()) || (e.shortDescription ?? "").toLowerCase().includes(d.toLowerCase())) : L, z = async (e, t) => {
271
+ }), [F] = n(), [I] = a(), L = j?.applications?.edges?.map((e) => e.node) ?? [], R = d ? L.filter((e) => e.name.toLowerCase().includes(d.toLowerCase()) || (e.shortDescription ?? "").toLowerCase().includes(d.toLowerCase())) : L, z = async (e, t) => {
272
272
  k(e), x(null), D(null);
273
273
  try {
274
274
  let n = await F({ variables: {
@@ -276,9 +276,9 @@ var D = ({ manifest: e, tr: t }) => {
276
276
  notes: t || void 0
277
277
  } });
278
278
  if (n.error) throw n.error;
279
- D(a("devportal.applicationApprovedSuccess", "Application approved successfully.")), await P();
279
+ D(r("devportal.applicationApprovedSuccess", "Application approved successfully.")), await P();
280
280
  } catch (e) {
281
- x(e instanceof Error ? e.message : a("devportal.failedToApproveApplication", "Failed to approve application"));
281
+ x(e instanceof Error ? e.message : r("devportal.failedToApproveApplication", "Failed to approve application"));
282
282
  } finally {
283
283
  A(e);
284
284
  }
@@ -291,48 +291,48 @@ var D = ({ manifest: e, tr: t }) => {
291
291
  notes: t
292
292
  } });
293
293
  if (n.error) throw n.error;
294
- D(a("devportal.applicationRejected", "Application rejected.")), await P();
294
+ D(r("devportal.applicationRejected", "Application rejected.")), await P();
295
295
  } catch (e) {
296
- x(e instanceof Error ? e.message : a("devportal.failedToRejectApplication", "Failed to reject application"));
296
+ x(e instanceof Error ? e.message : r("devportal.failedToRejectApplication", "Failed to reject application"));
297
297
  } finally {
298
298
  A(e);
299
299
  }
300
300
  }
301
301
  };
302
- return M && !j ? /* @__PURE__ */ T(n, {
303
- title: a("devportal.appReviewQueue", "App Review Queue"),
304
- description: a("devportal.appReviewQueueDescription", "Review submitted applications for approval"),
302
+ return M && !j ? /* @__PURE__ */ T(s, {
303
+ title: r("devportal.appReviewQueue", "App Review Queue"),
304
+ description: r("devportal.appReviewQueueDescription", "Review submitted applications for approval"),
305
305
  children: /* @__PURE__ */ T("div", {
306
306
  className: "flex items-center justify-center py-12",
307
307
  children: /* @__PURE__ */ T(S, { className: "h-8 w-8 animate-spin text-muted-foreground" })
308
308
  })
309
- }) : N ? /* @__PURE__ */ T(n, {
310
- title: a("devportal.appReviewQueue", "App Review Queue"),
311
- description: a("devportal.appReviewQueueDescription", "Review submitted applications for approval"),
309
+ }) : N ? /* @__PURE__ */ T(s, {
310
+ title: r("devportal.appReviewQueue", "App Review Queue"),
311
+ description: r("devportal.appReviewQueueDescription", "Review submitted applications for approval"),
312
312
  children: /* @__PURE__ */ E("div", {
313
313
  className: "rounded-lg border border-destructive/50 bg-destructive/10 p-6 text-center",
314
314
  children: [
315
315
  /* @__PURE__ */ T(m, { className: "mx-auto h-8 w-8 text-destructive" }),
316
316
  /* @__PURE__ */ T("p", {
317
317
  className: "mt-2 text-sm text-muted-foreground",
318
- children: l(N)
318
+ children: o(N)
319
319
  }),
320
320
  /* @__PURE__ */ T("button", {
321
321
  onClick: () => P(),
322
322
  className: "mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90",
323
- children: a("devportal.retry", "Retry")
323
+ children: r("devportal.retry", "Retry")
324
324
  })
325
325
  ]
326
326
  })
327
- }) : /* @__PURE__ */ T(c, {
327
+ }) : /* @__PURE__ */ T(l, {
328
328
  permission: u.REVIEW_MANAGE,
329
- children: /* @__PURE__ */ E(n, {
330
- title: a("devportal.appReviewQueue", "App Review Queue"),
331
- description: a("devportal.appReviewQueueFullDescription", "Review submitted applications for approval or rejection"),
329
+ children: /* @__PURE__ */ E(s, {
330
+ title: r("devportal.appReviewQueue", "App Review Queue"),
331
+ description: r("devportal.appReviewQueueFullDescription", "Review submitted applications for approval or rejection"),
332
332
  actions: /* @__PURE__ */ T("button", {
333
333
  onClick: () => P(),
334
334
  className: "rounded-md border px-3 py-1.5 text-sm hover:bg-muted",
335
- children: a("devportal.refresh", "Refresh")
335
+ children: r("devportal.refresh", "Refresh")
336
336
  }),
337
337
  children: [
338
338
  /* @__PURE__ */ E("div", {
@@ -347,7 +347,7 @@ var D = ({ manifest: e, tr: t }) => {
347
347
  children: [
348
348
  L.length,
349
349
  " ",
350
- a("devportal.pendingReview", "pending review")
350
+ r("devportal.pendingReview", "pending review")
351
351
  ]
352
352
  })]
353
353
  }), _.size > 0 && /* @__PURE__ */ E("div", {
@@ -355,7 +355,7 @@ var D = ({ manifest: e, tr: t }) => {
355
355
  children: [/* @__PURE__ */ T(S, {
356
356
  size: 14,
357
357
  className: "animate-spin"
358
- }), a("devportal.processing", "Processing...")]
358
+ }), r("devportal.processing", "Processing...")]
359
359
  })]
360
360
  }),
361
361
  w && /* @__PURE__ */ E("div", {
@@ -373,16 +373,16 @@ var D = ({ manifest: e, tr: t }) => {
373
373
  className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
374
374
  }), /* @__PURE__ */ T("input", {
375
375
  type: "text",
376
- placeholder: a("devportal.searchSubmittedApps", "Search submitted apps..."),
376
+ placeholder: r("devportal.searchSubmittedApps", "Search submitted apps..."),
377
377
  value: d,
378
378
  onChange: (e) => g(e.target.value),
379
379
  className: "w-full rounded-md border bg-background pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
380
380
  })]
381
381
  }),
382
- /* @__PURE__ */ T(r, { children: R.length === 0 ? /* @__PURE__ */ T(t, {
382
+ /* @__PURE__ */ T(c, { children: R.length === 0 ? /* @__PURE__ */ T(t, {
383
383
  icon: /* @__PURE__ */ T(h, { size: 32 }),
384
- title: a("devportal.noAppsPendingReview", "No apps pending review"),
385
- description: d ? a("devportal.noAppsMatchSearch", "No apps match your search") : a("devportal.allApplicationsReviewed", "All submitted applications have been reviewed")
384
+ title: r("devportal.noAppsPendingReview", "No apps pending review"),
385
+ description: d ? r("devportal.noAppsMatchSearch", "No apps match your search") : r("devportal.allApplicationsReviewed", "All submitted applications have been reviewed")
386
386
  }) : /* @__PURE__ */ T("div", {
387
387
  className: "space-y-3",
388
388
  children: R.map((e) => /* @__PURE__ */ T(O, {
@@ -1,11 +1,11 @@
1
1
  import { useDevportal as e } from "../providers/DevportalProvider.js";
2
2
  import { EmptyState as t } from "../components/EmptyState.js";
3
- import { PageLayout as n, PageSection as r } from "../components/PageLayout.js";
4
- import { StatCard as i, StatCardGrid as a } from "../components/StatCard.js";
5
- import { AppListItem as o } from "../components/AppCard.js";
6
- import { DataTable as ee } from "../components/DataTable.js";
7
- import { useGetAnalyticsDashboardOptionsQuery as te, useGetApplicationAnalyticsDashboardQuery as ne } from "../../generated/global-operations.js";
8
- import { getErrorMessage as s } from "../hooks/useGraphQL.js";
3
+ import { useGetAnalyticsDashboardOptionsQuery as n, useGetApplicationAnalyticsDashboardQuery as r } from "../../generated/global-operations.js";
4
+ import { getErrorMessage as i } from "../hooks/useGraphQL.js";
5
+ import { PageLayout as a, PageSection as o } from "../components/PageLayout.js";
6
+ import { StatCard as s, StatCardGrid as ee } from "../components/StatCard.js";
7
+ import { AppListItem as te } from "../components/AppCard.js";
8
+ import { DataTable as ne } from "../components/DataTable.js";
9
9
  import "../hooks/index.js";
10
10
  import { Tooltip as c } from "../../node_modules/.bun/recharts@2.15.4_21ccd8898788a04d/node_modules/recharts/es6/component/Tooltip.js";
11
11
  import { ResponsiveContainer as l } from "../../node_modules/.bun/recharts@2.15.4_21ccd8898788a04d/node_modules/recharts/es6/component/ResponsiveContainer.js";
@@ -16,45 +16,45 @@ import { XAxis as p } from "../../node_modules/.bun/recharts@2.15.4_21ccd8898788
16
16
  import { YAxis as m } from "../../node_modules/.bun/recharts@2.15.4_21ccd8898788a04d/node_modules/recharts/es6/cartesian/YAxis.js";
17
17
  import { LineChart as re } from "../../node_modules/.bun/recharts@2.15.4_21ccd8898788a04d/node_modules/recharts/es6/chart/LineChart.js";
18
18
  import { BarChart as ie } from "../../node_modules/.bun/recharts@2.15.4_21ccd8898788a04d/node_modules/recharts/es6/chart/BarChart.js";
19
- import { useTr as h } from "../utils/i18n.js";
20
- import { useEffect as g, useMemo as _, useState as v } from "react";
21
- import { Activity as ae, AlertCircle as y, AlertTriangle as oe, BarChart3 as b, Clock as x, Loader2 as S, Users as C } from "lucide-react";
19
+ import { useTr as ae } from "../utils/i18n.js";
20
+ import { useEffect as h, useMemo as g, useState as _ } from "react";
21
+ import { Activity as v, AlertCircle as y, AlertTriangle as b, BarChart3 as x, Clock as oe, Loader2 as S, Users as C } from "lucide-react";
22
22
  import { useParams as w } from "react-router-dom";
23
23
  import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
24
24
  //#region src/devportal/pages/AnalyticsDashboardPage.tsx
25
- var se = {
25
+ var O = {
26
26
  "7d": 7,
27
27
  "30d": 30,
28
28
  "90d": 90
29
- }, O = {
29
+ }, k = {
30
30
  primary: "var(--color-chart-1)",
31
31
  secondary: "var(--color-chart-2)",
32
32
  tertiary: "var(--color-chart-4)",
33
33
  negative: "var(--color-chart-negative)"
34
- }, k = () => {
35
- let { appId: k } = w(), { navigate: ce, basePath: A, activeOrgId: j } = e(), M = h(), [N, P] = v("30d"), [F, I] = v(k || ""), L = _(() => /* @__PURE__ */ new Date(), []), R = _(() => {
34
+ }, A = () => {
35
+ let { appId: A } = w(), { navigate: se, basePath: ce, activeOrgId: j } = e(), M = ae(), [N, P] = _("30d"), [F, I] = _(A || ""), L = g(() => /* @__PURE__ */ new Date(), []), R = g(() => {
36
36
  let e = new Date(L);
37
- return e.setDate(e.getDate() - se[N]), e.toISOString();
38
- }, [L, N]), { data: z, loading: B, error: V } = te({
39
- skip: !!k,
37
+ return e.setDate(e.getDate() - O[N]), e.toISOString();
38
+ }, [L, N]), { data: z, loading: B, error: V } = n({
39
+ skip: !!A,
40
40
  fetchPolicy: "cache-and-network"
41
- }), { data: H, loading: U, error: W } = ne({
41
+ }), { data: H, loading: U, error: W } = r({
42
42
  variables: {
43
- applicationId: F || k || "",
43
+ applicationId: F || A || "",
44
44
  period: "daily",
45
45
  startDate: R,
46
46
  endDate: L.toISOString()
47
47
  },
48
- skip: !(F || k),
48
+ skip: !(F || A),
49
49
  fetchPolicy: "cache-and-network"
50
50
  }), G = z?.applications?.edges?.map((e) => e.node) ?? [], K = j ? G.filter((e) => e.developerOrganizationId === j) : G, q = H?.application;
51
- g(() => {
52
- let e = q?.name, t = k || F;
51
+ h(() => {
52
+ let e = q?.name, t = A || F;
53
53
  if (!t || !e) return;
54
54
  let n = window.__breadcrumbRegistry;
55
55
  return n?.register(t, e), () => n?.unregister(t);
56
56
  }, [
57
- k,
57
+ A,
58
58
  F,
59
59
  q?.name
60
60
  ]);
@@ -70,16 +70,16 @@ var se = {
70
70
  sessions: e.sessions,
71
71
  avgResponseTime: e.avgResponseTime ?? 0
72
72
  })), Q = Y && Y.apiCalls > 0 ? Y.errors / Y.apiCalls * 100 : 0, le = X && X.apiCalls > 0 ? X.errors / X.apiCalls * 100 : 0, $ = Y?.avgResponseTime && X?.avgResponseTime ? X.avgResponseTime - Y.avgResponseTime : void 0, ue = (e) => {
73
- ce?.(`${A}${e}`);
73
+ se?.(`${ce}${e}`);
74
74
  };
75
- return !k && B && !z ? /* @__PURE__ */ E(n, {
75
+ return !A && B && !z ? /* @__PURE__ */ E(a, {
76
76
  title: M("devportal.analytics.title", "Analytics"),
77
77
  description: M("devportal.analytics.description", "Explore live application usage and performance metrics"),
78
78
  children: /* @__PURE__ */ E("div", {
79
79
  className: "flex items-center justify-center py-16 text-muted-foreground",
80
80
  children: /* @__PURE__ */ E(S, { className: "h-8 w-8 animate-spin" })
81
81
  })
82
- }) : !k && V ? /* @__PURE__ */ E(n, {
82
+ }) : !A && V ? /* @__PURE__ */ E(a, {
83
83
  title: M("devportal.analytics.title", "Analytics"),
84
84
  description: M("devportal.analytics.description", "Explore live application usage and performance metrics"),
85
85
  children: /* @__PURE__ */ E(t, {
@@ -88,23 +88,23 @@ var se = {
88
88
  className: "text-status-error-text"
89
89
  }),
90
90
  title: M("devportal.analytics.errorLoadApps", "Unable to load applications"),
91
- description: s(V)
91
+ description: i(V)
92
92
  })
93
- }) : !k && !F ? /* @__PURE__ */ E(n, {
93
+ }) : !A && !F ? /* @__PURE__ */ E(a, {
94
94
  title: M("devportal.analytics.title", "Analytics"),
95
95
  description: M("devportal.analytics.selectAppDescription", "Select an application to review live usage metrics from the public gateway"),
96
96
  children: K.length > 0 ? /* @__PURE__ */ E("div", {
97
97
  className: "space-y-2",
98
- children: K.map((e) => /* @__PURE__ */ E(o, {
98
+ children: K.map((e) => /* @__PURE__ */ E(te, {
99
99
  app: e,
100
100
  onClick: () => I(e.id)
101
101
  }, e.id))
102
102
  }) : /* @__PURE__ */ E(t, {
103
- icon: /* @__PURE__ */ E(b, { size: 32 }),
103
+ icon: /* @__PURE__ */ E(x, { size: 32 }),
104
104
  title: M("devportal.analytics.noAppsTitle", "No applications available"),
105
105
  description: M("devportal.analytics.noAppsDescription", "Create an application before viewing analytics.")
106
106
  })
107
- }) : W ? /* @__PURE__ */ E(n, {
107
+ }) : W ? /* @__PURE__ */ E(a, {
108
108
  title: M("devportal.analytics.title", "Analytics"),
109
109
  description: M("devportal.analytics.description", "Explore live application usage and performance metrics"),
110
110
  backLink: F ? `/apps/${F}` : void 0,
@@ -115,16 +115,16 @@ var se = {
115
115
  className: "text-status-error-text"
116
116
  }),
117
117
  title: M("devportal.analytics.errorLoadAnalytics", "Unable to load analytics"),
118
- description: s(W)
118
+ description: i(W)
119
119
  })
120
- }) : /* @__PURE__ */ E(n, {
121
- title: k ? M("devportal.analytics.appTitle", "Application Analytics") : M("devportal.analytics.title", "Analytics"),
120
+ }) : /* @__PURE__ */ E(a, {
121
+ title: A ? M("devportal.analytics.appTitle", "Application Analytics") : M("devportal.analytics.title", "Analytics"),
122
122
  description: q ? `${M("devportal.analytics.liveUsageFor", "Live usage and performance for")} ${q.name}` : M("devportal.analytics.description", "Explore live application usage and performance metrics"),
123
- backLink: k && q ? `/apps/${q.id}` : void 0,
123
+ backLink: A && q ? `/apps/${q.id}` : void 0,
124
124
  backLabel: M("devportal.analytics.backToApplication", "Back to Application"),
125
125
  actions: /* @__PURE__ */ D("div", {
126
126
  className: "flex flex-wrap gap-2",
127
- children: [!k && K.length > 0 && /* @__PURE__ */ E("select", {
127
+ children: [!A && K.length > 0 && /* @__PURE__ */ E("select", {
128
128
  value: F,
129
129
  onChange: (e) => I(e.target.value),
130
130
  "aria-label": M("devportal.analytics.selectAppAria", "Select application"),
@@ -158,32 +158,32 @@ var se = {
158
158
  className: "flex items-center justify-center py-16 text-muted-foreground",
159
159
  children: /* @__PURE__ */ E(S, { className: "h-8 w-8 animate-spin" })
160
160
  }) : J.length > 0 ? /* @__PURE__ */ D(T, { children: [
161
- /* @__PURE__ */ D(a, {
161
+ /* @__PURE__ */ D(ee, {
162
162
  columns: 4,
163
163
  children: [
164
- /* @__PURE__ */ E(i, {
164
+ /* @__PURE__ */ E(s, {
165
165
  title: M("devportal.analytics.apiCalls", "API Calls"),
166
166
  value: (Y?.apiCalls ?? 0).toLocaleString(),
167
- icon: /* @__PURE__ */ E(ae, { size: 20 })
167
+ icon: /* @__PURE__ */ E(v, { size: 20 })
168
168
  }),
169
- /* @__PURE__ */ E(i, {
169
+ /* @__PURE__ */ E(s, {
170
170
  title: M("devportal.analytics.activeUsers", "Active Users"),
171
171
  value: (Y?.activeUsers ?? 0).toLocaleString(),
172
172
  icon: /* @__PURE__ */ E(C, { size: 20 })
173
173
  }),
174
- /* @__PURE__ */ E(i, {
174
+ /* @__PURE__ */ E(s, {
175
175
  title: M("devportal.analytics.errorRate", "Error Rate"),
176
176
  value: `${Q.toFixed(2)}%`,
177
- icon: /* @__PURE__ */ E(oe, { size: 20 }),
177
+ icon: /* @__PURE__ */ E(b, { size: 20 }),
178
178
  trend: X ? {
179
179
  value: le - Q,
180
180
  label: M("devportal.analytics.vsPrevious", "vs previous period")
181
181
  } : void 0
182
182
  }),
183
- /* @__PURE__ */ E(i, {
183
+ /* @__PURE__ */ E(s, {
184
184
  title: M("devportal.analytics.avgResponseTime", "Avg Response Time"),
185
185
  value: Y?.avgResponseTime ? `${Y.avgResponseTime}ms` : M("devportal.common.na", "N/A"),
186
- icon: /* @__PURE__ */ E(x, { size: 20 }),
186
+ icon: /* @__PURE__ */ E(oe, { size: 20 }),
187
187
  trend: typeof $ == "number" ? {
188
188
  value: $,
189
189
  label: M("devportal.analytics.fasterThanPrevious", "faster than previous")
@@ -193,7 +193,7 @@ var se = {
193
193
  }),
194
194
  /* @__PURE__ */ D("div", {
195
195
  className: "grid gap-6 xl:grid-cols-2",
196
- children: [/* @__PURE__ */ E(r, {
196
+ children: [/* @__PURE__ */ E(o, {
197
197
  title: M("devportal.analytics.trafficTrend", "Traffic trend"),
198
198
  children: /* @__PURE__ */ E("div", {
199
199
  className: "rounded-lg border bg-card p-4",
@@ -224,14 +224,14 @@ var se = {
224
224
  /* @__PURE__ */ E(f, {
225
225
  type: "monotone",
226
226
  dataKey: "apiCalls",
227
- stroke: O.primary,
227
+ stroke: k.primary,
228
228
  strokeWidth: 2,
229
229
  dot: !1
230
230
  }),
231
231
  /* @__PURE__ */ E(f, {
232
232
  type: "monotone",
233
233
  dataKey: "errors",
234
- stroke: O.negative,
234
+ stroke: k.negative,
235
235
  strokeWidth: 2,
236
236
  dot: !1
237
237
  })
@@ -239,7 +239,7 @@ var se = {
239
239
  })
240
240
  })
241
241
  })
242
- }), /* @__PURE__ */ E(r, {
242
+ }), /* @__PURE__ */ E(o, {
243
243
  title: M("devportal.analytics.userActivity", "User activity"),
244
244
  children: /* @__PURE__ */ E("div", {
245
245
  className: "rounded-lg border bg-card p-4",
@@ -269,7 +269,7 @@ var se = {
269
269
  } }),
270
270
  /* @__PURE__ */ E(u, {
271
271
  dataKey: "activeUsers",
272
- fill: O.primary,
272
+ fill: k.primary,
273
273
  radius: [
274
274
  6,
275
275
  6,
@@ -279,7 +279,7 @@ var se = {
279
279
  }),
280
280
  /* @__PURE__ */ E(u, {
281
281
  dataKey: "newUsers",
282
- fill: O.secondary,
282
+ fill: k.secondary,
283
283
  radius: [
284
284
  6,
285
285
  6,
@@ -293,9 +293,9 @@ var se = {
293
293
  })
294
294
  })]
295
295
  }),
296
- /* @__PURE__ */ E(r, {
296
+ /* @__PURE__ */ E(o, {
297
297
  title: M("devportal.analytics.dailyBreakdown", "Daily breakdown"),
298
- children: /* @__PURE__ */ E(ee, {
298
+ children: /* @__PURE__ */ E(ne, {
299
299
  data: J,
300
300
  keyField: "id",
301
301
  columns: [
@@ -342,10 +342,10 @@ var se = {
342
342
  })
343
343
  })
344
344
  ] }) : /* @__PURE__ */ E(t, {
345
- icon: /* @__PURE__ */ E(b, { size: 32 }),
345
+ icon: /* @__PURE__ */ E(x, { size: 32 }),
346
346
  title: M("devportal.analytics.noAnalyticsTitle", "No analytics available yet"),
347
347
  description: M("devportal.analytics.noAnalyticsDescription", "Analytics will appear after this application starts receiving traffic through the public gateway."),
348
- action: k ? void 0 : /* @__PURE__ */ E("button", {
348
+ action: A ? void 0 : /* @__PURE__ */ E("button", {
349
349
  type: "button",
350
350
  onClick: () => ue("/apps"),
351
351
  className: "inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
@@ -355,6 +355,6 @@ var se = {
355
355
  });
356
356
  };
357
357
  //#endregion
358
- export { k as AnalyticsDashboardPage };
358
+ export { A as AnalyticsDashboardPage };
359
359
 
360
360
  //# sourceMappingURL=AnalyticsDashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsDashboardPage.js","names":[],"sources":["../../../src/devportal/pages/AnalyticsDashboardPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport {\n Activity,\n AlertCircle,\n AlertTriangle,\n BarChart3,\n Clock,\n Loader2,\n Users,\n} from \"lucide-react\";\nimport {\n Bar,\n BarChart,\n CartesianGrid,\n Line,\n LineChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { AppListItem } from \"../components/AppCard\";\nimport type { Application } from \"../types\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport {\n type GetAnalyticsDashboardOptionsQuery,\n getErrorMessage,\n useGetAnalyticsDashboardOptionsQuery,\n useGetApplicationAnalyticsDashboardQuery,\n} from \"../hooks\";\nimport { useTr } from \"../utils/i18n\";\n\ntype TimeRange = \"7d\" | \"30d\" | \"90d\";\n\nconst daysByRange: Record<TimeRange, number> = {\n \"7d\": 7,\n \"30d\": 30,\n \"90d\": 90,\n};\n\nconst chartColors = {\n primary: \"var(--color-chart-1)\",\n secondary: \"var(--color-chart-2)\",\n tertiary: \"var(--color-chart-4)\",\n negative: \"var(--color-chart-negative)\",\n};\n\nexport const AnalyticsDashboardPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath, activeOrgId } = useDevportal();\n const tr = useTr();\n const [timeRange, setTimeRange] = useState<TimeRange>(\"30d\");\n const [selectedApplicationId, setSelectedApplicationId] = useState(\n appId || \"\",\n );\n\n const now = useMemo(() => new Date(), []);\n const startDate = useMemo(() => {\n const nextDate = new Date(now);\n nextDate.setDate(nextDate.getDate() - daysByRange[timeRange]);\n return nextDate.toISOString();\n }, [now, timeRange]);\n\n const {\n data: optionsData,\n loading: optionsLoading,\n error: optionsError,\n } = useGetAnalyticsDashboardOptionsQuery({\n skip: !!appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const { data, loading, error } = useGetApplicationAnalyticsDashboardQuery({\n variables: {\n applicationId: selectedApplicationId || appId || \"\",\n period: \"daily\",\n startDate,\n endDate: now.toISOString(),\n },\n skip: !(selectedApplicationId || appId),\n fetchPolicy: \"cache-and-network\",\n });\n\n const allApplications: Application[] =\n optionsData?.applications?.edges?.map(\n (\n edge: GetAnalyticsDashboardOptionsQuery[\"applications\"][\"edges\"][number],\n ) => edge.node as Application,\n ) ?? [];\n // Scope the app picker to the active org when one is selected\n const applications = activeOrgId\n ? allApplications.filter((a) => a.developerOrganizationId === activeOrgId)\n : allApplications;\n const selectedApplication = data?.application;\n\n useEffect(() => {\n const name = selectedApplication?.name;\n const id = appId || selectedApplicationId;\n if (!id || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(id, name);\n return () => reg?.unregister(id);\n }, [appId, selectedApplicationId, selectedApplication?.name]);\n\n const analytics = [...(data?.applicationAnalytics ?? [])].sort(\n (left, right) =>\n new Date(left.date).getTime() - new Date(right.date).getTime(),\n );\n\n const latest = analytics[analytics.length - 1];\n const previous = analytics[analytics.length - 2];\n const chartData = analytics.map((entry) => ({\n date: new Date(entry.date).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n }),\n apiCalls: entry.apiCalls,\n errors: entry.errors,\n activeUsers: entry.activeUsers,\n newUsers: entry.newUsers,\n sessions: entry.sessions,\n avgResponseTime: entry.avgResponseTime ?? 0,\n }));\n\n const errorRate =\n latest && latest.apiCalls > 0 ? (latest.errors / latest.apiCalls) * 100 : 0;\n const previousErrorRate =\n previous && previous.apiCalls > 0\n ? (previous.errors / previous.apiCalls) * 100\n : 0;\n const responseTrend =\n latest?.avgResponseTime && previous?.avgResponseTime\n ? previous.avgResponseTime - latest.avgResponseTime\n : undefined;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n if (!appId && optionsLoading && !optionsData) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )}\n >\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n </PageLayout>\n );\n }\n\n if (!appId && optionsError) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.analytics.errorLoadApps\",\n \"Unable to load applications\",\n )}\n description={getErrorMessage(optionsError)}\n />\n </PageLayout>\n );\n }\n\n if (!appId && !selectedApplicationId) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.selectAppDescription\",\n \"Select an application to review live usage metrics from the public gateway\",\n )}\n >\n {applications.length > 0 ? (\n <div className=\"space-y-2\">\n {applications.map((application) => (\n <AppListItem\n key={application.id}\n app={application}\n onClick={() => setSelectedApplicationId(application.id)}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<BarChart3 size={32} />}\n title={tr(\n \"devportal.analytics.noAppsTitle\",\n \"No applications available\",\n )}\n description={tr(\n \"devportal.analytics.noAppsDescription\",\n \"Create an application before viewing analytics.\",\n )}\n />\n )}\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )}\n backLink={\n selectedApplicationId ? `/apps/${selectedApplicationId}` : undefined\n }\n backLabel={tr(\n \"devportal.analytics.backToApplication\",\n \"Back to Application\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.analytics.errorLoadAnalytics\",\n \"Unable to load analytics\",\n )}\n description={getErrorMessage(error)}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={\n appId\n ? tr(\"devportal.analytics.appTitle\", \"Application Analytics\")\n : tr(\"devportal.analytics.title\", \"Analytics\")\n }\n description={\n selectedApplication\n ? `${tr(\"devportal.analytics.liveUsageFor\", \"Live usage and performance for\")} ${selectedApplication.name}`\n : tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )\n }\n backLink={\n appId && selectedApplication\n ? `/apps/${selectedApplication.id}`\n : undefined\n }\n backLabel={tr(\n \"devportal.analytics.backToApplication\",\n \"Back to Application\",\n )}\n actions={\n <div className=\"flex flex-wrap gap-2\">\n {!appId && applications.length > 0 && (\n <select\n value={selectedApplicationId}\n onChange={(event) => setSelectedApplicationId(event.target.value)}\n aria-label={tr(\n \"devportal.analytics.selectAppAria\",\n \"Select application\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n {applications.map((application) => (\n <option key={application.id} value={application.id}>\n {application.name}\n </option>\n ))}\n </select>\n )}\n <select\n value={timeRange}\n onChange={(event) => setTimeRange(event.target.value as TimeRange)}\n aria-label={tr(\n \"devportal.analytics.selectRangeAria\",\n \"Select time range\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"7d\">\n {tr(\"devportal.analytics.range.7d\", \"Last 7 days\")}\n </option>\n <option value=\"30d\">\n {tr(\"devportal.analytics.range.30d\", \"Last 30 days\")}\n </option>\n <option value=\"90d\">\n {tr(\"devportal.analytics.range.90d\", \"Last 90 days\")}\n </option>\n </select>\n </div>\n }\n >\n {loading && !analytics.length ? (\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n ) : analytics.length > 0 ? (\n <>\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.analytics.apiCalls\", \"API Calls\")}\n value={(latest?.apiCalls ?? 0).toLocaleString()}\n icon={<Activity size={20} />}\n />\n <StatCard\n title={tr(\"devportal.analytics.activeUsers\", \"Active Users\")}\n value={(latest?.activeUsers ?? 0).toLocaleString()}\n icon={<Users size={20} />}\n />\n <StatCard\n title={tr(\"devportal.analytics.errorRate\", \"Error Rate\")}\n value={`${errorRate.toFixed(2)}%`}\n icon={<AlertTriangle size={20} />}\n trend={\n previous\n ? {\n value: previousErrorRate - errorRate,\n label: tr(\n \"devportal.analytics.vsPrevious\",\n \"vs previous period\",\n ),\n }\n : undefined\n }\n />\n <StatCard\n title={tr(\n \"devportal.analytics.avgResponseTime\",\n \"Avg Response Time\",\n )}\n value={\n latest?.avgResponseTime\n ? `${latest.avgResponseTime}ms`\n : tr(\"devportal.common.na\", \"N/A\")\n }\n icon={<Clock size={20} />}\n trend={\n typeof responseTrend === \"number\"\n ? {\n value: responseTrend,\n label: tr(\n \"devportal.analytics.fasterThanPrevious\",\n \"faster than previous\",\n ),\n }\n : undefined\n }\n />\n </StatCardGrid>\n\n <div className=\"grid gap-6 xl:grid-cols-2\">\n <PageSection\n title={tr(\"devportal.analytics.trafficTrend\", \"Traffic trend\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={300}>\n <LineChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Line\n type=\"monotone\"\n dataKey=\"apiCalls\"\n stroke={chartColors.primary}\n strokeWidth={2}\n dot={false}\n />\n <Line\n type=\"monotone\"\n dataKey=\"errors\"\n stroke={chartColors.negative}\n strokeWidth={2}\n dot={false}\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\"devportal.analytics.userActivity\", \"User activity\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={300}>\n <BarChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Bar\n dataKey=\"activeUsers\"\n fill={chartColors.primary}\n radius={[6, 6, 0, 0]}\n />\n <Bar\n dataKey=\"newUsers\"\n fill={chartColors.secondary}\n radius={[6, 6, 0, 0]}\n />\n </BarChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n </div>\n\n <PageSection\n title={tr(\"devportal.analytics.dailyBreakdown\", \"Daily breakdown\")}\n >\n <DataTable\n data={analytics}\n keyField=\"id\"\n columns={[\n {\n key: \"date\",\n header: tr(\"devportal.analytics.date\", \"Date\"),\n render: (entry) =>\n new Date(entry.date).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n }),\n },\n {\n key: \"apiCalls\",\n header: tr(\"devportal.analytics.apiCalls\", \"API Calls\"),\n render: (entry) => entry.apiCalls.toLocaleString(),\n },\n {\n key: \"errors\",\n header: tr(\"devportal.analytics.errors\", \"Errors\"),\n render: (entry) => entry.errors.toLocaleString(),\n },\n {\n key: \"activeUsers\",\n header: tr(\"devportal.analytics.activeUsers\", \"Active Users\"),\n render: (entry) => entry.activeUsers.toLocaleString(),\n },\n {\n key: \"newUsers\",\n header: tr(\"devportal.analytics.newUsers\", \"New Users\"),\n render: (entry) => entry.newUsers.toLocaleString(),\n },\n {\n key: \"avgResponseTime\",\n header: tr(\"devportal.analytics.avgResponse\", \"Avg Response\"),\n render: (entry) =>\n entry.avgResponseTime\n ? `${entry.avgResponseTime}ms`\n : tr(\"devportal.common.na\", \"N/A\"),\n },\n {\n key: \"sessions\",\n header: tr(\"devportal.analytics.sessions\", \"Sessions\"),\n render: (entry) => entry.sessions.toLocaleString(),\n },\n ]}\n />\n </PageSection>\n </>\n ) : (\n <EmptyState\n icon={<BarChart3 size={32} />}\n title={tr(\n \"devportal.analytics.noAnalyticsTitle\",\n \"No analytics available yet\",\n )}\n description={tr(\n \"devportal.analytics.noAnalyticsDescription\",\n \"Analytics will appear after this application starts receiving traffic through the public gateway.\",\n )}\n action={\n !appId ? (\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"/apps\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {tr(\n \"devportal.analytics.viewApplications\",\n \"View applications\",\n )}\n </button>\n ) : undefined\n }\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AnalyticsDashboardPage.js","names":[],"sources":["../../../src/devportal/pages/AnalyticsDashboardPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport {\n Activity,\n AlertCircle,\n AlertTriangle,\n BarChart3,\n Clock,\n Loader2,\n Users,\n} from \"lucide-react\";\nimport {\n Bar,\n BarChart,\n CartesianGrid,\n Line,\n LineChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { AppListItem } from \"../components/AppCard\";\nimport type { Application } from \"../types\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport {\n type GetAnalyticsDashboardOptionsQuery,\n getErrorMessage,\n useGetAnalyticsDashboardOptionsQuery,\n useGetApplicationAnalyticsDashboardQuery,\n} from \"../hooks\";\nimport { useTr } from \"../utils/i18n\";\n\ntype TimeRange = \"7d\" | \"30d\" | \"90d\";\n\nconst daysByRange: Record<TimeRange, number> = {\n \"7d\": 7,\n \"30d\": 30,\n \"90d\": 90,\n};\n\nconst chartColors = {\n primary: \"var(--color-chart-1)\",\n secondary: \"var(--color-chart-2)\",\n tertiary: \"var(--color-chart-4)\",\n negative: \"var(--color-chart-negative)\",\n};\n\nexport const AnalyticsDashboardPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath, activeOrgId } = useDevportal();\n const tr = useTr();\n const [timeRange, setTimeRange] = useState<TimeRange>(\"30d\");\n const [selectedApplicationId, setSelectedApplicationId] = useState(\n appId || \"\",\n );\n\n const now = useMemo(() => new Date(), []);\n const startDate = useMemo(() => {\n const nextDate = new Date(now);\n nextDate.setDate(nextDate.getDate() - daysByRange[timeRange]);\n return nextDate.toISOString();\n }, [now, timeRange]);\n\n const {\n data: optionsData,\n loading: optionsLoading,\n error: optionsError,\n } = useGetAnalyticsDashboardOptionsQuery({\n skip: !!appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const { data, loading, error } = useGetApplicationAnalyticsDashboardQuery({\n variables: {\n applicationId: selectedApplicationId || appId || \"\",\n period: \"daily\",\n startDate,\n endDate: now.toISOString(),\n },\n skip: !(selectedApplicationId || appId),\n fetchPolicy: \"cache-and-network\",\n });\n\n const allApplications: Application[] =\n optionsData?.applications?.edges?.map(\n (\n edge: GetAnalyticsDashboardOptionsQuery[\"applications\"][\"edges\"][number],\n ) => edge.node as Application,\n ) ?? [];\n // Scope the app picker to the active org when one is selected\n const applications = activeOrgId\n ? allApplications.filter((a) => a.developerOrganizationId === activeOrgId)\n : allApplications;\n const selectedApplication = data?.application;\n\n useEffect(() => {\n const name = selectedApplication?.name;\n const id = appId || selectedApplicationId;\n if (!id || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(id, name);\n return () => reg?.unregister(id);\n }, [appId, selectedApplicationId, selectedApplication?.name]);\n\n const analytics = [...(data?.applicationAnalytics ?? [])].sort(\n (left, right) =>\n new Date(left.date).getTime() - new Date(right.date).getTime(),\n );\n\n const latest = analytics[analytics.length - 1];\n const previous = analytics[analytics.length - 2];\n const chartData = analytics.map((entry) => ({\n date: new Date(entry.date).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n }),\n apiCalls: entry.apiCalls,\n errors: entry.errors,\n activeUsers: entry.activeUsers,\n newUsers: entry.newUsers,\n sessions: entry.sessions,\n avgResponseTime: entry.avgResponseTime ?? 0,\n }));\n\n const errorRate =\n latest && latest.apiCalls > 0 ? (latest.errors / latest.apiCalls) * 100 : 0;\n const previousErrorRate =\n previous && previous.apiCalls > 0\n ? (previous.errors / previous.apiCalls) * 100\n : 0;\n const responseTrend =\n latest?.avgResponseTime && previous?.avgResponseTime\n ? previous.avgResponseTime - latest.avgResponseTime\n : undefined;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n if (!appId && optionsLoading && !optionsData) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )}\n >\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n </PageLayout>\n );\n }\n\n if (!appId && optionsError) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.analytics.errorLoadApps\",\n \"Unable to load applications\",\n )}\n description={getErrorMessage(optionsError)}\n />\n </PageLayout>\n );\n }\n\n if (!appId && !selectedApplicationId) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.selectAppDescription\",\n \"Select an application to review live usage metrics from the public gateway\",\n )}\n >\n {applications.length > 0 ? (\n <div className=\"space-y-2\">\n {applications.map((application) => (\n <AppListItem\n key={application.id}\n app={application}\n onClick={() => setSelectedApplicationId(application.id)}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<BarChart3 size={32} />}\n title={tr(\n \"devportal.analytics.noAppsTitle\",\n \"No applications available\",\n )}\n description={tr(\n \"devportal.analytics.noAppsDescription\",\n \"Create an application before viewing analytics.\",\n )}\n />\n )}\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.analytics.title\", \"Analytics\")}\n description={tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )}\n backLink={\n selectedApplicationId ? `/apps/${selectedApplicationId}` : undefined\n }\n backLabel={tr(\n \"devportal.analytics.backToApplication\",\n \"Back to Application\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.analytics.errorLoadAnalytics\",\n \"Unable to load analytics\",\n )}\n description={getErrorMessage(error)}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={\n appId\n ? tr(\"devportal.analytics.appTitle\", \"Application Analytics\")\n : tr(\"devportal.analytics.title\", \"Analytics\")\n }\n description={\n selectedApplication\n ? `${tr(\"devportal.analytics.liveUsageFor\", \"Live usage and performance for\")} ${selectedApplication.name}`\n : tr(\n \"devportal.analytics.description\",\n \"Explore live application usage and performance metrics\",\n )\n }\n backLink={\n appId && selectedApplication\n ? `/apps/${selectedApplication.id}`\n : undefined\n }\n backLabel={tr(\n \"devportal.analytics.backToApplication\",\n \"Back to Application\",\n )}\n actions={\n <div className=\"flex flex-wrap gap-2\">\n {!appId && applications.length > 0 && (\n <select\n value={selectedApplicationId}\n onChange={(event) => setSelectedApplicationId(event.target.value)}\n aria-label={tr(\n \"devportal.analytics.selectAppAria\",\n \"Select application\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n {applications.map((application) => (\n <option key={application.id} value={application.id}>\n {application.name}\n </option>\n ))}\n </select>\n )}\n <select\n value={timeRange}\n onChange={(event) => setTimeRange(event.target.value as TimeRange)}\n aria-label={tr(\n \"devportal.analytics.selectRangeAria\",\n \"Select time range\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"7d\">\n {tr(\"devportal.analytics.range.7d\", \"Last 7 days\")}\n </option>\n <option value=\"30d\">\n {tr(\"devportal.analytics.range.30d\", \"Last 30 days\")}\n </option>\n <option value=\"90d\">\n {tr(\"devportal.analytics.range.90d\", \"Last 90 days\")}\n </option>\n </select>\n </div>\n }\n >\n {loading && !analytics.length ? (\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n ) : analytics.length > 0 ? (\n <>\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.analytics.apiCalls\", \"API Calls\")}\n value={(latest?.apiCalls ?? 0).toLocaleString()}\n icon={<Activity size={20} />}\n />\n <StatCard\n title={tr(\"devportal.analytics.activeUsers\", \"Active Users\")}\n value={(latest?.activeUsers ?? 0).toLocaleString()}\n icon={<Users size={20} />}\n />\n <StatCard\n title={tr(\"devportal.analytics.errorRate\", \"Error Rate\")}\n value={`${errorRate.toFixed(2)}%`}\n icon={<AlertTriangle size={20} />}\n trend={\n previous\n ? {\n value: previousErrorRate - errorRate,\n label: tr(\n \"devportal.analytics.vsPrevious\",\n \"vs previous period\",\n ),\n }\n : undefined\n }\n />\n <StatCard\n title={tr(\n \"devportal.analytics.avgResponseTime\",\n \"Avg Response Time\",\n )}\n value={\n latest?.avgResponseTime\n ? `${latest.avgResponseTime}ms`\n : tr(\"devportal.common.na\", \"N/A\")\n }\n icon={<Clock size={20} />}\n trend={\n typeof responseTrend === \"number\"\n ? {\n value: responseTrend,\n label: tr(\n \"devportal.analytics.fasterThanPrevious\",\n \"faster than previous\",\n ),\n }\n : undefined\n }\n />\n </StatCardGrid>\n\n <div className=\"grid gap-6 xl:grid-cols-2\">\n <PageSection\n title={tr(\"devportal.analytics.trafficTrend\", \"Traffic trend\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={300}>\n <LineChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Line\n type=\"monotone\"\n dataKey=\"apiCalls\"\n stroke={chartColors.primary}\n strokeWidth={2}\n dot={false}\n />\n <Line\n type=\"monotone\"\n dataKey=\"errors\"\n stroke={chartColors.negative}\n strokeWidth={2}\n dot={false}\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\"devportal.analytics.userActivity\", \"User activity\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={300}>\n <BarChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Bar\n dataKey=\"activeUsers\"\n fill={chartColors.primary}\n radius={[6, 6, 0, 0]}\n />\n <Bar\n dataKey=\"newUsers\"\n fill={chartColors.secondary}\n radius={[6, 6, 0, 0]}\n />\n </BarChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n </div>\n\n <PageSection\n title={tr(\"devportal.analytics.dailyBreakdown\", \"Daily breakdown\")}\n >\n <DataTable\n data={analytics}\n keyField=\"id\"\n columns={[\n {\n key: \"date\",\n header: tr(\"devportal.analytics.date\", \"Date\"),\n render: (entry) =>\n new Date(entry.date).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n }),\n },\n {\n key: \"apiCalls\",\n header: tr(\"devportal.analytics.apiCalls\", \"API Calls\"),\n render: (entry) => entry.apiCalls.toLocaleString(),\n },\n {\n key: \"errors\",\n header: tr(\"devportal.analytics.errors\", \"Errors\"),\n render: (entry) => entry.errors.toLocaleString(),\n },\n {\n key: \"activeUsers\",\n header: tr(\"devportal.analytics.activeUsers\", \"Active Users\"),\n render: (entry) => entry.activeUsers.toLocaleString(),\n },\n {\n key: \"newUsers\",\n header: tr(\"devportal.analytics.newUsers\", \"New Users\"),\n render: (entry) => entry.newUsers.toLocaleString(),\n },\n {\n key: \"avgResponseTime\",\n header: tr(\"devportal.analytics.avgResponse\", \"Avg Response\"),\n render: (entry) =>\n entry.avgResponseTime\n ? `${entry.avgResponseTime}ms`\n : tr(\"devportal.common.na\", \"N/A\"),\n },\n {\n key: \"sessions\",\n header: tr(\"devportal.analytics.sessions\", \"Sessions\"),\n render: (entry) => entry.sessions.toLocaleString(),\n },\n ]}\n />\n </PageSection>\n </>\n ) : (\n <EmptyState\n icon={<BarChart3 size={32} />}\n title={tr(\n \"devportal.analytics.noAnalyticsTitle\",\n \"No analytics available yet\",\n )}\n description={tr(\n \"devportal.analytics.noAnalyticsDescription\",\n \"Analytics will appear after this application starts receiving traffic through the public gateway.\",\n )}\n action={\n !appId ? (\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"/apps\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {tr(\n \"devportal.analytics.viewApplications\",\n \"View applications\",\n )}\n </button>\n ) : undefined\n }\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}