@burdenoff/microfe-devportal 2026.611.2 → 2026.616.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.
- package/dist/devportal/components/SectionNav.js +105 -41
- package/dist/devportal/components/SectionNav.js.map +1 -1
- package/dist/devportal/hooks/useGraphQL.js +1 -1
- package/dist/devportal/pages/AdminReviewPage.js +36 -36
- package/dist/devportal/pages/AnalyticsDashboardPage.js +150 -150
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/ApiKeysPage.js +184 -172
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +9 -9
- package/dist/devportal/pages/ApplicationDetailPage.js +414 -414
- package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +44 -44
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationsPage.js +118 -118
- package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +20 -20
- package/dist/devportal/pages/CreateApplicationPage.js +46 -66
- package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
- package/dist/devportal/pages/CreateOAuthClientPage.js +20 -20
- package/dist/devportal/pages/CreateOrganizationPage.js +125 -442
- package/dist/devportal/pages/CreateOrganizationPage.js.map +1 -1
- package/dist/devportal/pages/CreateWebhookPage.js +25 -25
- package/dist/devportal/pages/DashboardPage.js +160 -145
- package/dist/devportal/pages/DashboardPage.js.map +1 -1
- package/dist/devportal/pages/DelegationsPage.js +22 -22
- package/dist/devportal/pages/EditApplicationPage.js +297 -317
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +9 -9
- package/dist/devportal/pages/OAuthClientDetailPage.js +17 -17
- package/dist/devportal/pages/OAuthClientsPage.js +16 -16
- package/dist/devportal/pages/OrganizationDetailPage.js +78 -78
- package/dist/devportal/pages/OrganizationMembersPage.js +260 -260
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +18 -18
- package/dist/devportal/pages/PublishPage.js +16 -16
- package/dist/devportal/pages/PublisherProfilePage.js +156 -146
- package/dist/devportal/pages/PublisherProfilePage.js.map +1 -1
- package/dist/devportal/pages/RevenueDashboardPage.js +512 -362
- package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -1
- package/dist/devportal/pages/SettingsPage.js +17 -17
- package/dist/devportal/pages/SetupPage.js +99 -99
- package/dist/devportal/pages/SetupPage.js.map +1 -1
- package/dist/devportal/pages/WebhookDetailPage.js +143 -143
- package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +140 -140
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/dist/devportal/providers/DevportalProvider.js +46 -33
- package/dist/devportal/providers/DevportalProvider.js.map +1 -1
- package/dist/generated/global-operations.js +69 -55
- package/dist/generated/global-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { useDevportal as e } from "../providers/DevportalProvider.js";
|
|
2
2
|
import { EmptyState as t } from "../components/EmptyState.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
3
|
+
import { useDeactivateAppMutation as n, useDeleteApplicationMutation as r, useGetApplicationsQuery as ee } from "../../generated/global-operations.js";
|
|
4
|
+
import { getErrorMessage as te } from "../hooks/useGraphQL.js";
|
|
5
|
+
import { PageLayout as i } from "../components/PageLayout.js";
|
|
6
|
+
import { APP_STATUS_COLORS as ne, APP_TYPE_LABELS as a } from "../utils/constants.js";
|
|
7
|
+
import { SelectionCheckbox as re } from "../components/SelectionCheckbox.js";
|
|
8
|
+
import { AppCard as ie, AppListItem as ae } from "../components/AppCard.js";
|
|
9
|
+
import { ConfirmDialog as o } from "../components/ConfirmDialog.js";
|
|
10
|
+
import { PermissionGuard as oe } from "../components/PermissionGuard.js";
|
|
10
11
|
import "../components/index.js";
|
|
11
|
-
import { DEVPORTAL_PERMISSIONS as
|
|
12
|
-
import {
|
|
13
|
-
import { useDevportalPermission as f } from "../hooks/usePermission.js";
|
|
12
|
+
import { DEVPORTAL_PERMISSIONS as s } from "../constants/permissions.js";
|
|
13
|
+
import { useDevportalPermission as c } from "../hooks/usePermission.js";
|
|
14
14
|
import "../hooks/index.js";
|
|
15
|
-
import { useMemo as
|
|
16
|
-
import { useI18n as
|
|
17
|
-
import { AlertCircle as
|
|
18
|
-
import { jsx as
|
|
15
|
+
import { useMemo as l, useState as u } from "react";
|
|
16
|
+
import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
17
|
+
import { AlertCircle as f, AppWindow as p, Archive as m, Grid as h, List as g, Loader2 as se, Plus as _, Search as ce, Trash2 as le } from "lucide-react";
|
|
18
|
+
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
19
19
|
//#region src/devportal/pages/ApplicationsPage.tsx
|
|
20
|
-
function
|
|
20
|
+
function b(e, t, n) {
|
|
21
21
|
return `${e} ${t} application${t === 1 ? "" : "s"}${n > 0 ? ` • ${n} failed` : ""}`;
|
|
22
22
|
}
|
|
23
|
-
function
|
|
23
|
+
function ue(e) {
|
|
24
24
|
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;
|
|
25
25
|
return {
|
|
26
26
|
id: e.id,
|
|
@@ -66,190 +66,190 @@ function C(e) {
|
|
|
66
66
|
updatedAt: e.updatedAt
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
var
|
|
70
|
-
let { navigate:
|
|
71
|
-
let n =
|
|
69
|
+
var x = () => {
|
|
70
|
+
let { navigate: x, basePath: S, activeOrgId: C } = e(), { t: w } = d(), T = (e, t) => {
|
|
71
|
+
let n = w(e);
|
|
72
72
|
return n === e ? t : n;
|
|
73
|
-
}, E =
|
|
73
|
+
}, E = c(s.APP_CREATE), D = c(s.APP_DELETE), O = c(s.APP_UPDATE), [k, A] = u("grid"), [j, de] = u(""), [M, N] = u(""), [P, F] = u(""), [I, L] = u(/* @__PURE__ */ new Set()), [R, z] = u(null), [B, V] = u(null), { data: H, loading: fe, error: U, refetch: W } = ee({
|
|
74
74
|
variables: {
|
|
75
75
|
limit: 50,
|
|
76
76
|
offset: 0,
|
|
77
|
-
status:
|
|
77
|
+
status: M || void 0
|
|
78
78
|
},
|
|
79
79
|
fetchPolicy: "cache-and-network"
|
|
80
|
-
}),
|
|
81
|
-
|
|
82
|
-
}, J =
|
|
83
|
-
let t = !j || e.name.toLowerCase().includes(j.toLowerCase()) || e.shortDescription?.toLowerCase().includes(j.toLowerCase()),
|
|
84
|
-
return t && n;
|
|
85
|
-
}), Y =
|
|
86
|
-
|
|
80
|
+
}), G = l(() => H?.applications?.edges?.map((e) => ue(e.node)) ?? [], [H?.applications?.edges]), [pe] = r(), [K] = n(), q = (e) => {
|
|
81
|
+
x?.(`${S}${e}`);
|
|
82
|
+
}, J = G.filter((e) => {
|
|
83
|
+
let t = !C || e.developerOrganizationId === C, n = !j || e.name.toLowerCase().includes(j.toLowerCase()) || e.shortDescription?.toLowerCase().includes(j.toLowerCase()), r = !P || e.appType === P;
|
|
84
|
+
return t && n && r;
|
|
85
|
+
}), Y = l(() => G.filter((e) => I.has(e.id)), [G, I]), X = l(() => Y.filter((e) => e.status !== "INACTIVE" && e.status !== "REVOKED"), [Y]), Z = J.length > 0 && J.every((e) => I.has(e.id)), me = J.some((e) => I.has(e.id)) && !Z, Q = (e, t) => {
|
|
86
|
+
L((n) => {
|
|
87
87
|
let r = new Set(n);
|
|
88
88
|
return t ? r.add(e) : r.delete(e), r;
|
|
89
89
|
});
|
|
90
|
-
},
|
|
91
|
-
|
|
90
|
+
}, he = (e) => {
|
|
91
|
+
L((t) => {
|
|
92
92
|
let n = new Set(t);
|
|
93
93
|
return J.forEach((t) => {
|
|
94
94
|
e ? n.add(t.id) : n.delete(t.id);
|
|
95
95
|
}), n;
|
|
96
96
|
});
|
|
97
|
-
}, $ = () =>
|
|
98
|
-
return
|
|
97
|
+
}, $ = () => L(/* @__PURE__ */ new Set());
|
|
98
|
+
return fe && !H ? /* @__PURE__ */ v(i, {
|
|
99
99
|
title: T("devportal.myApplications", "My Applications"),
|
|
100
100
|
description: T("devportal.manageYourApps", "Manage your developer applications"),
|
|
101
|
-
children: /* @__PURE__ */
|
|
101
|
+
children: /* @__PURE__ */ y("div", {
|
|
102
102
|
className: "flex items-center justify-center py-12",
|
|
103
|
-
children: [/* @__PURE__ */
|
|
103
|
+
children: [/* @__PURE__ */ v(se, { className: "h-8 w-8 animate-spin text-muted-foreground" }), /* @__PURE__ */ v("span", {
|
|
104
104
|
className: "ml-2 text-muted-foreground",
|
|
105
105
|
children: T("devportal.loadingApplications", "Loading applications...")
|
|
106
106
|
})]
|
|
107
107
|
})
|
|
108
|
-
}) :
|
|
108
|
+
}) : U ? /* @__PURE__ */ v(i, {
|
|
109
109
|
title: T("devportal.myApplications", "My Applications"),
|
|
110
110
|
description: T("devportal.manageYourApps", "Manage your developer applications"),
|
|
111
|
-
children: /* @__PURE__ */
|
|
111
|
+
children: /* @__PURE__ */ y("div", {
|
|
112
112
|
className: "rounded-lg border border-destructive/50 bg-destructive/10 p-6 text-center",
|
|
113
113
|
children: [
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ v(f, { className: "mx-auto h-8 w-8 text-destructive" }),
|
|
115
|
+
/* @__PURE__ */ v("h3", {
|
|
116
116
|
className: "mt-2 font-medium text-destructive",
|
|
117
117
|
children: T("devportal.failedToLoadApplications", "Failed to load applications")
|
|
118
118
|
}),
|
|
119
|
-
/* @__PURE__ */
|
|
119
|
+
/* @__PURE__ */ v("p", {
|
|
120
120
|
className: "mt-1 text-sm text-muted-foreground",
|
|
121
|
-
children:
|
|
121
|
+
children: te(U)
|
|
122
122
|
}),
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
-
onClick: () =>
|
|
123
|
+
/* @__PURE__ */ v("button", {
|
|
124
|
+
onClick: () => W(),
|
|
125
125
|
className: "mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90",
|
|
126
126
|
children: T("devportal.tryAgain", "Try Again")
|
|
127
127
|
})
|
|
128
128
|
]
|
|
129
129
|
})
|
|
130
|
-
}) : /* @__PURE__ */
|
|
131
|
-
permission:
|
|
132
|
-
children: /* @__PURE__ */
|
|
130
|
+
}) : /* @__PURE__ */ v(oe, {
|
|
131
|
+
permission: s.APP_READ,
|
|
132
|
+
children: /* @__PURE__ */ y(i, {
|
|
133
133
|
title: T("devportal.myApplications", "My Applications"),
|
|
134
134
|
description: T("devportal.manageYourApps", "Manage your developer applications"),
|
|
135
|
-
actions: /* @__PURE__ */
|
|
135
|
+
actions: /* @__PURE__ */ y("button", {
|
|
136
136
|
onClick: () => q("/apps/new"),
|
|
137
137
|
disabled: !E.allowed,
|
|
138
138
|
"aria-disabled": !E.allowed,
|
|
139
139
|
title: E.allowed ? void 0 : T("devportal.common.noPermission", "You do not have permission to perform this action"),
|
|
140
140
|
className: "inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
|
|
141
|
-
children: [/* @__PURE__ */
|
|
141
|
+
children: [/* @__PURE__ */ v(_, {
|
|
142
142
|
size: 16,
|
|
143
143
|
"aria-hidden": "true"
|
|
144
144
|
}), T("devportal.createApp", "Create App")]
|
|
145
145
|
}),
|
|
146
146
|
children: [
|
|
147
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ y("div", {
|
|
148
148
|
className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
149
|
-
children: [/* @__PURE__ */
|
|
149
|
+
children: [/* @__PURE__ */ y("div", {
|
|
150
150
|
className: "flex flex-1 items-center gap-4",
|
|
151
151
|
children: [
|
|
152
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ y("div", {
|
|
153
153
|
className: "relative flex-1 max-w-md",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ v(ce, {
|
|
155
155
|
size: 16,
|
|
156
156
|
className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
|
157
|
-
}), /* @__PURE__ */
|
|
157
|
+
}), /* @__PURE__ */ v("input", {
|
|
158
158
|
type: "text",
|
|
159
159
|
placeholder: T("devportal.searchApplications", "Search applications..."),
|
|
160
160
|
value: j,
|
|
161
|
-
onChange: (e) =>
|
|
161
|
+
onChange: (e) => de(e.target.value),
|
|
162
162
|
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"
|
|
163
163
|
})]
|
|
164
164
|
}),
|
|
165
|
-
/* @__PURE__ */
|
|
166
|
-
value:
|
|
167
|
-
onChange: (e) =>
|
|
165
|
+
/* @__PURE__ */ y("select", {
|
|
166
|
+
value: M,
|
|
167
|
+
onChange: (e) => N(e.target.value),
|
|
168
168
|
className: "rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
|
|
169
|
-
children: [/* @__PURE__ */
|
|
169
|
+
children: [/* @__PURE__ */ v("option", {
|
|
170
170
|
value: "",
|
|
171
171
|
children: T("devportal.allStatus", "All Status")
|
|
172
|
-
}), Object.keys(
|
|
172
|
+
}), Object.keys(ne).map((e) => /* @__PURE__ */ v("option", {
|
|
173
173
|
value: e,
|
|
174
174
|
children: e.replace(/_/g, " ")
|
|
175
175
|
}, e))]
|
|
176
176
|
}),
|
|
177
|
-
/* @__PURE__ */
|
|
178
|
-
value:
|
|
179
|
-
onChange: (e) =>
|
|
177
|
+
/* @__PURE__ */ y("select", {
|
|
178
|
+
value: P,
|
|
179
|
+
onChange: (e) => F(e.target.value),
|
|
180
180
|
className: "rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
|
|
181
|
-
children: [/* @__PURE__ */
|
|
181
|
+
children: [/* @__PURE__ */ v("option", {
|
|
182
182
|
value: "",
|
|
183
183
|
children: T("devportal.allTypes", "All Types")
|
|
184
|
-
}), Object.entries(
|
|
184
|
+
}), Object.entries(a).map(([e, t]) => /* @__PURE__ */ v("option", {
|
|
185
185
|
value: e,
|
|
186
186
|
children: t
|
|
187
187
|
}, e))]
|
|
188
188
|
})
|
|
189
189
|
]
|
|
190
|
-
}), /* @__PURE__ */
|
|
190
|
+
}), /* @__PURE__ */ y("div", {
|
|
191
191
|
className: "flex items-center gap-1 rounded-md border p-1",
|
|
192
|
-
children: [/* @__PURE__ */
|
|
192
|
+
children: [/* @__PURE__ */ v("button", {
|
|
193
193
|
onClick: () => A("grid"),
|
|
194
194
|
className: `rounded p-1.5 ${k === "grid" ? "bg-muted" : "hover:bg-muted/50"}`,
|
|
195
195
|
title: "Grid view",
|
|
196
|
-
children: /* @__PURE__ */
|
|
197
|
-
}), /* @__PURE__ */
|
|
196
|
+
children: /* @__PURE__ */ v(h, { size: 16 })
|
|
197
|
+
}), /* @__PURE__ */ v("button", {
|
|
198
198
|
onClick: () => A("list"),
|
|
199
199
|
className: `rounded p-1.5 ${k === "list" ? "bg-muted" : "hover:bg-muted/50"}`,
|
|
200
200
|
title: "List view",
|
|
201
|
-
children: /* @__PURE__ */
|
|
201
|
+
children: /* @__PURE__ */ v(g, { size: 16 })
|
|
202
202
|
})]
|
|
203
203
|
})]
|
|
204
204
|
}),
|
|
205
|
-
|
|
206
|
-
className: `rounded-lg border px-4 py-3 text-sm ${
|
|
207
|
-
children: /* @__PURE__ */
|
|
205
|
+
B && /* @__PURE__ */ v("div", {
|
|
206
|
+
className: `rounded-lg border px-4 py-3 text-sm ${B.type === "success" ? "border-border-subtle bg-status-success-bg-subtle text-status-success-text" : "border-destructive/40 bg-destructive/10 text-destructive"}`,
|
|
207
|
+
children: /* @__PURE__ */ y("div", {
|
|
208
208
|
className: "flex items-center justify-between gap-3",
|
|
209
|
-
children: [/* @__PURE__ */
|
|
210
|
-
onClick: () =>
|
|
209
|
+
children: [/* @__PURE__ */ v("span", { children: B.message }), /* @__PURE__ */ v("button", {
|
|
210
|
+
onClick: () => V(null),
|
|
211
211
|
className: "text-xs font-medium underline underline-offset-2",
|
|
212
212
|
children: "Dismiss"
|
|
213
213
|
})]
|
|
214
214
|
})
|
|
215
215
|
}),
|
|
216
|
-
J.length > 0 && /* @__PURE__ */
|
|
216
|
+
J.length > 0 && /* @__PURE__ */ v("div", {
|
|
217
217
|
className: "rounded-lg border bg-card p-4",
|
|
218
|
-
children: /* @__PURE__ */
|
|
218
|
+
children: /* @__PURE__ */ y("div", {
|
|
219
219
|
className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",
|
|
220
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ y("div", {
|
|
221
221
|
className: "flex flex-wrap items-center gap-3",
|
|
222
|
-
children: [/* @__PURE__ */
|
|
222
|
+
children: [/* @__PURE__ */ y("div", {
|
|
223
223
|
className: "flex items-center gap-2",
|
|
224
|
-
children: [/* @__PURE__ */
|
|
224
|
+
children: [/* @__PURE__ */ v(re, {
|
|
225
225
|
checked: Z,
|
|
226
|
-
indeterminate:
|
|
227
|
-
onChange:
|
|
226
|
+
indeterminate: me,
|
|
227
|
+
onChange: he,
|
|
228
228
|
ariaLabel: "Select all visible applications"
|
|
229
|
-
}), /* @__PURE__ */
|
|
229
|
+
}), /* @__PURE__ */ v("span", {
|
|
230
230
|
className: "text-sm font-medium",
|
|
231
231
|
children: "Select all visible"
|
|
232
232
|
})]
|
|
233
|
-
}),
|
|
233
|
+
}), I.size > 0 && /* @__PURE__ */ v("button", {
|
|
234
234
|
onClick: $,
|
|
235
235
|
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
236
236
|
children: "Clear selection"
|
|
237
237
|
})]
|
|
238
|
-
}), /* @__PURE__ */
|
|
238
|
+
}), /* @__PURE__ */ y("div", {
|
|
239
239
|
className: "flex flex-wrap items-center gap-2",
|
|
240
240
|
children: [
|
|
241
|
-
/* @__PURE__ */
|
|
241
|
+
/* @__PURE__ */ y("span", {
|
|
242
242
|
className: "rounded-full bg-muted px-3 py-1 text-sm font-medium text-muted-foreground",
|
|
243
|
-
children: [
|
|
243
|
+
children: [I.size, " selected"]
|
|
244
244
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
246
|
-
onClick: () =>
|
|
245
|
+
/* @__PURE__ */ y("button", {
|
|
246
|
+
onClick: () => z("deactivate"),
|
|
247
247
|
disabled: X.length === 0 || !O.allowed,
|
|
248
248
|
"aria-disabled": X.length === 0 || !O.allowed,
|
|
249
249
|
title: O.allowed ? void 0 : T("devportal.common.noPermission", "You do not have permission to perform this action"),
|
|
250
250
|
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",
|
|
251
251
|
children: [
|
|
252
|
-
/* @__PURE__ */
|
|
252
|
+
/* @__PURE__ */ v(m, {
|
|
253
253
|
size: 16,
|
|
254
254
|
"aria-hidden": "true"
|
|
255
255
|
}),
|
|
@@ -257,14 +257,14 @@ var w = () => {
|
|
|
257
257
|
X.length > 0 ? ` (${X.length})` : ""
|
|
258
258
|
]
|
|
259
259
|
}),
|
|
260
|
-
/* @__PURE__ */
|
|
261
|
-
onClick: () =>
|
|
260
|
+
/* @__PURE__ */ y("button", {
|
|
261
|
+
onClick: () => z("delete"),
|
|
262
262
|
disabled: Y.length === 0 || !D.allowed,
|
|
263
263
|
"aria-disabled": Y.length === 0 || !D.allowed,
|
|
264
264
|
title: D.allowed ? void 0 : T("devportal.common.noPermission", "You do not have permission to perform this action"),
|
|
265
265
|
className: "inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
|
|
266
266
|
children: [
|
|
267
|
-
/* @__PURE__ */
|
|
267
|
+
/* @__PURE__ */ v(le, {
|
|
268
268
|
size: 16,
|
|
269
269
|
"aria-hidden": "true"
|
|
270
270
|
}),
|
|
@@ -276,7 +276,7 @@ var w = () => {
|
|
|
276
276
|
})]
|
|
277
277
|
})
|
|
278
278
|
}),
|
|
279
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ y("p", {
|
|
280
280
|
className: "text-sm text-muted-foreground",
|
|
281
281
|
children: [
|
|
282
282
|
J.length,
|
|
@@ -285,42 +285,42 @@ var w = () => {
|
|
|
285
285
|
" found"
|
|
286
286
|
]
|
|
287
287
|
}),
|
|
288
|
-
J.length > 0 ? k === "grid" ? /* @__PURE__ */
|
|
288
|
+
J.length > 0 ? k === "grid" ? /* @__PURE__ */ v("div", {
|
|
289
289
|
className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
290
|
-
children: J.map((e) => /* @__PURE__ */
|
|
290
|
+
children: J.map((e) => /* @__PURE__ */ v(ie, {
|
|
291
291
|
app: e,
|
|
292
|
-
selected:
|
|
292
|
+
selected: I.has(e.id),
|
|
293
293
|
onToggleSelect: (t) => Q(e.id, t)
|
|
294
294
|
}, e.id))
|
|
295
|
-
}) : /* @__PURE__ */
|
|
295
|
+
}) : /* @__PURE__ */ v("div", {
|
|
296
296
|
className: "space-y-2",
|
|
297
|
-
children: J.map((e) => /* @__PURE__ */
|
|
297
|
+
children: J.map((e) => /* @__PURE__ */ v(ae, {
|
|
298
298
|
app: e,
|
|
299
|
-
selected:
|
|
299
|
+
selected: I.has(e.id),
|
|
300
300
|
onToggleSelect: (t) => Q(e.id, t)
|
|
301
301
|
}, e.id))
|
|
302
|
-
}) : /* @__PURE__ */
|
|
303
|
-
icon: /* @__PURE__ */
|
|
302
|
+
}) : /* @__PURE__ */ v(t, {
|
|
303
|
+
icon: /* @__PURE__ */ v(p, { size: 32 }),
|
|
304
304
|
title: T("devportal.noApplicationsFound", "No applications found"),
|
|
305
|
-
description: j ||
|
|
306
|
-
action: !j && !
|
|
305
|
+
description: j || M || P ? T("devportal.tryAdjustingFilters", "Try adjusting your filters") : T("devportal.createFirstApp", "Create your first application to get started"),
|
|
306
|
+
action: !j && !M && !P ? /* @__PURE__ */ y("button", {
|
|
307
307
|
onClick: () => q("/apps/new"),
|
|
308
308
|
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",
|
|
309
|
-
children: [/* @__PURE__ */
|
|
309
|
+
children: [/* @__PURE__ */ v(_, { size: 16 }), T("devportal.createApp", "Create App")]
|
|
310
310
|
}) : void 0
|
|
311
311
|
}),
|
|
312
|
-
/* @__PURE__ */
|
|
313
|
-
open:
|
|
312
|
+
/* @__PURE__ */ v(o, {
|
|
313
|
+
open: R === "deactivate",
|
|
314
314
|
onOpenChange: (e) => {
|
|
315
|
-
e ||
|
|
315
|
+
e || z(null);
|
|
316
316
|
},
|
|
317
317
|
onConfirm: async () => {
|
|
318
318
|
if (X.length === 0) return;
|
|
319
|
-
let e = await Promise.allSettled(X.map((e) =>
|
|
320
|
-
|
|
319
|
+
let e = await Promise.allSettled(X.map((e) => K({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
|
|
320
|
+
V({
|
|
321
321
|
type: n === 0 ? "success" : "error",
|
|
322
|
-
message:
|
|
323
|
-
}), $(),
|
|
322
|
+
message: b("Deactivated", t, n)
|
|
323
|
+
}), $(), z(null), await W();
|
|
324
324
|
},
|
|
325
325
|
title: "Deactivate selected applications",
|
|
326
326
|
description: `Deactivate ${X.length} selected application${X.length === 1 ? "" : "s"}? Users and integrations may lose access until these apps are re-enabled.`,
|
|
@@ -328,18 +328,18 @@ var w = () => {
|
|
|
328
328
|
cancelLabel: "Cancel",
|
|
329
329
|
variant: "warning"
|
|
330
330
|
}),
|
|
331
|
-
/* @__PURE__ */
|
|
332
|
-
open:
|
|
331
|
+
/* @__PURE__ */ v(o, {
|
|
332
|
+
open: R === "delete",
|
|
333
333
|
onOpenChange: (e) => {
|
|
334
|
-
e ||
|
|
334
|
+
e || z(null);
|
|
335
335
|
},
|
|
336
336
|
onConfirm: async () => {
|
|
337
337
|
if (Y.length === 0) return;
|
|
338
|
-
let e = await Promise.allSettled(Y.map((e) =>
|
|
339
|
-
|
|
338
|
+
let e = await Promise.allSettled(Y.map((e) => pe({ variables: { id: e.id } }))), t = e.filter((e) => e.status === "fulfilled").length, n = e.length - t;
|
|
339
|
+
V({
|
|
340
340
|
type: n === 0 ? "success" : "error",
|
|
341
|
-
message:
|
|
342
|
-
}), $(),
|
|
341
|
+
message: b("Deleted", t, n)
|
|
342
|
+
}), $(), z(null), await W();
|
|
343
343
|
},
|
|
344
344
|
title: "Delete selected applications",
|
|
345
345
|
description: `Delete ${Y.length} selected application${Y.length === 1 ? "" : "s"}? This cannot be undone.`,
|
|
@@ -352,6 +352,6 @@ var w = () => {
|
|
|
352
352
|
});
|
|
353
353
|
};
|
|
354
354
|
//#endregion
|
|
355
|
-
export {
|
|
355
|
+
export { x as ApplicationsPage };
|
|
356
356
|
|
|
357
357
|
//# sourceMappingURL=ApplicationsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n Trash2,\n} from \"lucide-react\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard, AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\ntype BulkAction = \"delete\" | \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: \"Deleted\" | \"Deactivated\",\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\n/**\n * Map GraphQL application to local Application type\n */\nfunction mapApplication(app: ApplicationFieldsFragment): Application {\n // Convert screenshots array to Record if needed\n const screenshots = Array.isArray(app.screenshots)\n ? app.screenshots.length > 0\n ? (app.screenshots as unknown as Record<string, unknown>)\n : undefined\n : (app.screenshots as Record<string, unknown> | undefined);\n\n // Convert pricingDetails\n const pricingDetails =\n app.pricingDetails && typeof app.pricingDetails === \"object\"\n ? (app.pricingDetails as Record<string, unknown>)\n : undefined;\n\n return {\n id: app.id,\n name: app.name,\n slug: app.slug,\n description: app.description ?? undefined,\n shortDescription: app.shortDescription ?? undefined,\n appType: app.appType as AppType,\n status: app.status as AppStatus,\n visibility: app.visibility as \"PUBLIC\" | \"PRIVATE\" | \"UNLISTED\",\n category: app.category ?? undefined,\n tags: app.tags ?? [],\n keywords: app.keywords ?? [],\n iconUrl: app.iconUrl ?? undefined,\n bannerUrl: app.bannerUrl ?? undefined,\n screenshots,\n videoUrl: app.videoUrl ?? undefined,\n websiteUrl: app.websiteUrl ?? undefined,\n documentationUrl: app.documentationUrl ?? undefined,\n supportUrl: app.supportUrl ?? undefined,\n privacyPolicyUrl: app.privacyPolicyUrl ?? undefined,\n termsOfServiceUrl: app.termsOfServiceUrl ?? undefined,\n githubUrl: app.githubUrl ?? undefined,\n pricingType: app.pricingType ?? undefined,\n pricingDetails,\n isVerified: app.isVerified,\n isFeatured: app.isFeatured,\n averageRating: app.averageRating ?? undefined,\n reviewCount: app.reviewCount ?? 0,\n installCount: app.installCount ?? 0,\n activeInstallCount: app.activeInstallCount ?? 0,\n requiresApproval: app.requiresApproval,\n reviewStatus: app.reviewStatus ?? undefined,\n reviewNotes: app.reviewNotes ?? undefined,\n reviewedBy: app.reviewedBy ?? undefined,\n lastReviewedAt: app.lastReviewedAt ?? undefined,\n submittedAt: app.submittedAt ?? undefined,\n publishedAt: app.publishedAt ?? undefined,\n developerId: app.developerId,\n developerOrganizationId: app.developerOrganizationId ?? undefined,\n tenantId: app.tenantId,\n createdAt: app.createdAt,\n updatedAt: app.updatedAt,\n };\n}\n\n/**\n * Applications listing page\n *\n * Displays all applications for the current developer.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const ApplicationsPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const deletePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_DELETE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [statusFilter, setStatusFilter] = useState<AppStatus | \"\">(\"\");\n const [typeFilter, setTypeFilter] = useState<AppType | \"\">(\"\");\n const [selectedAppIds, setSelectedAppIds] = useState<Set<string>>(new Set());\n const [bulkAction, setBulkAction] = useState<BulkAction>(null);\n const [feedback, setFeedback] = useState<{\n type: \"success\" | \"error\";\n message: string;\n } | null>(null);\n\n // Fetch applications from GraphQL API\n const { data, loading, error, refetch } = useGetApplicationsQuery({\n variables: {\n limit: 50,\n offset: 0,\n status: statusFilter || undefined,\n },\n fetchPolicy: \"cache-and-network\",\n });\n\n const applications: Application[] = useMemo(\n () =>\n data?.applications?.edges?.map(\n (edge: { node: ApplicationFieldsFragment }) =>\n mapApplication(edge.node),\n ) ?? [],\n [data?.applications?.edges],\n );\n\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Client-side filtering for search and type (status is filtered server-side)\n const filteredApps = applications.filter((app: Application) => {\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 matchesSearch && matchesType;\n });\n\n const selectedApps = useMemo(\n () => applications.filter((app: Application) => selectedAppIds.has(app.id)),\n [applications, selectedAppIds],\n );\n\n const deactivatableApps = useMemo(\n () =>\n selectedApps.filter(\n (app: Application) =>\n app.status !== \"INACTIVE\" && app.status !== \"REVOKED\",\n ),\n [selectedApps],\n );\n\n const allVisibleSelected =\n filteredApps.length > 0 &&\n filteredApps.every((app: Application) => selectedAppIds.has(app.id));\n const partiallySelected =\n filteredApps.some((app: Application) => selectedAppIds.has(app.id)) &&\n !allVisibleSelected;\n\n const toggleAppSelection = (appId: string, checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(appId);\n } else {\n next.delete(appId);\n }\n return next;\n });\n };\n\n const toggleAllVisible = (checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n filteredApps.forEach((app: Application) => {\n if (checked) {\n next.add(app.id);\n } else {\n next.delete(app.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedAppIds(new Set());\n\n const runBulkDeactivate = async () => {\n if (deactivatableApps.length === 0) return;\n\n const results = await Promise.allSettled(\n deactivatableApps.map((app: Application) =>\n deactivateApp({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deactivated\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n const runBulkDelete = async () => {\n if (selectedApps.length === 0) return;\n\n const results = await Promise.allSettled(\n selectedApps.map((app: Application) =>\n deleteApplication({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deleted\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <span className=\"ml-2 text-muted-foreground\">\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-destructive/50 bg-destructive/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-destructive\" />\n <h3 className=\"mt-2 font-medium text-destructive\">\n {tr(\n \"devportal.failedToLoadApplications\",\n \"Failed to load applications\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n 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-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/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-muted-foreground\"\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-background 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-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\"devportal.allStatus\", \"All Status\")}\n </option>\n {Object.keys(APP_STATUS_COLORS).map((status) => (\n <option key={status} value={status}>\n {status.replace(/_/g, \" \")}\n </option>\n ))}\n </select>\n\n {/* Type Filter */}\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as AppType | \"\")}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">{tr(\"devportal.allTypes\", \"All Types\")}</option>\n {Object.entries(APP_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <button\n onClick={() => setViewMode(\"grid\")}\n className={`rounded p-1.5 ${viewMode === \"grid\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"Grid view\"\n >\n <Grid size={16} />\n </button>\n <button\n onClick={() => setViewMode(\"list\")}\n className={`rounded p-1.5 ${viewMode === \"list\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"List view\"\n >\n <List size={16} />\n </button>\n </div>\n </div>\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-destructive/40 bg-destructive/10 text-destructive\"\n }`}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span>{feedback.message}</span>\n <button\n onClick={() => setFeedback(null)}\n className=\"text-xs font-medium underline underline-offset-2\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {filteredApps.length > 0 && (\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisible}\n ariaLabel=\"Select all visible applications\"\n />\n <span className=\"text-sm font-medium\">\n Select all visible\n </span>\n </div>\n {selectedAppIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-muted px-3 py-1 text-sm font-medium text-muted-foreground\">\n {selectedAppIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"deactivate\")}\n disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n aria-disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n title={\n !updatePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Archive size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deactivateSelected\", \"Deactivate Selected\")}\n {deactivatableApps.length > 0\n ? ` (${deactivatableApps.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"delete\")}\n disabled={selectedApps.length === 0 || !deletePerm.allowed}\n aria-disabled={\n selectedApps.length === 0 || !deletePerm.allowed\n }\n title={\n !deletePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deleteSelected\", \"Delete Selected\")}\n {selectedApps.length > 0 ? ` (${selectedApps.length})` : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-muted-foreground\">\n {filteredApps.length} application\n {filteredApps.length !== 1 ? \"s\" : \"\"} found\n </p>\n\n {/* Applications */}\n {filteredApps.length > 0 ? (\n viewMode === \"grid\" ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {filteredApps.map((app: Application) => (\n <AppCard\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredApps.map((app: Application) => (\n <AppListItem\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n )\n ) : (\n <EmptyState\n 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-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : undefined\n }\n />\n )}\n\n <ConfirmDialog\n open={bulkAction === \"deactivate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDeactivate}\n title=\"Deactivate selected applications\"\n description={`Deactivate ${deactivatableApps.length} selected application${deactivatableApps.length === 1 ? \"\" : \"s\"}? Users and integrations may lose access until these apps are re-enabled.`}\n confirmLabel=\"Deactivate\"\n cancelLabel=\"Cancel\"\n variant=\"warning\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"delete\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDelete}\n title=\"Delete selected applications\"\n description={`Delete ${selectedApps.length} selected application${selectedApps.length === 1 ? \"\" : \"s\"}? This cannot be undone.`}\n confirmLabel=\"Delete\"\n cancelLabel=\"Cancel\"\n variant=\"danger\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmCA,SAAS,EACP,GACA,GACA,GACQ;AACR,QAAO,GAAG,EAAO,GAAG,EAAU,cAAc,MAAc,IAAI,KAAK,MACjE,IAAS,IAAI,MAAM,EAAO,WAAW;;AAOzC,SAAS,EAAe,GAA6C;CAEnE,IAAM,IAAc,MAAM,QAAQ,EAAI,YAAY,GAC9C,EAAI,YAAY,SAAS,IACtB,EAAI,cACL,KAAA,IACD,EAAI,aAGH,IACJ,EAAI,kBAAkB,OAAO,EAAI,kBAAmB,WAC/C,EAAI,iBACL,KAAA;AAEN,QAAO;EACL,IAAI,EAAI;EACR,MAAM,EAAI;EACV,MAAM,EAAI;EACV,aAAa,EAAI,eAAe,KAAA;EAChC,kBAAkB,EAAI,oBAAoB,KAAA;EAC1C,SAAS,EAAI;EACb,QAAQ,EAAI;EACZ,YAAY,EAAI;EAChB,UAAU,EAAI,YAAY,KAAA;EAC1B,MAAM,EAAI,QAAQ,EAAE;EACpB,UAAU,EAAI,YAAY,EAAE;EAC5B,SAAS,EAAI,WAAW,KAAA;EACxB,WAAW,EAAI,aAAa,KAAA;EAC5B;EACA,UAAU,EAAI,YAAY,KAAA;EAC1B,YAAY,EAAI,cAAc,KAAA;EAC9B,kBAAkB,EAAI,oBAAoB,KAAA;EAC1C,YAAY,EAAI,cAAc,KAAA;EAC9B,kBAAkB,EAAI,oBAAoB,KAAA;EAC1C,mBAAmB,EAAI,qBAAqB,KAAA;EAC5C,WAAW,EAAI,aAAa,KAAA;EAC5B,aAAa,EAAI,eAAe,KAAA;EAChC;EACA,YAAY,EAAI;EAChB,YAAY,EAAI;EAChB,eAAe,EAAI,iBAAiB,KAAA;EACpC,aAAa,EAAI,eAAe;EAChC,cAAc,EAAI,gBAAgB;EAClC,oBAAoB,EAAI,sBAAsB;EAC9C,kBAAkB,EAAI;EACtB,cAAc,EAAI,gBAAgB,KAAA;EAClC,aAAa,EAAI,eAAe,KAAA;EAChC,YAAY,EAAI,cAAc,KAAA;EAC9B,gBAAgB,EAAI,kBAAkB,KAAA;EACtC,aAAa,EAAI,eAAe,KAAA;EAChC,aAAa,EAAI,eAAe,KAAA;EAChC,aAAa,EAAI;EACjB,yBAAyB,EAAI,2BAA2B,KAAA;EACxD,UAAU,EAAI;EACd,WAAW,EAAI;EACf,WAAW,EAAI;EAChB;;AASH,IAAa,UAA6B;CACxC,IAAM,EAAE,aAAU,iBAAa,GAAc,EACvC,EAAE,UAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,GAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAE9B,IAAa,EAAuB,EAAsB,WAAW,EACrE,IAAa,EAAuB,EAAsB,WAAW,EACrE,IAAa,EAAuB,EAAsB,WAAW,EACrE,CAAC,GAAU,KAAe,EAA0B,OAAO,EAC3D,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAc,KAAmB,EAAyB,GAAG,EAC9D,CAAC,GAAY,KAAiB,EAAuB,GAAG,EACxD,CAAC,GAAgB,KAAqB,kBAAsB,IAAI,KAAK,CAAC,EACtE,CAAC,GAAY,KAAiB,EAAqB,KAAK,EACxD,CAAC,GAAU,KAAe,EAGtB,KAAK,EAGT,EAAE,SAAM,aAAS,UAAO,eAAY,EAAwB;EAChE,WAAW;GACT,OAAO;GACP,QAAQ;GACR,QAAQ,KAAgB,KAAA;GACzB;EACD,aAAa;EACd,CAAC,EAEI,IAA8B,QAEhC,GAAM,cAAc,OAAO,KACxB,MACC,EAAe,EAAK,KAAK,CAC5B,IAAI,EAAE,EACT,CAAC,GAAM,cAAc,MAAM,CAC5B,EAEK,CAAC,MAAqB,IAA8B,EACpD,CAAC,MAAiB,IAA0B,EAE5C,KAAkB,MAAiB;AACvC,MAAW,GAAG,KAAW,IAAO;IAI5B,IAAe,EAAa,QAAQ,MAAqB;EAC7D,IAAM,IACJ,CAAC,KACD,EAAI,KAAK,aAAa,CAAC,SAAS,EAAY,aAAa,CAAC,IAC1D,EAAI,kBAAkB,aAAa,CAAC,SAAS,EAAY,aAAa,CAAC,EACnE,IAAc,CAAC,KAAc,EAAI,YAAY;AACnD,SAAO,KAAiB;GACxB,EAEI,IAAe,QACb,EAAa,QAAQ,MAAqB,EAAe,IAAI,EAAI,GAAG,CAAC,EAC3E,CAAC,GAAc,EAAe,CAC/B,EAEK,IAAoB,QAEtB,EAAa,QACV,MACC,EAAI,WAAW,cAAc,EAAI,WAAW,UAC/C,EACH,CAAC,EAAa,CACf,EAEK,IACJ,EAAa,SAAS,KACtB,EAAa,OAAO,MAAqB,EAAe,IAAI,EAAI,GAAG,CAAC,EAChE,KACJ,EAAa,MAAM,MAAqB,EAAe,IAAI,EAAI,GAAG,CAAC,IACnE,CAAC,GAEG,KAAsB,GAAe,MAAqB;AAC9D,KAAmB,MAAS;GAC1B,IAAM,IAAO,IAAI,IAAI,EAAK;AAM1B,UALI,IACF,EAAK,IAAI,EAAM,GAEf,EAAK,OAAO,EAAM,EAEb;IACP;IAGE,MAAoB,MAAqB;AAC7C,KAAmB,MAAS;GAC1B,IAAM,IAAO,IAAI,IAAI,EAAK;AAQ1B,UAPA,EAAa,SAAS,MAAqB;AACzC,IAAI,IACF,EAAK,IAAI,EAAI,GAAG,GAEhB,EAAK,OAAO,EAAI,GAAG;KAErB,EACK;IACP;IAGE,UAAuB,kBAAkB,IAAI,KAAK,CAAC;AAoGzD,QAnDI,MAAW,CAAC,IAEZ,kBAAC,GAAD;EACE,OAAO,EAAG,4BAA4B,kBAAkB;EACxD,aAAa,EACX,4BACA,qCACD;YAED,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,IAAD,EAAS,WAAU,8CAA+C,CAAA,EAClE,kBAAC,QAAD;IAAM,WAAU;cACb,EAAG,iCAAiC,0BAA0B;IAC1D,CAAA,CACH;;EACK,CAAA,GAKb,IAEA,kBAAC,GAAD;EACE,OAAO,EAAG,4BAA4B,kBAAkB;EACxD,aAAa,EACX,4BACA,qCACD;YAED,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;IAC5D,kBAAC,MAAD;KAAI,WAAU;eACX,EACC,sCACA,8BACD;KACE,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAgB,EAAM;KACrB,CAAA;IACJ,kBAAC,UAAD;KACE,eAAe,GAAS;KACxB,WAAU;eAET,EAAG,sBAAsB,YAAY;KAC/B,CAAA;IACL;;EACK,CAAA,GAKf,kBAAC,GAAD;EAAiB,YAAY,EAAsB;YACjD,kBAAC,GAAD;GACE,OAAO,EAAG,4BAA4B,kBAAkB;GACxD,aAAa,EACX,4BACA,qCACD;GACD,SACE,kBAAC,UAAD;IACE,eAAe,EAAe,YAAY;IAC1C,UAAU,CAAC,EAAW;IACtB,iBAAe,CAAC,EAAW;IAC3B,OACG,EAAW,UAKR,KAAA,IAJA,EACE,iCACA,oDACD;IAGP,WAAU;cAZZ,CAcE,kBAAC,GAAD;KAAM,MAAM;KAAI,eAAY;KAAS,CAAA,EACpC,EAAG,uBAAuB,aAAa,CACjC;;aAvBb;IA2BE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OAEE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,IAAD;SACE,MAAM;SACN,WAAU;SACV,CAAA,EACF,kBAAC,SAAD;SACE,MAAK;SACL,aAAa,EACX,gCACA,yBACD;SACD,OAAO;SACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;SAC/C,WAAU;SACV,CAAA,CACE;;OAGN,kBAAC,UAAD;QACE,OAAO;QACP,WAAW,MACT,EAAgB,EAAE,OAAO,MAAwB;QAEnD,WAAU;kBALZ,CAOE,kBAAC,UAAD;SAAQ,OAAM;mBACX,EAAG,uBAAuB,aAAa;SACjC,CAAA,EACR,OAAO,KAAK,EAAkB,CAAC,KAAK,MACnC,kBAAC,UAAD;SAAqB,OAAO;mBACzB,EAAO,QAAQ,MAAM,IAAI;SACnB,EAFI,EAEJ,CACT,CACK;;OAGT,kBAAC,UAAD;QACE,OAAO;QACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAsB;QAC9D,WAAU;kBAHZ,CAKE,kBAAC,UAAD;SAAQ,OAAM;mBAAI,EAAG,sBAAsB,YAAY;SAAU,CAAA,EAChE,OAAO,QAAQ,EAAgB,CAAC,KAAK,CAAC,GAAO,OAC5C,kBAAC,UAAD;SAA2B;mBACxB;SACM,EAFI,EAEJ,CACT,CACK;;OACL;SAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OACE,eAAe,EAAY,OAAO;OAClC,WAAW,iBAAiB,MAAa,SAAS,aAAa;OAC/D,OAAM;iBAEN,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;OACX,CAAA,EACT,kBAAC,UAAD;OACE,eAAe,EAAY,OAAO;OAClC,WAAW,iBAAiB,MAAa,SAAS,aAAa;OAC/D,OAAM;iBAEN,kBAAC,IAAD,EAAM,MAAM,IAAM,CAAA;OACX,CAAA,CACL;QACF;;IAEL,KACC,kBAAC,OAAD;KACE,WAAW,uCACT,EAAS,SAAS,YACd,8EACA;eAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAS,SAAe,CAAA,EAC/B,kBAAC,UAAD;OACE,eAAe,EAAY,KAAK;OAChC,WAAU;iBACX;OAEQ,CAAA,CACL;;KACF,CAAA;IAGP,EAAa,SAAS,KACrB,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,IAAD;SACE,SAAS;SACT,eAAe;SACf,UAAU;SACV,WAAU;SACV,CAAA,EACF,kBAAC,QAAD;SAAM,WAAU;mBAAsB;SAE/B,CAAA,CACH;WACL,EAAe,OAAO,KACrB,kBAAC,UAAD;QACE,SAAS;QACT,WAAU;kBACX;QAEQ,CAAA,CAEP;UAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACG,EAAe,MAAK,YAChB;;QACP,kBAAC,UAAD;SACE,eAAe,EAAc,aAAa;SAC1C,UACE,EAAkB,WAAW,KAAK,CAAC,EAAW;SAEhD,iBACE,EAAkB,WAAW,KAAK,CAAC,EAAW;SAEhD,OACG,EAAW,UAKR,KAAA,IAJA,EACE,iCACA,oDACD;SAGP,WAAU;mBAhBZ;UAkBE,kBAAC,GAAD;WAAS,MAAM;WAAI,eAAY;WAAS,CAAA;UACvC,EAAG,gCAAgC,sBAAsB;UACzD,EAAkB,SAAS,IACxB,KAAK,EAAkB,OAAO,KAC9B;UACG;;QACT,kBAAC,UAAD;SACE,eAAe,EAAc,SAAS;SACtC,UAAU,EAAa,WAAW,KAAK,CAAC,EAAW;SACnD,iBACE,EAAa,WAAW,KAAK,CAAC,EAAW;SAE3C,OACG,EAAW,UAKR,KAAA,IAJA,EACE,iCACA,oDACD;SAGP,WAAU;mBAdZ;UAgBE,kBAAC,IAAD;WAAQ,MAAM;WAAI,eAAY;WAAS,CAAA;UACtC,EAAG,4BAA4B,kBAAkB;UACjD,EAAa,SAAS,IAAI,KAAK,EAAa,OAAO,KAAK;UAClD;;QACL;SACF;;KACF,CAAA;IAIR,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,EAAa;MAAO;MACpB,EAAa,WAAW,IAAU,KAAN;MAAS;MACpC;;IAGH,EAAa,SAAS,IACrB,MAAa,SACX,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAa,KAAK,MACjB,kBAAC,GAAD;MAEO;MACL,UAAU,EAAe,IAAI,EAAI,GAAG;MACpC,iBAAiB,MACf,EAAmB,EAAI,IAAI,EAAQ;MAErC,EANK,EAAI,GAMT,CACF;KACE,CAAA,GAEN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAa,KAAK,MACjB,kBAAC,GAAD;MAEO;MACL,UAAU,EAAe,IAAI,EAAI,GAAG;MACpC,iBAAiB,MACf,EAAmB,EAAI,IAAI,EAAQ;MAErC,EANK,EAAI,GAMT,CACF;KACE,CAAA,GAGR,kBAAC,GAAD;KACE,MAAM,kBAAC,IAAD,EAAW,MAAM,IAAM,CAAA;KAC7B,OAAO,EAAG,iCAAiC,wBAAwB;KACnE,aACE,KAAe,KAAgB,IAC3B,EACE,iCACA,6BACD,GACD,EACE,4BACA,+CACD;KAEP,QACE,CAAC,KAAe,CAAC,KAAgB,CAAC,IAChC,kBAAC,UAAD;MACE,eAAe,EAAe,YAAY;MAC1C,WAAU;gBAFZ,CAIE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,uBAAuB,aAAa,CACjC;UACP,KAAA;KAEN,CAAA;IAGJ,kBAAC,GAAD;KACE,MAAM,MAAe;KACrB,eAAe,MAAS;AACtB,MAAK,KAAM,EAAc,KAAK;;KAEhC,WA9WkB,YAAY;AACpC,UAAI,EAAkB,WAAW,EAAG;MAEpC,IAAM,IAAU,MAAM,QAAQ,WAC5B,EAAkB,KAAK,MACrB,GAAc,EAAE,WAAW,EAAE,IAAI,EAAI,IAAI,EAAE,CAAC,CAC7C,CACF,EAEK,IAAY,EAAQ,QACvB,MAA0C,EAAO,WAAW,YAC9D,CAAC,QACI,IAAS,EAAQ,SAAS;AAQhC,MANA,EAAY;OACV,MAAM,MAAW,IAAI,YAAY;OACjC,SAAS,EAAiB,eAAe,GAAW,EAAO;OAC5D,CAAC,EACF,GAAgB,EAChB,EAAc,KAAK,EACnB,MAAM,GAAS;;KA2VT,OAAM;KACN,aAAa,cAAc,EAAkB,OAAO,uBAAuB,EAAkB,WAAW,IAAI,KAAK,IAAI;KACrH,cAAa;KACb,aAAY;KACZ,SAAQ;KACR,CAAA;IAEF,kBAAC,GAAD;KACE,MAAM,MAAe;KACrB,eAAe,MAAS;AACtB,MAAK,KAAM,EAAc,KAAK;;KAEhC,WApWc,YAAY;AAChC,UAAI,EAAa,WAAW,EAAG;MAE/B,IAAM,IAAU,MAAM,QAAQ,WAC5B,EAAa,KAAK,MAChB,GAAkB,EAAE,WAAW,EAAE,IAAI,EAAI,IAAI,EAAE,CAAC,CACjD,CACF,EAEK,IAAY,EAAQ,QACvB,MAA0C,EAAO,WAAW,YAC9D,CAAC,QACI,IAAS,EAAQ,SAAS;AAQhC,MANA,EAAY;OACV,MAAM,MAAW,IAAI,YAAY;OACjC,SAAS,EAAiB,WAAW,GAAW,EAAO;OACxD,CAAC,EACF,GAAgB,EAChB,EAAc,KAAK,EACnB,MAAM,GAAS;;KAiVT,OAAM;KACN,aAAa,UAAU,EAAa,OAAO,uBAAuB,EAAa,WAAW,IAAI,KAAK,IAAI;KACvG,cAAa;KACb,aAAY;KACZ,SAAQ;KACR,CAAA;IACS;;EACG,CAAA"}
|
|
1
|
+
{"version":3,"file":"ApplicationsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n Trash2,\n} from \"lucide-react\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard, AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\ntype BulkAction = \"delete\" | \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: \"Deleted\" | \"Deactivated\",\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\n/**\n * Map GraphQL application to local Application type\n */\nfunction mapApplication(app: ApplicationFieldsFragment): Application {\n // Convert screenshots array to Record if needed\n const screenshots = Array.isArray(app.screenshots)\n ? app.screenshots.length > 0\n ? (app.screenshots as unknown as Record<string, unknown>)\n : undefined\n : (app.screenshots as Record<string, unknown> | undefined);\n\n // Convert pricingDetails\n const pricingDetails =\n app.pricingDetails && typeof app.pricingDetails === \"object\"\n ? (app.pricingDetails as Record<string, unknown>)\n : undefined;\n\n return {\n id: app.id,\n name: app.name,\n slug: app.slug,\n description: app.description ?? undefined,\n shortDescription: app.shortDescription ?? undefined,\n appType: app.appType as AppType,\n status: app.status as AppStatus,\n visibility: app.visibility as \"PUBLIC\" | \"PRIVATE\" | \"UNLISTED\",\n category: app.category ?? undefined,\n tags: app.tags ?? [],\n keywords: app.keywords ?? [],\n iconUrl: app.iconUrl ?? undefined,\n bannerUrl: app.bannerUrl ?? undefined,\n screenshots,\n videoUrl: app.videoUrl ?? undefined,\n websiteUrl: app.websiteUrl ?? undefined,\n documentationUrl: app.documentationUrl ?? undefined,\n supportUrl: app.supportUrl ?? undefined,\n privacyPolicyUrl: app.privacyPolicyUrl ?? undefined,\n termsOfServiceUrl: app.termsOfServiceUrl ?? undefined,\n githubUrl: app.githubUrl ?? undefined,\n pricingType: app.pricingType ?? undefined,\n pricingDetails,\n isVerified: app.isVerified,\n isFeatured: app.isFeatured,\n averageRating: app.averageRating ?? undefined,\n reviewCount: app.reviewCount ?? 0,\n installCount: app.installCount ?? 0,\n activeInstallCount: app.activeInstallCount ?? 0,\n requiresApproval: app.requiresApproval,\n reviewStatus: app.reviewStatus ?? undefined,\n reviewNotes: app.reviewNotes ?? undefined,\n reviewedBy: app.reviewedBy ?? undefined,\n lastReviewedAt: app.lastReviewedAt ?? undefined,\n submittedAt: app.submittedAt ?? undefined,\n publishedAt: app.publishedAt ?? undefined,\n developerId: app.developerId,\n developerOrganizationId: app.developerOrganizationId ?? undefined,\n tenantId: app.tenantId,\n createdAt: app.createdAt,\n updatedAt: app.updatedAt,\n };\n}\n\n/**\n * Applications listing page\n *\n * Displays all applications for the current developer.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const ApplicationsPage: FC = () => {\n const { navigate, basePath, activeOrgId } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const deletePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_DELETE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [statusFilter, setStatusFilter] = useState<AppStatus | \"\">(\"\");\n const [typeFilter, setTypeFilter] = useState<AppType | \"\">(\"\");\n const [selectedAppIds, setSelectedAppIds] = useState<Set<string>>(new Set());\n const [bulkAction, setBulkAction] = useState<BulkAction>(null);\n const [feedback, setFeedback] = useState<{\n type: \"success\" | \"error\";\n message: string;\n } | null>(null);\n\n // Fetch applications from GraphQL API\n const { data, loading, error, refetch } = useGetApplicationsQuery({\n variables: {\n limit: 50,\n offset: 0,\n status: statusFilter || undefined,\n },\n fetchPolicy: \"cache-and-network\",\n });\n\n const applications: Application[] = useMemo(\n () =>\n data?.applications?.edges?.map(\n (edge: { node: ApplicationFieldsFragment }) =>\n mapApplication(edge.node),\n ) ?? [],\n [data?.applications?.edges],\n );\n\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Client-side filtering: org scope + search + type (status filtered server-side)\n const filteredApps = applications.filter((app: Application) => {\n const matchesOrg =\n !activeOrgId || app.developerOrganizationId === activeOrgId;\n const matchesSearch =\n !searchQuery ||\n app.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n app.shortDescription?.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesType = !typeFilter || app.appType === typeFilter;\n return matchesOrg && matchesSearch && matchesType;\n });\n\n const selectedApps = useMemo(\n () => applications.filter((app: Application) => selectedAppIds.has(app.id)),\n [applications, selectedAppIds],\n );\n\n const deactivatableApps = useMemo(\n () =>\n selectedApps.filter(\n (app: Application) =>\n app.status !== \"INACTIVE\" && app.status !== \"REVOKED\",\n ),\n [selectedApps],\n );\n\n const allVisibleSelected =\n filteredApps.length > 0 &&\n filteredApps.every((app: Application) => selectedAppIds.has(app.id));\n const partiallySelected =\n filteredApps.some((app: Application) => selectedAppIds.has(app.id)) &&\n !allVisibleSelected;\n\n const toggleAppSelection = (appId: string, checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(appId);\n } else {\n next.delete(appId);\n }\n return next;\n });\n };\n\n const toggleAllVisible = (checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n filteredApps.forEach((app: Application) => {\n if (checked) {\n next.add(app.id);\n } else {\n next.delete(app.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedAppIds(new Set());\n\n const runBulkDeactivate = async () => {\n if (deactivatableApps.length === 0) return;\n\n const results = await Promise.allSettled(\n deactivatableApps.map((app: Application) =>\n deactivateApp({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deactivated\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n const runBulkDelete = async () => {\n if (selectedApps.length === 0) return;\n\n const results = await Promise.allSettled(\n selectedApps.map((app: Application) =>\n deleteApplication({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deleted\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <span className=\"ml-2 text-muted-foreground\">\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-destructive/50 bg-destructive/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-destructive\" />\n <h3 className=\"mt-2 font-medium text-destructive\">\n {tr(\n \"devportal.failedToLoadApplications\",\n \"Failed to load applications\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n 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-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/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-muted-foreground\"\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-background 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-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\"devportal.allStatus\", \"All Status\")}\n </option>\n {Object.keys(APP_STATUS_COLORS).map((status) => (\n <option key={status} value={status}>\n {status.replace(/_/g, \" \")}\n </option>\n ))}\n </select>\n\n {/* Type Filter */}\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as AppType | \"\")}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">{tr(\"devportal.allTypes\", \"All Types\")}</option>\n {Object.entries(APP_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <button\n onClick={() => setViewMode(\"grid\")}\n className={`rounded p-1.5 ${viewMode === \"grid\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"Grid view\"\n >\n <Grid size={16} />\n </button>\n <button\n onClick={() => setViewMode(\"list\")}\n className={`rounded p-1.5 ${viewMode === \"list\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"List view\"\n >\n <List size={16} />\n </button>\n </div>\n </div>\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-destructive/40 bg-destructive/10 text-destructive\"\n }`}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span>{feedback.message}</span>\n <button\n onClick={() => setFeedback(null)}\n className=\"text-xs font-medium underline underline-offset-2\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {filteredApps.length > 0 && (\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisible}\n ariaLabel=\"Select all visible applications\"\n />\n <span className=\"text-sm font-medium\">\n Select all visible\n </span>\n </div>\n {selectedAppIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-muted px-3 py-1 text-sm font-medium text-muted-foreground\">\n {selectedAppIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"deactivate\")}\n disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n aria-disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n title={\n !updatePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Archive size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deactivateSelected\", \"Deactivate Selected\")}\n {deactivatableApps.length > 0\n ? ` (${deactivatableApps.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"delete\")}\n disabled={selectedApps.length === 0 || !deletePerm.allowed}\n aria-disabled={\n selectedApps.length === 0 || !deletePerm.allowed\n }\n title={\n !deletePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deleteSelected\", \"Delete Selected\")}\n {selectedApps.length > 0 ? ` (${selectedApps.length})` : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-muted-foreground\">\n {filteredApps.length} application\n {filteredApps.length !== 1 ? \"s\" : \"\"} found\n </p>\n\n {/* Applications */}\n {filteredApps.length > 0 ? (\n viewMode === \"grid\" ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {filteredApps.map((app: Application) => (\n <AppCard\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredApps.map((app: Application) => (\n <AppListItem\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n )\n ) : (\n <EmptyState\n 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-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : undefined\n }\n />\n )}\n\n <ConfirmDialog\n open={bulkAction === \"deactivate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDeactivate}\n title=\"Deactivate selected applications\"\n description={`Deactivate ${deactivatableApps.length} selected application${deactivatableApps.length === 1 ? \"\" : \"s\"}? Users and integrations may lose access until these apps are re-enabled.`}\n confirmLabel=\"Deactivate\"\n cancelLabel=\"Cancel\"\n variant=\"warning\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"delete\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDelete}\n title=\"Delete selected applications\"\n description={`Delete ${selectedApps.length} selected application${selectedApps.length === 1 ? \"\" : \"s\"}? This cannot be undone.`}\n confirmLabel=\"Delete\"\n cancelLabel=\"Cancel\"\n variant=\"danger\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|