@burdenoff/microfe-devportal 2026.609.4 → 2026.611.1

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 (58) hide show
  1. package/dist/devportal/DevportalRoot.js +6 -1
  2. package/dist/devportal/DevportalRoot.js.map +1 -1
  3. package/dist/devportal/DevportalRoutes.js +169 -158
  4. package/dist/devportal/DevportalRoutes.js.map +1 -1
  5. package/dist/devportal/hooks/usePackageUpload.js +120 -0
  6. package/dist/devportal/hooks/usePackageUpload.js.map +1 -0
  7. package/dist/devportal/pages/AnalyticsDashboardPage.js +73 -62
  8. package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
  9. package/dist/devportal/pages/AppLogsPage.js +89 -82
  10. package/dist/devportal/pages/AppLogsPage.js.map +1 -1
  11. package/dist/devportal/pages/ApplicationDetailPage.js +948 -367
  12. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  13. package/dist/devportal/pages/ApplicationVersionsPage.js +56 -45
  14. package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
  15. package/dist/devportal/pages/CreateApiKeyPage.js +30 -32
  16. package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
  17. package/dist/devportal/pages/CreateApplicationPage.js +8 -3
  18. package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
  19. package/dist/devportal/pages/CreateOAuthClientPage.js +4 -4
  20. package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
  21. package/dist/devportal/pages/CreateOrganizationPage.js +233 -228
  22. package/dist/devportal/pages/CreateOrganizationPage.js.map +1 -1
  23. package/dist/devportal/pages/CreateWebhookPage.js +159 -148
  24. package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
  25. package/dist/devportal/pages/DelegationsPage.js +1 -1
  26. package/dist/devportal/pages/DelegationsPage.js.map +1 -1
  27. package/dist/devportal/pages/EditApplicationPage.js +25 -17
  28. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  29. package/dist/devportal/pages/ListingPreviewPage.js +159 -153
  30. package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
  31. package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
  32. package/dist/devportal/pages/OAuthClientsPage.js +2 -2
  33. package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
  34. package/dist/devportal/pages/OrganizationDetailPage.js +158 -153
  35. package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
  36. package/dist/devportal/pages/OrganizationMembersPage.js +223 -212
  37. package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
  38. package/dist/devportal/pages/PublishPage.js +172 -165
  39. package/dist/devportal/pages/PublishPage.js.map +1 -1
  40. package/dist/devportal/pages/ResourcesPage.js.map +1 -1
  41. package/dist/devportal/pages/RevenueDashboardPage.js +405 -0
  42. package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -0
  43. package/dist/devportal/pages/SetupPage.js +186 -181
  44. package/dist/devportal/pages/SetupPage.js.map +1 -1
  45. package/dist/devportal/pages/StoreSubmissionPage.js +76 -97
  46. package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
  47. package/dist/devportal/pages/WebhookDetailPage.js +172 -154
  48. package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
  49. package/dist/devportal/pages/WebhooksPage.js +218 -200
  50. package/dist/devportal/pages/WebhooksPage.js.map +1 -1
  51. package/dist/devportal/providers/DevportalProvider.js +16 -13
  52. package/dist/devportal/providers/DevportalProvider.js.map +1 -1
  53. package/dist/devportal/types/index.js.map +1 -1
  54. package/dist/generated/global-operations.js +310 -225
  55. package/dist/generated/global-operations.js.map +1 -1
  56. package/package.json +1 -1
  57. package/dist/devportal/pages/RevenueRedirectPage.js +0 -14
  58. package/dist/devportal/pages/RevenueRedirectPage.js.map +0 -1
@@ -5,146 +5,153 @@ import { useGetApplicationAuditLogsQuery as i } from "../../generated/global-ope
5
5
  import { getErrorMessage as a } from "../hooks/useGraphQL.js";
6
6
  import "../hooks/index.js";
7
7
  import o from "../../node_modules/date-fns/format.js";
8
- import { useMemo as s, useState as c } from "react";
9
- import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
- import { AlertCircle as u, Download as d, FileClock as f, Filter as p, Loader2 as m, RefreshCw as h } from "lucide-react";
11
- import { useParams as g } from "react-router-dom";
12
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
8
+ import { useEffect as s, useMemo as c, useState as l } from "react";
9
+ import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
+ import { AlertCircle as d, Download as f, FileClock as p, Filter as m, Loader2 as h, RefreshCw as g } from "lucide-react";
11
+ import { useParams as _ } from "react-router-dom";
12
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
13
13
  //#region src/devportal/pages/AppLogsPage.tsx
14
- var y = 25, b = (e) => o(new Date(e), "MMM d, yyyy HH:mm:ss"), x = (e) => e.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (e) => e.toUpperCase()), S = (e) => {
14
+ var b = 25, x = (e) => o(new Date(e), "MMM d, yyyy HH:mm:ss"), S = (e) => e.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (e) => e.toUpperCase()), C = (e) => {
15
15
  if (!e) return "";
16
16
  try {
17
17
  return JSON.stringify(e, null, 2);
18
18
  } catch {
19
19
  return "";
20
20
  }
21
- }, C = () => {
22
- let { t: o } = l(), { appId: C } = g(), { navigate: w, basePath: T, currentUser: E } = e(), D = (e) => E?.id === e && E.email ? E.email : e, [O, k] = c("all"), [A, j] = c(""), [M, N] = c(1), { data: P, loading: F, error: I, refetch: L } = i({
21
+ }, w = () => {
22
+ let { t: o } = u(), { appId: w } = _(), { navigate: T, basePath: E, currentUser: D } = e(), O = (e) => D?.id === e && D.email ? D.email : e, [k, A] = l("all"), [j, M] = l(""), [N, P] = l(1), { data: F, loading: I, error: L, refetch: R } = i({
23
23
  variables: {
24
- applicationId: C || "",
25
- limit: y,
26
- offset: (M - 1) * y
24
+ applicationId: w || "",
25
+ limit: b,
26
+ offset: (N - 1) * b
27
27
  },
28
- skip: !C,
28
+ skip: !w,
29
29
  fetchPolicy: "cache-and-network"
30
- }), R = P?.application, z = P?.auditLogs?.totalCount ?? 0, B = P?.auditLogs?.edges?.map((e) => e.node) ?? [], V = s(() => Array.from(new Set(B.map((e) => e.action))).sort((e, t) => e.localeCompare(t)), [B]), H = s(() => {
31
- let e = A.trim().toLowerCase();
32
- return B.filter((t) => O === "all" || t.action === O ? e ? [
30
+ }), z = F?.application;
31
+ s(() => {
32
+ let e = z?.name;
33
+ if (!w || !e) return;
34
+ let t = window.__breadcrumbRegistry;
35
+ return t?.register(w, e), () => t?.unregister(w);
36
+ }, [w, z?.name]);
37
+ let B = F?.auditLogs?.totalCount ?? 0, V = F?.auditLogs?.edges?.map((e) => e.node) ?? [], H = c(() => Array.from(new Set(V.map((e) => e.action))).sort((e, t) => e.localeCompare(t)), [V]), U = c(() => {
38
+ let e = j.trim().toLowerCase();
39
+ return V.filter((t) => k === "all" || t.action === k ? e ? [
33
40
  t.action,
34
41
  t.actorId,
35
- D(t.actorId),
42
+ O(t.actorId),
36
43
  t.resource,
37
- S(t.metadata)
44
+ C(t.metadata)
38
45
  ].join(" ").toLowerCase().includes(e) : !0 : !1);
39
46
  }, [
40
- O,
41
- B,
42
- A
47
+ k,
48
+ V,
49
+ j
43
50
  ]);
44
- return F && !P ? /* @__PURE__ */ _(n, {
51
+ return I && !F ? /* @__PURE__ */ v(n, {
45
52
  title: "Application Activity",
46
53
  description: "Loading application audit history",
47
- backLink: C ? `/apps/${C}` : "/apps",
54
+ backLink: w ? `/apps/${w}` : "/apps",
48
55
  backLabel: "Back to Application",
49
- children: /* @__PURE__ */ _("div", {
56
+ children: /* @__PURE__ */ v("div", {
50
57
  className: "flex items-center justify-center py-16 text-muted-foreground",
51
- children: /* @__PURE__ */ _(m, { className: "h-8 w-8 animate-spin" })
58
+ children: /* @__PURE__ */ v(h, { className: "h-8 w-8 animate-spin" })
52
59
  })
53
- }) : I || !R ? /* @__PURE__ */ _(n, {
60
+ }) : L || !z ? /* @__PURE__ */ v(n, {
54
61
  title: "Application Activity",
55
62
  description: "Review audit events for this application",
56
- backLink: C ? `/apps/${C}` : "/apps",
63
+ backLink: w ? `/apps/${w}` : "/apps",
57
64
  backLabel: "Back to Application",
58
- children: /* @__PURE__ */ _(t, {
59
- icon: /* @__PURE__ */ _(u, {
65
+ children: /* @__PURE__ */ v(t, {
66
+ icon: /* @__PURE__ */ v(d, {
60
67
  size: 32,
61
68
  className: "text-status-error-text"
62
69
  }),
63
70
  title: "Unable to load activity",
64
- description: I ? a(I) : "Application not found"
71
+ description: L ? a(L) : "Application not found"
65
72
  })
66
- }) : /* @__PURE__ */ v(n, {
73
+ }) : /* @__PURE__ */ y(n, {
67
74
  title: "Application Activity",
68
- description: `Audit events for ${R.name}`,
69
- backLink: `/apps/${R.id}`,
75
+ description: `Audit events for ${z.name}`,
76
+ backLink: `/apps/${z.id}`,
70
77
  backLabel: "Back to Application",
71
- actions: /* @__PURE__ */ v("div", {
78
+ actions: /* @__PURE__ */ y("div", {
72
79
  className: "flex flex-wrap gap-2",
73
- children: [/* @__PURE__ */ v("button", {
80
+ children: [/* @__PURE__ */ y("button", {
74
81
  type: "button",
75
- onClick: () => void L(),
82
+ onClick: () => void R(),
76
83
  className: "inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent",
77
- children: [/* @__PURE__ */ _(h, { size: 16 }), "Refresh"]
78
- }), /* @__PURE__ */ v("button", {
84
+ children: [/* @__PURE__ */ v(g, { size: 16 }), "Refresh"]
85
+ }), /* @__PURE__ */ y("button", {
79
86
  type: "button",
80
87
  onClick: () => {
81
- let e = new Blob([JSON.stringify(H, null, 2)], { type: "application/json" }), t = URL.createObjectURL(e), n = document.createElement("a");
82
- n.href = t, n.download = `${R?.slug || C || "application"}-audit-log.json`, n.click(), URL.revokeObjectURL(t);
88
+ let e = new Blob([JSON.stringify(U, null, 2)], { type: "application/json" }), t = URL.createObjectURL(e), n = document.createElement("a");
89
+ n.href = t, n.download = `${z?.slug || w || "application"}-audit-log.json`, n.click(), URL.revokeObjectURL(t);
83
90
  },
84
91
  className: "inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent",
85
- children: [/* @__PURE__ */ _(d, { size: 16 }), "Export JSON"]
92
+ children: [/* @__PURE__ */ v(f, { size: 16 }), "Export JSON"]
86
93
  })]
87
94
  }),
88
95
  children: [
89
- /* @__PURE__ */ v("div", {
96
+ /* @__PURE__ */ y("div", {
90
97
  className: "grid gap-4 rounded-lg border bg-card p-4 lg:grid-cols-[220px_minmax(0,1fr)_auto] lg:items-center",
91
98
  children: [
92
- /* @__PURE__ */ v("label", {
99
+ /* @__PURE__ */ y("label", {
93
100
  className: "grid gap-2 text-sm font-medium",
94
- children: [/* @__PURE__ */ v("span", {
101
+ children: [/* @__PURE__ */ y("span", {
95
102
  className: "flex items-center gap-2 text-muted-foreground",
96
- children: [/* @__PURE__ */ _(p, { size: 16 }), "Filter by action"]
97
- }), /* @__PURE__ */ v("select", {
98
- value: O,
99
- onChange: (e) => k(e.target.value),
103
+ children: [/* @__PURE__ */ v(m, { size: 16 }), "Filter by action"]
104
+ }), /* @__PURE__ */ y("select", {
105
+ value: k,
106
+ onChange: (e) => A(e.target.value),
100
107
  className: "rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
101
- children: [/* @__PURE__ */ _("option", {
108
+ children: [/* @__PURE__ */ v("option", {
102
109
  value: "all",
103
110
  children: "All actions"
104
- }), V.map((e) => /* @__PURE__ */ _("option", {
111
+ }), H.map((e) => /* @__PURE__ */ v("option", {
105
112
  value: e,
106
- children: x(e)
113
+ children: S(e)
107
114
  }, e))]
108
115
  })]
109
116
  }),
110
- /* @__PURE__ */ v("label", {
117
+ /* @__PURE__ */ y("label", {
111
118
  className: "grid gap-2 text-sm font-medium",
112
- children: [/* @__PURE__ */ _("span", {
119
+ children: [/* @__PURE__ */ v("span", {
113
120
  className: "text-muted-foreground",
114
121
  children: "Search metadata"
115
- }), /* @__PURE__ */ _("input", {
122
+ }), /* @__PURE__ */ v("input", {
116
123
  type: "text",
117
- value: A,
118
- onChange: (e) => j(e.target.value),
124
+ value: j,
125
+ onChange: (e) => M(e.target.value),
119
126
  placeholder: "Search actor, action, or metadata",
120
127
  className: "rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
121
128
  })]
122
129
  }),
123
- /* @__PURE__ */ v("div", {
130
+ /* @__PURE__ */ y("div", {
124
131
  className: "rounded-full bg-muted px-3 py-2 text-sm text-muted-foreground",
125
- children: [z, " total events"]
132
+ children: [B, " total events"]
126
133
  })
127
134
  ]
128
135
  }),
129
- /* @__PURE__ */ _(r, { children: H.length > 0 ? /* @__PURE__ */ _("div", {
136
+ /* @__PURE__ */ v(r, { children: U.length > 0 ? /* @__PURE__ */ v("div", {
130
137
  className: "space-y-3 rounded-lg border bg-card p-4",
131
- children: H.map((e) => /* @__PURE__ */ v("article", {
138
+ children: U.map((e) => /* @__PURE__ */ y("article", {
132
139
  className: "rounded-lg border bg-background p-4",
133
140
  children: [
134
- /* @__PURE__ */ v("div", {
141
+ /* @__PURE__ */ y("div", {
135
142
  className: "flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between",
136
- children: [/* @__PURE__ */ v("div", {
143
+ children: [/* @__PURE__ */ y("div", {
137
144
  className: "space-y-2",
138
- children: [/* @__PURE__ */ v("div", {
145
+ children: [/* @__PURE__ */ y("div", {
139
146
  className: "flex flex-wrap items-center gap-2",
140
- children: [/* @__PURE__ */ _("span", {
147
+ children: [/* @__PURE__ */ v("span", {
141
148
  className: "rounded-full bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary",
142
- children: x(e.action)
143
- }), /* @__PURE__ */ v("span", {
149
+ children: S(e.action)
150
+ }), /* @__PURE__ */ y("span", {
144
151
  className: "text-xs text-muted-foreground",
145
- children: ["Actor ", D(e.actorId)]
152
+ children: ["Actor ", O(e.actorId)]
146
153
  })]
147
- }), /* @__PURE__ */ v("p", {
154
+ }), /* @__PURE__ */ y("p", {
148
155
  className: "text-sm text-muted-foreground",
149
156
  children: [
150
157
  "Resource: ",
@@ -152,45 +159,45 @@ var y = 25, b = (e) => o(new Date(e), "MMM d, yyyy HH:mm:ss"), x = (e) => e.repl
152
159
  e.resourceId ? ` · ${e.resourceId}` : ""
153
160
  ]
154
161
  })]
155
- }), /* @__PURE__ */ _("time", {
162
+ }), /* @__PURE__ */ v("time", {
156
163
  className: "text-xs text-muted-foreground",
157
- children: b(e.createdAt)
164
+ children: x(e.createdAt)
158
165
  })]
159
166
  }),
160
- e.metadata && /* @__PURE__ */ _("pre", {
167
+ e.metadata && /* @__PURE__ */ v("pre", {
161
168
  className: "mt-3 overflow-x-auto rounded-md bg-muted p-3 text-xs text-foreground",
162
- children: S(e.metadata)
169
+ children: C(e.metadata)
163
170
  }),
164
- e.changes && /* @__PURE__ */ v("details", {
171
+ e.changes && /* @__PURE__ */ y("details", {
165
172
  className: "mt-3 rounded-md border bg-card p-3",
166
- children: [/* @__PURE__ */ _("summary", {
173
+ children: [/* @__PURE__ */ v("summary", {
167
174
  className: "cursor-pointer text-sm font-medium text-foreground",
168
175
  children: "View captured changes"
169
- }), /* @__PURE__ */ _("pre", {
176
+ }), /* @__PURE__ */ v("pre", {
170
177
  className: "mt-3 overflow-x-auto text-xs text-muted-foreground",
171
- children: S(e.changes)
178
+ children: C(e.changes)
172
179
  })]
173
180
  })
174
181
  ]
175
182
  }, e.id))
176
- }) : /* @__PURE__ */ _(t, {
177
- icon: /* @__PURE__ */ _(f, { size: 24 }),
183
+ }) : /* @__PURE__ */ v(t, {
184
+ icon: /* @__PURE__ */ v(p, { size: 24 }),
178
185
  title: "No audit events found",
179
186
  description: "Events will appear here after application or webhook actions are performed through the public gateway."
180
187
  }) }),
181
- P.auditLogs?.pageInfo?.hasNextPage && /* @__PURE__ */ _("div", {
188
+ F.auditLogs?.pageInfo?.hasNextPage && /* @__PURE__ */ v("div", {
182
189
  className: "flex justify-center",
183
- children: /* @__PURE__ */ v("button", {
190
+ children: /* @__PURE__ */ y("button", {
184
191
  type: "button",
185
- onClick: () => N((e) => e + 1),
192
+ onClick: () => P((e) => e + 1),
186
193
  className: "inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-accent",
187
- children: [/* @__PURE__ */ _(h, { size: 16 }), "Next page"]
194
+ children: [/* @__PURE__ */ v(g, { size: 16 }), "Next page"]
188
195
  })
189
196
  })
190
197
  ]
191
198
  });
192
199
  };
193
200
  //#endregion
194
- export { C as AppLogsPage };
201
+ export { w as AppLogsPage };
195
202
 
196
203
  //# sourceMappingURL=AppLogsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppLogsPage.js","names":[],"sources":["../../../src/devportal/pages/AppLogsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Download,\n Filter,\n Loader2,\n RefreshCw,\n AlertCircle,\n FileClock,\n} from \"lucide-react\";\nimport { format } from \"date-fns\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport {\n type GetApplicationAuditLogsQuery,\n getErrorMessage,\n useGetApplicationAuditLogsQuery,\n} from \"../hooks\";\n\nconst PAGE_SIZE = 25;\ntype AuditLogEntry =\n GetApplicationAuditLogsQuery[\"auditLogs\"][\"edges\"][number][\"node\"];\n\nconst formatTimestamp = (value: string) =>\n format(new Date(value), \"MMM d, yyyy HH:mm:ss\");\n\nconst formatAction = (value: string) =>\n value\n .replace(/_/g, \" \")\n .toLowerCase()\n .replace(/\\b\\w/g, (character) => character.toUpperCase());\n\nconst metadataPreview = (metadata: unknown): string => {\n if (!metadata) return \"\";\n\n try {\n return JSON.stringify(metadata, null, 2);\n } catch {\n return \"\";\n }\n};\n\nexport const AppLogsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath, currentUser } = useDevportal();\n const resolveActorLabel = (actorId: string): string => {\n if (currentUser?.id === actorId && currentUser.email)\n return currentUser.email;\n return actorId;\n };\n const [actionFilter, setActionFilter] = useState(\"all\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [page, setPage] = useState(1);\n\n const { data, loading, error, refetch } = useGetApplicationAuditLogsQuery({\n variables: {\n applicationId: appId || \"\",\n limit: PAGE_SIZE,\n offset: (page - 1) * PAGE_SIZE,\n },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const application = data?.application;\n const totalCount = data?.auditLogs?.totalCount ?? 0;\n const auditLogs: AuditLogEntry[] =\n data?.auditLogs?.edges?.map(\n (edge: GetApplicationAuditLogsQuery[\"auditLogs\"][\"edges\"][number]) =>\n edge.node,\n ) ?? [];\n\n const availableActions = useMemo(\n () =>\n Array.from(\n new Set(auditLogs.map((entry: AuditLogEntry) => entry.action)),\n ).sort((left, right) => left.localeCompare(right)),\n [auditLogs],\n );\n\n const filteredLogs = useMemo(() => {\n const normalizedQuery = searchQuery.trim().toLowerCase();\n\n return auditLogs.filter((entry: AuditLogEntry) => {\n const matchesAction =\n actionFilter === \"all\" || entry.action === actionFilter;\n if (!matchesAction) return false;\n\n if (!normalizedQuery) return true;\n\n const haystack = [\n entry.action,\n entry.actorId,\n resolveActorLabel(entry.actorId),\n entry.resource,\n metadataPreview(entry.metadata),\n ]\n .join(\" \")\n .toLowerCase();\n\n return haystack.includes(normalizedQuery);\n });\n }, [actionFilter, auditLogs, searchQuery]);\n\n const exportPayload = () => {\n const blob = new Blob([JSON.stringify(filteredLogs, null, 2)], {\n type: \"application/json\",\n });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = `${application?.slug || appId || \"application\"}-audit-log.json`;\n anchor.click();\n URL.revokeObjectURL(url);\n };\n\n if (loading && !data) {\n return (\n <PageLayout\n title=\"Application Activity\"\n description=\"Loading application audit history\"\n backLink={appId ? `/apps/${appId}` : \"/apps\"}\n backLabel=\"Back to Application\"\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 (error || !application) {\n return (\n <PageLayout\n title=\"Application Activity\"\n description=\"Review audit events for this application\"\n backLink={appId ? `/apps/${appId}` : \"/apps\"}\n backLabel=\"Back to Application\"\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title=\"Unable to load activity\"\n description={error ? getErrorMessage(error) : \"Application not found\"}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Application Activity\"\n description={`Audit events for ${application.name}`}\n backLink={`/apps/${application.id}`}\n backLabel=\"Back to Application\"\n actions={\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent\"\n >\n <RefreshCw size={16} />\n Refresh\n </button>\n <button\n type=\"button\"\n onClick={exportPayload}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent\"\n >\n <Download size={16} />\n Export JSON\n </button>\n </div>\n }\n >\n <div className=\"grid gap-4 rounded-lg border bg-card p-4 lg:grid-cols-[220px_minmax(0,1fr)_auto] lg:items-center\">\n <label className=\"grid gap-2 text-sm font-medium\">\n <span className=\"flex items-center gap-2 text-muted-foreground\">\n <Filter size={16} />\n Filter by action\n </span>\n <select\n value={actionFilter}\n onChange={(event) => setActionFilter(event.target.value)}\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=\"all\">All actions</option>\n {availableActions.map((action) => (\n <option key={action} value={action}>\n {formatAction(action)}\n </option>\n ))}\n </select>\n </label>\n\n <label className=\"grid gap-2 text-sm font-medium\">\n <span className=\"text-muted-foreground\">Search metadata</span>\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.target.value)}\n placeholder=\"Search actor, action, or metadata\"\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </label>\n\n <div className=\"rounded-full bg-muted px-3 py-2 text-sm text-muted-foreground\">\n {totalCount} total events\n </div>\n </div>\n\n <PageSection>\n {filteredLogs.length > 0 ? (\n <div className=\"space-y-3 rounded-lg border bg-card p-4\">\n {filteredLogs.map((entry: AuditLogEntry) => (\n <article\n key={entry.id}\n className=\"rounded-lg border bg-background p-4\"\n >\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary\">\n {formatAction(entry.action)}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n Actor {resolveActorLabel(entry.actorId)}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n Resource: {entry.resource}\n {entry.resourceId ? ` · ${entry.resourceId}` : \"\"}\n </p>\n </div>\n\n <time className=\"text-xs text-muted-foreground\">\n {formatTimestamp(entry.createdAt)}\n </time>\n </div>\n\n {entry.metadata && (\n <pre className=\"mt-3 overflow-x-auto rounded-md bg-muted p-3 text-xs text-foreground\">\n {metadataPreview(entry.metadata)}\n </pre>\n )}\n\n {entry.changes && (\n <details className=\"mt-3 rounded-md border bg-card p-3\">\n <summary className=\"cursor-pointer text-sm font-medium text-foreground\">\n View captured changes\n </summary>\n <pre className=\"mt-3 overflow-x-auto text-xs text-muted-foreground\">\n {metadataPreview(entry.changes)}\n </pre>\n </details>\n )}\n </article>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<FileClock size={24} />}\n title=\"No audit events found\"\n description=\"Events will appear here after application or webhook actions are performed through the public gateway.\"\n />\n )}\n </PageSection>\n\n {data.auditLogs?.pageInfo?.hasNextPage && (\n <div className=\"flex justify-center\">\n <button\n type=\"button\"\n onClick={() => setPage((previous) => previous + 1)}\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-accent\"\n >\n <RefreshCw size={16} />\n Next page\n </button>\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AppLogsPage.js","names":[],"sources":["../../../src/devportal/pages/AppLogsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Download,\n Filter,\n Loader2,\n RefreshCw,\n AlertCircle,\n FileClock,\n} from \"lucide-react\";\nimport { format } from \"date-fns\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport {\n type GetApplicationAuditLogsQuery,\n getErrorMessage,\n useGetApplicationAuditLogsQuery,\n} from \"../hooks\";\n\nconst PAGE_SIZE = 25;\ntype AuditLogEntry =\n GetApplicationAuditLogsQuery[\"auditLogs\"][\"edges\"][number][\"node\"];\n\nconst formatTimestamp = (value: string) =>\n format(new Date(value), \"MMM d, yyyy HH:mm:ss\");\n\nconst formatAction = (value: string) =>\n value\n .replace(/_/g, \" \")\n .toLowerCase()\n .replace(/\\b\\w/g, (character) => character.toUpperCase());\n\nconst metadataPreview = (metadata: unknown): string => {\n if (!metadata) return \"\";\n\n try {\n return JSON.stringify(metadata, null, 2);\n } catch {\n return \"\";\n }\n};\n\nexport const AppLogsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath, currentUser } = useDevportal();\n const resolveActorLabel = (actorId: string): string => {\n if (currentUser?.id === actorId && currentUser.email)\n return currentUser.email;\n return actorId;\n };\n const [actionFilter, setActionFilter] = useState(\"all\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [page, setPage] = useState(1);\n\n const { data, loading, error, refetch } = useGetApplicationAuditLogsQuery({\n variables: {\n applicationId: appId || \"\",\n limit: PAGE_SIZE,\n offset: (page - 1) * PAGE_SIZE,\n },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const application = data?.application;\n\n useEffect(() => {\n const name = application?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, application?.name]);\n\n const totalCount = data?.auditLogs?.totalCount ?? 0;\n const auditLogs: AuditLogEntry[] =\n data?.auditLogs?.edges?.map(\n (edge: GetApplicationAuditLogsQuery[\"auditLogs\"][\"edges\"][number]) =>\n edge.node,\n ) ?? [];\n\n const availableActions = useMemo(\n () =>\n Array.from(\n new Set(auditLogs.map((entry: AuditLogEntry) => entry.action)),\n ).sort((left, right) => left.localeCompare(right)),\n [auditLogs],\n );\n\n const filteredLogs = useMemo(() => {\n const normalizedQuery = searchQuery.trim().toLowerCase();\n\n return auditLogs.filter((entry: AuditLogEntry) => {\n const matchesAction =\n actionFilter === \"all\" || entry.action === actionFilter;\n if (!matchesAction) return false;\n\n if (!normalizedQuery) return true;\n\n const haystack = [\n entry.action,\n entry.actorId,\n resolveActorLabel(entry.actorId),\n entry.resource,\n metadataPreview(entry.metadata),\n ]\n .join(\" \")\n .toLowerCase();\n\n return haystack.includes(normalizedQuery);\n });\n }, [actionFilter, auditLogs, searchQuery]);\n\n const exportPayload = () => {\n const blob = new Blob([JSON.stringify(filteredLogs, null, 2)], {\n type: \"application/json\",\n });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = `${application?.slug || appId || \"application\"}-audit-log.json`;\n anchor.click();\n URL.revokeObjectURL(url);\n };\n\n if (loading && !data) {\n return (\n <PageLayout\n title=\"Application Activity\"\n description=\"Loading application audit history\"\n backLink={appId ? `/apps/${appId}` : \"/apps\"}\n backLabel=\"Back to Application\"\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 (error || !application) {\n return (\n <PageLayout\n title=\"Application Activity\"\n description=\"Review audit events for this application\"\n backLink={appId ? `/apps/${appId}` : \"/apps\"}\n backLabel=\"Back to Application\"\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title=\"Unable to load activity\"\n description={error ? getErrorMessage(error) : \"Application not found\"}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Application Activity\"\n description={`Audit events for ${application.name}`}\n backLink={`/apps/${application.id}`}\n backLabel=\"Back to Application\"\n actions={\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => void refetch()}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent\"\n >\n <RefreshCw size={16} />\n Refresh\n </button>\n <button\n type=\"button\"\n onClick={exportPayload}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-accent\"\n >\n <Download size={16} />\n Export JSON\n </button>\n </div>\n }\n >\n <div className=\"grid gap-4 rounded-lg border bg-card p-4 lg:grid-cols-[220px_minmax(0,1fr)_auto] lg:items-center\">\n <label className=\"grid gap-2 text-sm font-medium\">\n <span className=\"flex items-center gap-2 text-muted-foreground\">\n <Filter size={16} />\n Filter by action\n </span>\n <select\n value={actionFilter}\n onChange={(event) => setActionFilter(event.target.value)}\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=\"all\">All actions</option>\n {availableActions.map((action) => (\n <option key={action} value={action}>\n {formatAction(action)}\n </option>\n ))}\n </select>\n </label>\n\n <label className=\"grid gap-2 text-sm font-medium\">\n <span className=\"text-muted-foreground\">Search metadata</span>\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.target.value)}\n placeholder=\"Search actor, action, or metadata\"\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </label>\n\n <div className=\"rounded-full bg-muted px-3 py-2 text-sm text-muted-foreground\">\n {totalCount} total events\n </div>\n </div>\n\n <PageSection>\n {filteredLogs.length > 0 ? (\n <div className=\"space-y-3 rounded-lg border bg-card p-4\">\n {filteredLogs.map((entry: AuditLogEntry) => (\n <article\n key={entry.id}\n className=\"rounded-lg border bg-background p-4\"\n >\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary\">\n {formatAction(entry.action)}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n Actor {resolveActorLabel(entry.actorId)}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n Resource: {entry.resource}\n {entry.resourceId ? ` · ${entry.resourceId}` : \"\"}\n </p>\n </div>\n\n <time className=\"text-xs text-muted-foreground\">\n {formatTimestamp(entry.createdAt)}\n </time>\n </div>\n\n {entry.metadata && (\n <pre className=\"mt-3 overflow-x-auto rounded-md bg-muted p-3 text-xs text-foreground\">\n {metadataPreview(entry.metadata)}\n </pre>\n )}\n\n {entry.changes && (\n <details className=\"mt-3 rounded-md border bg-card p-3\">\n <summary className=\"cursor-pointer text-sm font-medium text-foreground\">\n View captured changes\n </summary>\n <pre className=\"mt-3 overflow-x-auto text-xs text-muted-foreground\">\n {metadataPreview(entry.changes)}\n </pre>\n </details>\n )}\n </article>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<FileClock size={24} />}\n title=\"No audit events found\"\n description=\"Events will appear here after application or webhook actions are performed through the public gateway.\"\n />\n )}\n </PageSection>\n\n {data.auditLogs?.pageInfo?.hasNextPage && (\n <div className=\"flex justify-center\">\n <button\n type=\"button\"\n onClick={() => setPage((previous) => previous + 1)}\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-accent\"\n >\n <RefreshCw size={16} />\n Next page\n </button>\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}