@burdenoff/microfe-devportal 2026.717.1 → 2026.720.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/PermissionGuard.d.ts +14 -1
- package/dist/devportal/components/PermissionGuard.d.ts.map +1 -1
- package/dist/devportal/components/PermissionGuard.js +16 -13
- package/dist/devportal/components/PermissionGuard.js.map +1 -1
- package/dist/devportal/pages/AdminReviewPage.js +9 -9
- package/dist/devportal/pages/ApiKeysPage.js +180 -181
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationDetailPage.js +3 -3
- package/dist/devportal/pages/ApplicationVersionsPage.js +4 -4
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationsPage.js +4 -4
- package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +1 -1
- package/dist/devportal/pages/CreateOAuthClientPage.js +1 -1
- package/dist/devportal/pages/CreateOrganizationPage.js +1 -1
- package/dist/devportal/pages/CreateWebhookPage.js +25 -25
- package/dist/devportal/pages/DashboardPage.d.ts.map +1 -1
- package/dist/devportal/pages/DashboardPage.js +110 -111
- package/dist/devportal/pages/DashboardPage.js.map +1 -1
- package/dist/devportal/pages/DelegationsPage.js +1 -1
- package/dist/devportal/pages/EditApplicationPage.js +4 -4
- package/dist/devportal/pages/ListingPreviewPage.d.ts.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +160 -161
- package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientDetailPage.d.ts.map +1 -1
- package/dist/devportal/pages/OAuthClientDetailPage.js +166 -167
- package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientsPage.d.ts.map +1 -1
- package/dist/devportal/pages/OAuthClientsPage.js +121 -122
- package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.js +3 -3
- package/dist/devportal/pages/OrganizationMembersPage.js +4 -4
- package/dist/devportal/pages/OrganizationsPage.js +1 -1
- package/dist/devportal/pages/PublishPage.js +246 -246
- package/dist/devportal/pages/PublishPage.js.map +1 -1
- package/dist/devportal/pages/PublisherProfilePage.js +4 -4
- package/dist/devportal/pages/PublisherProfilePage.js.map +1 -1
- package/dist/devportal/pages/StoreSubmissionPage.js +3 -3
- package/dist/devportal/pages/WebhookDetailPage.js +3 -3
- package/dist/devportal/pages/WebhooksPage.js +129 -129
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,140 +5,139 @@ import { PageLayout as r } from "../components/PageLayout.js";
|
|
|
5
5
|
import { AppCard as i } from "../components/AppCard.js";
|
|
6
6
|
import { PermissionGuard as a } from "../components/PermissionGuard.js";
|
|
7
7
|
import "../components/index.js";
|
|
8
|
-
import { DEVPORTAL_PERMISSIONS as o } from "../constants/permissions.js";
|
|
9
8
|
import "../hooks/index.js";
|
|
10
|
-
import { useEffect as
|
|
11
|
-
import { useI18n as
|
|
12
|
-
import { AppWindow as
|
|
13
|
-
import { Fragment as
|
|
14
|
-
import { GlassCard as
|
|
9
|
+
import { useEffect as o } from "react";
|
|
10
|
+
import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
+
import { AppWindow as c, ArrowRight as l, Building2 as u, DollarSign as d, Download as f, Loader2 as p, Plus as m } from "lucide-react";
|
|
12
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
13
|
+
import { GlassCard as v, GradientText as y } from "@burdenoff/fe-libs/ui";
|
|
15
14
|
//#region src/devportal/pages/DashboardPage.tsx
|
|
16
|
-
var
|
|
17
|
-
let { navigate:
|
|
18
|
-
let n =
|
|
15
|
+
var b = () => {
|
|
16
|
+
let { navigate: d, basePath: f, activeOrgId: v, setActiveOrgId: b } = e(), { t: w } = s(), T = (e, t) => {
|
|
17
|
+
let n = w(e);
|
|
19
18
|
return n === e ? t : n;
|
|
20
|
-
}, { data:
|
|
19
|
+
}, { data: E, loading: D } = n({
|
|
21
20
|
variables: {},
|
|
22
21
|
fetchPolicy: "network-only"
|
|
23
|
-
}),
|
|
24
|
-
if (
|
|
22
|
+
}), O = E?.myDeveloperOrganizations ?? [], k = (() => {
|
|
23
|
+
if (O.length) return v && O.some((e) => e.id === v) ? v : O[0]?.id;
|
|
25
24
|
})();
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
o(() => {
|
|
26
|
+
k && k !== v && b(k);
|
|
28
27
|
}, [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
k,
|
|
29
|
+
v,
|
|
30
|
+
b
|
|
32
31
|
]);
|
|
33
|
-
let { data:
|
|
34
|
-
variables: { organizationId:
|
|
35
|
-
skip: !
|
|
32
|
+
let { data: A, loading: j } = n({
|
|
33
|
+
variables: { organizationId: k },
|
|
34
|
+
skip: !k,
|
|
36
35
|
fetchPolicy: "cache-and-network"
|
|
37
|
-
}),
|
|
38
|
-
|
|
39
|
-
if (!(
|
|
36
|
+
}), M = D || j, N = A ?? E;
|
|
37
|
+
o(() => {
|
|
38
|
+
if (!(D || !E) && !(O.length > 0)) {
|
|
40
39
|
try {
|
|
41
40
|
if (localStorage.getItem("devportal_setup_dismissed")) return;
|
|
42
41
|
} catch {
|
|
43
42
|
return;
|
|
44
43
|
}
|
|
45
|
-
|
|
44
|
+
d?.(`${f}/setup`);
|
|
46
45
|
}
|
|
47
46
|
}, [
|
|
48
|
-
O,
|
|
49
47
|
D,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
E,
|
|
49
|
+
O.length,
|
|
50
|
+
d,
|
|
51
|
+
f
|
|
53
52
|
]);
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
},
|
|
57
|
-
return /* @__PURE__ */
|
|
58
|
-
|
|
59
|
-
children: /* @__PURE__ */
|
|
60
|
-
title: /* @__PURE__ */
|
|
61
|
-
|
|
53
|
+
let P = A?.applications?.edges?.map((e) => e.node) ?? [], F = N?.applications?.totalCount ?? 0, I = O.length, L = (e) => {
|
|
54
|
+
d?.(`${f}${e}`);
|
|
55
|
+
}, R = M, z = !D && O.length > 0;
|
|
56
|
+
return /* @__PURE__ */ g(a, {
|
|
57
|
+
authOnly: !0,
|
|
58
|
+
children: /* @__PURE__ */ g(r, {
|
|
59
|
+
title: /* @__PURE__ */ _(h, { children: [
|
|
60
|
+
T("devportal.developer", "Developer"),
|
|
62
61
|
" ",
|
|
63
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ g(y, { children: T("devportal.portal", "Portal") })
|
|
64
63
|
] }),
|
|
65
|
-
actions:
|
|
64
|
+
actions: z ? /* @__PURE__ */ _("button", {
|
|
66
65
|
"data-tour": "devportal-dashboard-create-app-button",
|
|
67
|
-
onClick: () =>
|
|
66
|
+
onClick: () => L("/apps/new"),
|
|
68
67
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
70
|
-
}) :
|
|
68
|
+
children: [/* @__PURE__ */ g(m, { size: 16 }), T("devportal.createApp", "Create App")]
|
|
69
|
+
}) : R ? null : /* @__PURE__ */ _("button", {
|
|
71
70
|
"data-tour": "devportal-dashboard-create-org-button",
|
|
72
|
-
onClick: () =>
|
|
71
|
+
onClick: () => L("/organizations/new"),
|
|
73
72
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors",
|
|
74
|
-
children: [/* @__PURE__ */
|
|
73
|
+
children: [/* @__PURE__ */ g(m, { size: 16 }), T("devportal.createOrganization", "Create Organization")]
|
|
75
74
|
}),
|
|
76
|
-
children: /* @__PURE__ */
|
|
75
|
+
children: /* @__PURE__ */ _("div", {
|
|
77
76
|
className: "flex flex-col gap-8",
|
|
78
77
|
children: [
|
|
79
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ g("div", {
|
|
80
79
|
className: "flex items-center gap-6 border-b border-border-seam pb-6",
|
|
81
|
-
children:
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
icon: /* @__PURE__ */
|
|
84
|
-
value:
|
|
85
|
-
label:
|
|
80
|
+
children: R ? /* @__PURE__ */ g(p, { className: "h-4 w-4 animate-spin text-text-secondary" }) : /* @__PURE__ */ _(h, { children: [
|
|
81
|
+
/* @__PURE__ */ g(x, {
|
|
82
|
+
icon: /* @__PURE__ */ g(c, { size: 14 }),
|
|
83
|
+
value: F,
|
|
84
|
+
label: T("devportal.apps", "Apps")
|
|
86
85
|
}),
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
-
/* @__PURE__ */
|
|
89
|
-
icon: /* @__PURE__ */
|
|
90
|
-
value:
|
|
91
|
-
label:
|
|
86
|
+
/* @__PURE__ */ g("div", { className: "h-4 w-px bg-border-seam" }),
|
|
87
|
+
/* @__PURE__ */ g(x, {
|
|
88
|
+
icon: /* @__PURE__ */ g(u, { size: 14 }),
|
|
89
|
+
value: I,
|
|
90
|
+
label: T("devportal.organizations", "Organizations")
|
|
92
91
|
})
|
|
93
92
|
] })
|
|
94
93
|
}),
|
|
95
|
-
/* @__PURE__ */
|
|
96
|
-
title:
|
|
97
|
-
action:
|
|
98
|
-
onClick: () =>
|
|
94
|
+
/* @__PURE__ */ g(S, {
|
|
95
|
+
title: T("devportal.recentApplications", "Recent Applications"),
|
|
96
|
+
action: P.length > 0 ? /* @__PURE__ */ _("button", {
|
|
97
|
+
onClick: () => L("/apps"),
|
|
99
98
|
className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
100
|
-
children: [
|
|
99
|
+
children: [T("devportal.viewAll", "View all"), /* @__PURE__ */ g(l, { size: 14 })]
|
|
101
100
|
}) : void 0,
|
|
102
|
-
children:
|
|
101
|
+
children: R ? /* @__PURE__ */ g("div", {
|
|
103
102
|
className: "flex items-center justify-center py-12",
|
|
104
|
-
children: /* @__PURE__ */
|
|
105
|
-
}) :
|
|
103
|
+
children: /* @__PURE__ */ g(p, { className: "h-6 w-6 animate-spin text-text-secondary" })
|
|
104
|
+
}) : P.length > 0 ? /* @__PURE__ */ g("div", {
|
|
106
105
|
className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
107
|
-
children:
|
|
106
|
+
children: P.slice(0, 3).map((e) => /* @__PURE__ */ g(i, {
|
|
108
107
|
app: e,
|
|
109
|
-
onClick: () =>
|
|
108
|
+
onClick: () => L(`/apps/${e.id}`),
|
|
110
109
|
showActions: !1
|
|
111
110
|
}, e.id))
|
|
112
|
-
}) : /* @__PURE__ */
|
|
111
|
+
}) : /* @__PURE__ */ g(t, {
|
|
113
112
|
illustration: "empty-generic",
|
|
114
|
-
title:
|
|
115
|
-
description:
|
|
116
|
-
action:
|
|
117
|
-
onClick: () =>
|
|
113
|
+
title: T("devportal.noApplicationsYet", "No applications yet"),
|
|
114
|
+
description: z ? T("devportal.createFirstApplicationToGetStarted", "Create your first application to get started") : T("devportal.createOrgFirstToPublishApps", "Create an organization first to start publishing apps"),
|
|
115
|
+
action: z ? /* @__PURE__ */ _("button", {
|
|
116
|
+
onClick: () => L("/apps/new"),
|
|
118
117
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
119
|
-
children: [/* @__PURE__ */
|
|
120
|
-
}) : /* @__PURE__ */
|
|
121
|
-
onClick: () =>
|
|
118
|
+
children: [/* @__PURE__ */ g(m, { size: 16 }), T("devportal.createApp", "Create App")]
|
|
119
|
+
}) : /* @__PURE__ */ _("button", {
|
|
120
|
+
onClick: () => L("/organizations/new"),
|
|
122
121
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
123
|
-
children: [/* @__PURE__ */
|
|
122
|
+
children: [/* @__PURE__ */ g(m, { size: 16 }), T("devportal.createOrganization", "Create Organization")]
|
|
124
123
|
})
|
|
125
124
|
})
|
|
126
125
|
}),
|
|
127
|
-
(
|
|
128
|
-
title:
|
|
129
|
-
action:
|
|
130
|
-
onClick: () =>
|
|
126
|
+
(R || O.length > 0) && /* @__PURE__ */ g(S, {
|
|
127
|
+
title: T("devportal.yourOrganizations", "Your Organizations"),
|
|
128
|
+
action: O.length > 0 ? /* @__PURE__ */ _("button", {
|
|
129
|
+
onClick: () => L("/organizations"),
|
|
131
130
|
className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
132
|
-
children: [
|
|
131
|
+
children: [T("devportal.viewAll", "View all"), /* @__PURE__ */ g(l, { size: 14 })]
|
|
133
132
|
}) : void 0,
|
|
134
|
-
children:
|
|
133
|
+
children: R ? /* @__PURE__ */ g("div", {
|
|
135
134
|
className: "flex items-center justify-center py-12",
|
|
136
|
-
children: /* @__PURE__ */
|
|
137
|
-
}) : /* @__PURE__ */
|
|
135
|
+
children: /* @__PURE__ */ g(p, { className: "h-6 w-6 animate-spin text-text-secondary" })
|
|
136
|
+
}) : /* @__PURE__ */ g("div", {
|
|
138
137
|
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
139
|
-
children:
|
|
138
|
+
children: O.slice(0, 3).map((e) => /* @__PURE__ */ g(C, {
|
|
140
139
|
org: e,
|
|
141
|
-
onClick: () =>
|
|
140
|
+
onClick: () => L(`/organizations/${e.id}`)
|
|
142
141
|
}, e.id))
|
|
143
142
|
})
|
|
144
143
|
})
|
|
@@ -146,37 +145,37 @@ var x = () => {
|
|
|
146
145
|
})
|
|
147
146
|
})
|
|
148
147
|
});
|
|
149
|
-
},
|
|
148
|
+
}, x = ({ icon: e, value: t, label: n }) => /* @__PURE__ */ _("div", {
|
|
150
149
|
className: "flex items-center gap-1.5",
|
|
151
150
|
children: [
|
|
152
|
-
/* @__PURE__ */
|
|
151
|
+
/* @__PURE__ */ g("span", {
|
|
153
152
|
className: "text-text-muted",
|
|
154
153
|
children: e
|
|
155
154
|
}),
|
|
156
|
-
/* @__PURE__ */
|
|
155
|
+
/* @__PURE__ */ g("span", {
|
|
157
156
|
className: "text-sm font-semibold tabular-nums",
|
|
158
157
|
children: t
|
|
159
158
|
}),
|
|
160
|
-
/* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ g("span", {
|
|
161
160
|
className: "text-sm text-text-secondary",
|
|
162
161
|
children: n
|
|
163
162
|
})
|
|
164
163
|
]
|
|
165
|
-
}),
|
|
164
|
+
}), S = ({ title: e, action: t, children: n }) => /* @__PURE__ */ _("section", {
|
|
166
165
|
className: "flex flex-col gap-4",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ _("div", {
|
|
168
167
|
className: "flex items-center justify-between",
|
|
169
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ g("h2", {
|
|
170
169
|
className: "text-sm font-semibold uppercase tracking-wider text-text-secondary",
|
|
171
170
|
children: e
|
|
172
171
|
}), t]
|
|
173
172
|
}), n]
|
|
174
|
-
}),
|
|
175
|
-
let { t: n } =
|
|
173
|
+
}), C = ({ org: e, onClick: t }) => {
|
|
174
|
+
let { t: n } = s(), r = (e, t) => {
|
|
176
175
|
let r = n(e);
|
|
177
176
|
return r === e ? t : r;
|
|
178
177
|
}, i = e.name.split(" ").map((e) => e[0]).join("").slice(0, 2).toUpperCase();
|
|
179
|
-
return /* @__PURE__ */ v
|
|
178
|
+
return /* @__PURE__ */ _(v, {
|
|
180
179
|
treatment: "insight",
|
|
181
180
|
role: "button",
|
|
182
181
|
tabIndex: 0,
|
|
@@ -185,23 +184,23 @@ var x = () => {
|
|
|
185
184
|
onKeyDown: (e) => {
|
|
186
185
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), t());
|
|
187
186
|
},
|
|
188
|
-
children: [/* @__PURE__ */
|
|
187
|
+
children: [/* @__PURE__ */ _("div", {
|
|
189
188
|
className: "flex items-center gap-3 mb-4",
|
|
190
189
|
children: [
|
|
191
|
-
e.logoUrl ? /* @__PURE__ */
|
|
190
|
+
e.logoUrl ? /* @__PURE__ */ g("img", {
|
|
192
191
|
src: e.logoUrl,
|
|
193
192
|
alt: e.name,
|
|
194
193
|
className: "h-10 w-10 rounded-xl object-cover"
|
|
195
|
-
}) : /* @__PURE__ */
|
|
194
|
+
}) : /* @__PURE__ */ g("div", {
|
|
196
195
|
className: "flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold",
|
|
197
196
|
children: i
|
|
198
197
|
}),
|
|
199
|
-
/* @__PURE__ */
|
|
198
|
+
/* @__PURE__ */ _("div", {
|
|
200
199
|
className: "min-w-0 flex-1",
|
|
201
|
-
children: [/* @__PURE__ */
|
|
200
|
+
children: [/* @__PURE__ */ g("p", {
|
|
202
201
|
className: "font-semibold truncate text-text-primary",
|
|
203
202
|
children: e.name
|
|
204
|
-
}), /* @__PURE__ */
|
|
203
|
+
}), /* @__PURE__ */ _("p", {
|
|
205
204
|
className: "text-xs text-text-secondary mt-0.5",
|
|
206
205
|
children: [
|
|
207
206
|
e.publishedApps ?? 0,
|
|
@@ -210,34 +209,34 @@ var x = () => {
|
|
|
210
209
|
]
|
|
211
210
|
})]
|
|
212
211
|
}),
|
|
213
|
-
/* @__PURE__ */
|
|
212
|
+
/* @__PURE__ */ g(l, {
|
|
214
213
|
size: 15,
|
|
215
214
|
className: "text-text-muted shrink-0"
|
|
216
215
|
})
|
|
217
216
|
]
|
|
218
|
-
}), /* @__PURE__ */
|
|
217
|
+
}), /* @__PURE__ */ _("div", {
|
|
219
218
|
className: "grid grid-cols-2 gap-3",
|
|
220
|
-
children: [/* @__PURE__ */
|
|
219
|
+
children: [/* @__PURE__ */ _("div", {
|
|
221
220
|
className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
|
|
222
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ g(f, {
|
|
223
222
|
size: 12,
|
|
224
223
|
className: "text-text-muted shrink-0"
|
|
225
|
-
}), /* @__PURE__ */
|
|
224
|
+
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
|
|
226
225
|
className: "text-[11px] text-text-secondary leading-none mb-0.5",
|
|
227
226
|
children: r("devportal.installs", "Installs")
|
|
228
|
-
}), /* @__PURE__ */
|
|
227
|
+
}), /* @__PURE__ */ g("p", {
|
|
229
228
|
className: "text-sm font-semibold tabular-nums",
|
|
230
229
|
children: (e.totalInstalls || 0).toLocaleString()
|
|
231
230
|
})] })]
|
|
232
|
-
}), /* @__PURE__ */
|
|
231
|
+
}), /* @__PURE__ */ _("div", {
|
|
233
232
|
className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
|
|
234
|
-
children: [/* @__PURE__ */
|
|
233
|
+
children: [/* @__PURE__ */ g(d, {
|
|
235
234
|
size: 12,
|
|
236
235
|
className: "text-text-muted shrink-0"
|
|
237
|
-
}), /* @__PURE__ */
|
|
236
|
+
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
|
|
238
237
|
className: "text-[11px] text-text-secondary leading-none mb-0.5",
|
|
239
238
|
children: r("devportal.revenue", "Revenue")
|
|
240
|
-
}), /* @__PURE__ */
|
|
239
|
+
}), /* @__PURE__ */ _("p", {
|
|
241
240
|
className: "text-sm font-semibold tabular-nums",
|
|
242
241
|
children: ["$", (e.totalRevenue || 0).toLocaleString()]
|
|
243
242
|
})] })]
|
|
@@ -246,6 +245,6 @@ var x = () => {
|
|
|
246
245
|
});
|
|
247
246
|
};
|
|
248
247
|
//#endregion
|
|
249
|
-
export {
|
|
248
|
+
export { b as DashboardPage };
|
|
250
249
|
|
|
251
250
|
//# sourceMappingURL=DashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/devportal/pages/DashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AppWindow,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n Download,\n DollarSign,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, DeveloperOrganization } from \"../types\";\nimport {\n useGetDevportalDashboardBootstrapQuery,\n type OrganizationFieldsFragment,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\nexport const DashboardPage: FC = () => {\n const { navigate, basePath, activeOrgId, setActiveOrgId } = 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\n // network-only prevents a stale empty-orgs cache entry from\n // firing the /setup redirect before the real response arrives.\n const { data: orgsData, loading: orgsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: {},\n fetchPolicy: \"network-only\",\n });\n\n const organizations: OrganizationFieldsFragment[] =\n orgsData?.myDeveloperOrganizations ?? [];\n\n const resolvedOrgId: string | undefined = (() => {\n if (!organizations.length) return undefined;\n if (activeOrgId && organizations.some((o) => o.id === activeOrgId))\n return activeOrgId;\n return organizations[0]?.id;\n })();\n\n useEffect(() => {\n if (resolvedOrgId && resolvedOrgId !== activeOrgId) {\n setActiveOrgId(resolvedOrgId);\n }\n }, [resolvedOrgId, activeOrgId, setActiveOrgId]);\n\n const { data: appsData, loading: appsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: { organizationId: resolvedOrgId },\n skip: !resolvedOrgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const loading = orgsLoading || appsLoading;\n const data = appsData ?? orgsData;\n\n useEffect(() => {\n if (orgsLoading || !orgsData) return;\n if (organizations.length > 0) return;\n try {\n if (localStorage.getItem(\"devportal_setup_dismissed\")) return;\n } catch {\n return;\n }\n navigate?.(`${basePath}/setup`);\n }, [orgsLoading, orgsData, organizations.length, navigate, basePath]);\n\n const applications: ApplicationFieldsFragment[] =\n appsData?.applications?.edges?.map(\n (e: { node: ApplicationFieldsFragment }) => e.node,\n ) ?? [];\n\n const totalApps = data?.applications?.totalCount ?? 0;\n const totalOrgs = organizations.length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const isLoading = loading;\n // hasOrgs depends only on the orgs query — not on appsLoading — so the\n // header action doesn't flash \"Create Organization\" while apps are loading.\n const hasOrgs = !orgsLoading && organizations.length > 0;\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={\n <>\n {tr(\"devportal.developer\", \"Developer\")}{\" \"}\n <GradientText>{tr(\"devportal.portal\", \"Portal\")}</GradientText>\n </>\n }\n actions={\n hasOrgs ? (\n <button\n data-tour=\"devportal-dashboard-create-app-button\"\n onClick={() => handleNavigate(\"/apps/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : !isLoading ? (\n <button\n data-tour=\"devportal-dashboard-create-org-button\"\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {isLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<AppWindow size={14} />}\n value={totalApps}\n label={tr(\"devportal.apps\", \"Apps\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={totalOrgs}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Apps */}\n <DashSection\n title={tr(\"devportal.recentApplications\", \"Recent Applications\")}\n action={\n applications.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/apps\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : applications.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {applications\n .slice(0, 3)\n .map((app: ApplicationFieldsFragment) => (\n <AppCard\n key={app.id}\n app={app as Application}\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n showActions={false}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={tr(\"devportal.noApplicationsYet\", \"No applications yet\")}\n description={\n hasOrgs\n ? tr(\n \"devportal.createFirstApplicationToGetStarted\",\n \"Create your first application to get started\",\n )\n : tr(\n \"devportal.createOrgFirstToPublishApps\",\n \"Create an organization first to start publishing apps\",\n )\n }\n action={\n hasOrgs ? (\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : (\n <button\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n </button>\n )\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || organizations.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n organizations.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/organizations\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {organizations\n .slice(0, 3)\n .map((org: OrganizationFieldsFragment) => (\n <OrgCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() =>\n handleNavigate(`/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n\nconst StatPill: FC<{ icon: ReactNode; value: number; label: string }> = ({\n icon,\n value,\n label,\n}) => (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-muted\">{icon}</span>\n <span className=\"text-sm font-semibold tabular-nums\">{value}</span>\n <span className=\"text-sm text-text-secondary\">{label}</span>\n </div>\n);\n\nconst DashSection: FC<{\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}> = ({ title, action, children }) => (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold uppercase tracking-wider text-text-secondary\">\n {title}\n </h2>\n {action}\n </div>\n {children}\n </section>\n);\n\nconst OrgCard: FC<{ org: DeveloperOrganization; onClick: () => void }> = ({\n org,\n onClick,\n}) => {\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\n const initials = org.name\n .split(\" \")\n .map((w: string) => w[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-xl object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold\">\n {initials}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">{org.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {org.publishedApps ?? 0}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n <ArrowRight size={15} className=\"text-text-muted shrink-0\" />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <Download size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.installs\", \"Installs\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <DollarSign size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.revenue\", \"Revenue\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n ${(org.totalRevenue || 0).toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/devportal/pages/DashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AppWindow,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n Download,\n DollarSign,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport type { Application, DeveloperOrganization } from \"../types\";\nimport {\n useGetDevportalDashboardBootstrapQuery,\n type OrganizationFieldsFragment,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\nexport const DashboardPage: FC = () => {\n const { navigate, basePath, activeOrgId, setActiveOrgId } = 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\n // network-only prevents a stale empty-orgs cache entry from\n // firing the /setup redirect before the real response arrives.\n const { data: orgsData, loading: orgsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: {},\n fetchPolicy: \"network-only\",\n });\n\n const organizations: OrganizationFieldsFragment[] =\n orgsData?.myDeveloperOrganizations ?? [];\n\n const resolvedOrgId: string | undefined = (() => {\n if (!organizations.length) return undefined;\n if (activeOrgId && organizations.some((o) => o.id === activeOrgId))\n return activeOrgId;\n return organizations[0]?.id;\n })();\n\n useEffect(() => {\n if (resolvedOrgId && resolvedOrgId !== activeOrgId) {\n setActiveOrgId(resolvedOrgId);\n }\n }, [resolvedOrgId, activeOrgId, setActiveOrgId]);\n\n const { data: appsData, loading: appsLoading } =\n useGetDevportalDashboardBootstrapQuery({\n variables: { organizationId: resolvedOrgId },\n skip: !resolvedOrgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const loading = orgsLoading || appsLoading;\n const data = appsData ?? orgsData;\n\n useEffect(() => {\n if (orgsLoading || !orgsData) return;\n if (organizations.length > 0) return;\n try {\n if (localStorage.getItem(\"devportal_setup_dismissed\")) return;\n } catch {\n return;\n }\n navigate?.(`${basePath}/setup`);\n }, [orgsLoading, orgsData, organizations.length, navigate, basePath]);\n\n const applications: ApplicationFieldsFragment[] =\n appsData?.applications?.edges?.map(\n (e: { node: ApplicationFieldsFragment }) => e.node,\n ) ?? [];\n\n const totalApps = data?.applications?.totalCount ?? 0;\n const totalOrgs = organizations.length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const isLoading = loading;\n // hasOrgs depends only on the orgs query — not on appsLoading — so the\n // header action doesn't flash \"Create Organization\" while apps are loading.\n const hasOrgs = !orgsLoading && organizations.length > 0;\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.developer\", \"Developer\")}{\" \"}\n <GradientText>{tr(\"devportal.portal\", \"Portal\")}</GradientText>\n </>\n }\n actions={\n hasOrgs ? (\n <button\n data-tour=\"devportal-dashboard-create-app-button\"\n onClick={() => handleNavigate(\"/apps/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : !isLoading ? (\n <button\n data-tour=\"devportal-dashboard-create-org-button\"\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {isLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<AppWindow size={14} />}\n value={totalApps}\n label={tr(\"devportal.apps\", \"Apps\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={totalOrgs}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Apps */}\n <DashSection\n title={tr(\"devportal.recentApplications\", \"Recent Applications\")}\n action={\n applications.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/apps\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : applications.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {applications\n .slice(0, 3)\n .map((app: ApplicationFieldsFragment) => (\n <AppCard\n key={app.id}\n app={app as Application}\n onClick={() => handleNavigate(`/apps/${app.id}`)}\n showActions={false}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={tr(\"devportal.noApplicationsYet\", \"No applications yet\")}\n description={\n hasOrgs\n ? tr(\n \"devportal.createFirstApplicationToGetStarted\",\n \"Create your first application to get started\",\n )\n : tr(\n \"devportal.createOrgFirstToPublishApps\",\n \"Create an organization first to start publishing apps\",\n )\n }\n action={\n hasOrgs ? (\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n ) : (\n <button\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n </button>\n )\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || organizations.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n organizations.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/organizations\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {organizations\n .slice(0, 3)\n .map((org: OrganizationFieldsFragment) => (\n <OrgCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() =>\n handleNavigate(`/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n\nconst StatPill: FC<{ icon: ReactNode; value: number; label: string }> = ({\n icon,\n value,\n label,\n}) => (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-muted\">{icon}</span>\n <span className=\"text-sm font-semibold tabular-nums\">{value}</span>\n <span className=\"text-sm text-text-secondary\">{label}</span>\n </div>\n);\n\nconst DashSection: FC<{\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}> = ({ title, action, children }) => (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold uppercase tracking-wider text-text-secondary\">\n {title}\n </h2>\n {action}\n </div>\n {children}\n </section>\n);\n\nconst OrgCard: FC<{ org: DeveloperOrganization; onClick: () => void }> = ({\n org,\n onClick,\n}) => {\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\n const initials = org.name\n .split(\" \")\n .map((w: string) => w[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-xl object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold\">\n {initials}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">{org.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {org.publishedApps ?? 0}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n <ArrowRight size={15} className=\"text-text-muted shrink-0\" />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <Download size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.installs\", \"Installs\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <DollarSign size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.revenue\", \"Revenue\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n ${(org.totalRevenue || 0).toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@ import { SelectionCheckbox as s } from "../components/SelectionCheckbox.js";
|
|
|
7
7
|
import { ConfirmDialog as c } from "../components/ConfirmDialog.js";
|
|
8
8
|
import { PermissionGuard as l } from "../components/PermissionGuard.js";
|
|
9
9
|
import "../components/index.js";
|
|
10
|
-
import { DEVPORTAL_PERMISSIONS as u } from "../constants/permissions.js";
|
|
11
10
|
import { useDevportalPermission as ee } from "../hooks/usePermission.js";
|
|
11
|
+
import { DEVPORTAL_PERMISSIONS as u } from "../constants/permissions.js";
|
|
12
12
|
import { useCallback as d, useEffect as f, useMemo as te, useState as p } from "react";
|
|
13
13
|
import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
14
14
|
import { AlertCircle as h, AlertTriangle as g, Bot as _, Clock as v, Cog as y, Loader2 as b, Shield as x, Users as S, XCircle as C, Zap as w } from "lucide-react";
|
|
@@ -11,8 +11,8 @@ import { CheckboxField as ce, InputField as s, SelectField as c, TagInput as l,
|
|
|
11
11
|
import { ConfirmDialog as d } from "../components/ConfirmDialog.js";
|
|
12
12
|
import { PermissionGuard as le } from "../components/PermissionGuard.js";
|
|
13
13
|
import "../components/index.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { useDevportalPermission as f } from "../hooks/usePermission.js";
|
|
15
|
+
import { DEVPORTAL_PERMISSIONS as p } from "../constants/permissions.js";
|
|
16
16
|
import { useEffect as m, useState as h } from "react";
|
|
17
17
|
import { useI18n as ue } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
18
18
|
import { AlertCircle as de, AlertTriangle as fe, AppWindow as pe, Archive as me, Check as g, Copy as he, Eye as ge, EyeOff as _e, Power as ve, RefreshCw as _, Save as ye, Send as be, Trash2 as xe } from "lucide-react";
|
|
@@ -129,7 +129,7 @@ function De(e) {
|
|
|
129
129
|
} : null;
|
|
130
130
|
}
|
|
131
131
|
var S = () => {
|
|
132
|
-
let { navigate: a, basePath: S } = e(), { appId: C } = Se(), { t: w } = ue(), { allowed: T } = p
|
|
132
|
+
let { navigate: a, basePath: S } = e(), { appId: C } = Se(), { t: w } = ue(), { allowed: T } = f(p.APP_UPDATE), { allowed: E } = f(p.APP_DELETE), D = (e, t) => {
|
|
133
133
|
let n = w(e);
|
|
134
134
|
return n === e ? t : n;
|
|
135
135
|
}, [O, k] = h(!1), [A, j] = h({}), [Oe, M] = h(!1), [ke, N] = h(!1), [Ae, P] = h(!1), [F, I] = h(!1), [L, R] = h(!1), [z, B] = h(!1), [V, je] = h(null), [Me, H] = h(!1), { data: U, loading: Ne, error: W, refetch: Pe } = re({
|
|
@@ -308,7 +308,7 @@ var S = () => {
|
|
|
308
308
|
});
|
|
309
309
|
let We = K.status === "DRAFT" || K.status === "REJECTED", Ge = K.status === "PUBLISHED", Ke = K.status === "ACTIVE" || K.status === "PUBLISHED";
|
|
310
310
|
return /* @__PURE__ */ y(le, {
|
|
311
|
-
permission:
|
|
311
|
+
permission: p.APP_UPDATE,
|
|
312
312
|
children: /* @__PURE__ */ b(r, {
|
|
313
313
|
title: `${D("devportal.editAppTitlePrefix", "Edit:")} ${K.name}`,
|
|
314
314
|
description: D("devportal.editAppDescription", "Update your application settings"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListingPreviewPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/ListingPreviewPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ListingPreviewPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/ListingPreviewPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAyDhC,eAAO,MAAM,kBAAkB,EAAE,EAmahC,CAAC"}
|