@burdenoff/microfe-devportal 2026.717.1 → 2026.720.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.d.ts.map +1 -1
- package/dist/devportal/pages/CreateOrganizationPage.js +97 -98
- package/dist/devportal/pages/CreateOrganizationPage.js.map +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/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.d.ts.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +97 -98
- package/dist/devportal/pages/OrganizationsPage.js.map +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
|
@@ -6,122 +6,121 @@ import { PageLayout as i } from "../components/PageLayout.js";
|
|
|
6
6
|
import { StatusBadge as a, VerifiedBadge as o } from "../components/StatusBadge.js";
|
|
7
7
|
import { PermissionGuard as s } from "../components/PermissionGuard.js";
|
|
8
8
|
import "../components/index.js";
|
|
9
|
-
import { DEVPORTAL_PERMISSIONS as c } from "../constants/permissions.js";
|
|
10
9
|
import "../hooks/index.js";
|
|
11
|
-
import { useI18n as
|
|
12
|
-
import { AlertCircle as
|
|
13
|
-
import { jsx as
|
|
14
|
-
import { EmphasisPanel as
|
|
10
|
+
import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
+
import { AlertCircle as l, AppWindow as u, Building2 as d, CheckCircle as f, DollarSign as p, Loader2 as m, Plus as h, Users as g } from "lucide-react";
|
|
12
|
+
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
13
|
+
import { EmphasisPanel as y, GlassCard as b } from "@burdenoff/fe-libs/ui";
|
|
15
14
|
//#region src/devportal/pages/OrganizationsPage.tsx
|
|
16
|
-
var
|
|
17
|
-
let { navigate: a, basePath: o } = e(), { t:
|
|
18
|
-
let n =
|
|
15
|
+
var x = () => {
|
|
16
|
+
let { navigate: a, basePath: o } = e(), { t: u } = c(), d = (e, t) => {
|
|
17
|
+
let n = u(e);
|
|
19
18
|
return n === e ? t : n;
|
|
20
|
-
}, { data:
|
|
19
|
+
}, { data: f, loading: p, error: g, refetch: x } = n({ fetchPolicy: "cache-and-network" }), C = f?.myDeveloperOrganizations ?? [], w = (e) => {
|
|
21
20
|
a?.(`${o}${e}`);
|
|
22
21
|
};
|
|
23
|
-
return
|
|
24
|
-
title:
|
|
25
|
-
description:
|
|
26
|
-
children: /* @__PURE__ */
|
|
22
|
+
return p && !f ? /* @__PURE__ */ _(i, {
|
|
23
|
+
title: d("devportal.developerOrganizations", "Developer Organizations"),
|
|
24
|
+
description: d("devportal.manageYourDevTeams", "Manage your development teams"),
|
|
25
|
+
children: /* @__PURE__ */ v("div", {
|
|
27
26
|
className: "flex items-center justify-center py-12",
|
|
28
|
-
children: [/* @__PURE__ */
|
|
27
|
+
children: [/* @__PURE__ */ _(m, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ _("span", {
|
|
29
28
|
className: "ml-2 text-text-secondary",
|
|
30
|
-
children:
|
|
29
|
+
children: d("devportal.loadingOrganizations", "Loading organizations...")
|
|
31
30
|
})]
|
|
32
31
|
})
|
|
33
|
-
}) :
|
|
34
|
-
title:
|
|
35
|
-
description:
|
|
36
|
-
children: /* @__PURE__ */
|
|
32
|
+
}) : g ? /* @__PURE__ */ _(i, {
|
|
33
|
+
title: d("devportal.developerOrganizations", "Developer Organizations"),
|
|
34
|
+
description: d("devportal.manageYourDevTeams", "Manage your development teams"),
|
|
35
|
+
children: /* @__PURE__ */ v("div", {
|
|
37
36
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
|
|
38
37
|
children: [
|
|
39
|
-
/* @__PURE__ */
|
|
40
|
-
/* @__PURE__ */
|
|
38
|
+
/* @__PURE__ */ _(l, { className: "mx-auto h-8 w-8 text-status-error-text" }),
|
|
39
|
+
/* @__PURE__ */ _("h3", {
|
|
41
40
|
className: "mt-2 font-medium text-status-error-text",
|
|
42
|
-
children:
|
|
41
|
+
children: d("devportal.failedToLoadOrganizations", "Failed to load organizations")
|
|
43
42
|
}),
|
|
44
|
-
/* @__PURE__ */
|
|
43
|
+
/* @__PURE__ */ _("p", {
|
|
45
44
|
className: "mt-1 text-sm text-text-secondary",
|
|
46
|
-
children: r(
|
|
45
|
+
children: r(g)
|
|
47
46
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
49
|
-
onClick: () =>
|
|
47
|
+
/* @__PURE__ */ _("button", {
|
|
48
|
+
onClick: () => x(),
|
|
50
49
|
className: "mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
51
|
-
children:
|
|
50
|
+
children: d("devportal.tryAgain", "Try Again")
|
|
52
51
|
})
|
|
53
52
|
]
|
|
54
53
|
})
|
|
55
|
-
}) : /* @__PURE__ */
|
|
56
|
-
|
|
57
|
-
children: /* @__PURE__ */
|
|
58
|
-
title:
|
|
59
|
-
description:
|
|
60
|
-
purpose:
|
|
61
|
-
actions: /* @__PURE__ */
|
|
62
|
-
onClick: () =>
|
|
54
|
+
}) : /* @__PURE__ */ _(s, {
|
|
55
|
+
authOnly: !0,
|
|
56
|
+
children: /* @__PURE__ */ v(i, {
|
|
57
|
+
title: d("devportal.developerOrganizations", "Developer Organizations"),
|
|
58
|
+
description: d("devportal.manageYourDevTeams", "Manage your development teams"),
|
|
59
|
+
purpose: d("devportal.organizationsPurpose", "An organization is the team that owns your apps, members, and revenue. Create one so collaborators can share access to the same applications, billing, and store presence instead of working in isolation."),
|
|
60
|
+
actions: /* @__PURE__ */ v("button", {
|
|
61
|
+
onClick: () => w("/organizations/new"),
|
|
63
62
|
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",
|
|
64
|
-
children: [/* @__PURE__ */
|
|
63
|
+
children: [/* @__PURE__ */ _(h, { size: 16 }), d("devportal.createOrganization", "Create Organization")]
|
|
65
64
|
}),
|
|
66
|
-
children: [
|
|
65
|
+
children: [C.length > 0 && /* @__PURE__ */ _(y, {
|
|
67
66
|
className: "mb-6",
|
|
68
|
-
children: /* @__PURE__ */
|
|
67
|
+
children: /* @__PURE__ */ v("div", {
|
|
69
68
|
className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
|
|
70
69
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ v(b, {
|
|
72
71
|
treatment: "metric",
|
|
73
72
|
className: "p-4",
|
|
74
|
-
children: [/* @__PURE__ */
|
|
73
|
+
children: [/* @__PURE__ */ _("p", {
|
|
75
74
|
className: "text-sm text-text-secondary",
|
|
76
|
-
children:
|
|
77
|
-
}), /* @__PURE__ */
|
|
75
|
+
children: d("devportal.organizations", "Organizations")
|
|
76
|
+
}), /* @__PURE__ */ _("p", {
|
|
78
77
|
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
79
|
-
children:
|
|
78
|
+
children: C.length
|
|
80
79
|
})]
|
|
81
80
|
}),
|
|
82
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ v(b, {
|
|
83
82
|
treatment: "metric",
|
|
84
83
|
className: "p-4",
|
|
85
|
-
children: [/* @__PURE__ */
|
|
84
|
+
children: [/* @__PURE__ */ _("p", {
|
|
86
85
|
className: "text-sm text-text-secondary",
|
|
87
|
-
children:
|
|
88
|
-
}), /* @__PURE__ */
|
|
86
|
+
children: d("devportal.totalApps", "Total Apps")
|
|
87
|
+
}), /* @__PURE__ */ _("p", {
|
|
89
88
|
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
90
|
-
children:
|
|
89
|
+
children: C.reduce((e, t) => e + (t.totalApps ?? 0), 0)
|
|
91
90
|
})]
|
|
92
91
|
}),
|
|
93
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ v(b, {
|
|
94
93
|
treatment: "metric",
|
|
95
94
|
className: "p-4",
|
|
96
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ _("p", {
|
|
97
96
|
className: "text-sm text-text-secondary",
|
|
98
|
-
children:
|
|
99
|
-
}), /* @__PURE__ */
|
|
97
|
+
children: d("devportal.activeInstalls", "Active Installs")
|
|
98
|
+
}), /* @__PURE__ */ _("p", {
|
|
100
99
|
className: "mt-1 text-2xl font-semibold tabular-nums",
|
|
101
|
-
children:
|
|
100
|
+
children: C.reduce((e, t) => e + (t.activeInstalls ?? 0), 0).toLocaleString()
|
|
102
101
|
})]
|
|
103
102
|
})
|
|
104
103
|
]
|
|
105
104
|
})
|
|
106
|
-
}),
|
|
105
|
+
}), C.length > 0 ? /* @__PURE__ */ _("div", {
|
|
107
106
|
className: "grid gap-6",
|
|
108
|
-
children:
|
|
107
|
+
children: C.map((e) => /* @__PURE__ */ _(S, {
|
|
109
108
|
org: e,
|
|
110
|
-
onClick: () =>
|
|
109
|
+
onClick: () => w(`/organizations/${e.id}`)
|
|
111
110
|
}, e.id))
|
|
112
|
-
}) : /* @__PURE__ */
|
|
111
|
+
}) : /* @__PURE__ */ _(t, {
|
|
113
112
|
illustration: "empty-people",
|
|
114
|
-
title:
|
|
115
|
-
description:
|
|
116
|
-
action: /* @__PURE__ */
|
|
117
|
-
onClick: () =>
|
|
113
|
+
title: d("devportal.noOrganizationsYet", "No organizations yet"),
|
|
114
|
+
description: d("devportal.createOrgToCollaborate", "Create an organization to collaborate with your team and manage apps together"),
|
|
115
|
+
action: /* @__PURE__ */ v("button", {
|
|
116
|
+
onClick: () => w("/organizations/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__ */
|
|
118
|
+
children: [/* @__PURE__ */ _(h, { size: 16 }), d("devportal.createOrganization", "Create Organization")]
|
|
120
119
|
})
|
|
121
120
|
})]
|
|
122
121
|
})
|
|
123
122
|
});
|
|
124
|
-
},
|
|
123
|
+
}, S = ({ org: e, onClick: t }) => /* @__PURE__ */ v("div", {
|
|
125
124
|
role: "button",
|
|
126
125
|
tabIndex: 0,
|
|
127
126
|
onClick: t,
|
|
@@ -129,106 +128,106 @@ var S = () => {
|
|
|
129
128
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), t());
|
|
130
129
|
},
|
|
131
130
|
className: "cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
131
|
+
children: [/* @__PURE__ */ v("div", {
|
|
133
132
|
className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",
|
|
134
|
-
children: [/* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ v("div", {
|
|
135
134
|
className: "flex items-start gap-4",
|
|
136
|
-
children: [e.logoUrl ? /* @__PURE__ */
|
|
135
|
+
children: [e.logoUrl ? /* @__PURE__ */ _("img", {
|
|
137
136
|
src: e.logoUrl,
|
|
138
137
|
alt: e.name,
|
|
139
138
|
className: "h-16 w-16 rounded-lg object-cover"
|
|
140
|
-
}) : /* @__PURE__ */
|
|
139
|
+
}) : /* @__PURE__ */ _("div", {
|
|
141
140
|
className: "flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary",
|
|
142
|
-
children: /* @__PURE__ */
|
|
143
|
-
}), /* @__PURE__ */
|
|
144
|
-
/* @__PURE__ */
|
|
141
|
+
children: /* @__PURE__ */ _(d, { size: 32 })
|
|
142
|
+
}), /* @__PURE__ */ v("div", { children: [
|
|
143
|
+
/* @__PURE__ */ v("div", {
|
|
145
144
|
className: "flex items-center gap-2 flex-wrap",
|
|
146
145
|
children: [
|
|
147
|
-
/* @__PURE__ */
|
|
146
|
+
/* @__PURE__ */ _("h3", {
|
|
148
147
|
className: "text-lg font-semibold",
|
|
149
148
|
children: e.name
|
|
150
149
|
}),
|
|
151
|
-
e.isVerified && /* @__PURE__ */
|
|
152
|
-
e.isCertified && /* @__PURE__ */
|
|
150
|
+
e.isVerified && /* @__PURE__ */ _(o, { verified: !0 }),
|
|
151
|
+
e.isCertified && /* @__PURE__ */ v("span", {
|
|
153
152
|
className: "inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
153
|
+
children: [/* @__PURE__ */ _(f, { size: 12 }), " Certified"]
|
|
155
154
|
})
|
|
156
155
|
]
|
|
157
156
|
}),
|
|
158
|
-
e.description && /* @__PURE__ */
|
|
157
|
+
e.description && /* @__PURE__ */ _("p", {
|
|
159
158
|
className: "mt-1 text-sm text-text-secondary",
|
|
160
159
|
children: e.description
|
|
161
160
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ v("div", {
|
|
163
162
|
className: "mt-2 flex flex-wrap items-center gap-2",
|
|
164
|
-
children: [/* @__PURE__ */
|
|
163
|
+
children: [/* @__PURE__ */ _(a, {
|
|
165
164
|
status: e.tier,
|
|
166
165
|
type: "tier"
|
|
167
|
-
}), e.partnerTier && /* @__PURE__ */
|
|
166
|
+
}), e.partnerTier && /* @__PURE__ */ _(a, {
|
|
168
167
|
status: e.partnerTier,
|
|
169
168
|
type: "partner"
|
|
170
169
|
})]
|
|
171
170
|
})
|
|
172
171
|
] })]
|
|
173
|
-
}), /* @__PURE__ */
|
|
172
|
+
}), /* @__PURE__ */ v("div", {
|
|
174
173
|
className: "flex flex-wrap gap-6 text-sm",
|
|
175
174
|
children: [
|
|
176
|
-
/* @__PURE__ */
|
|
175
|
+
/* @__PURE__ */ v("div", {
|
|
177
176
|
className: "flex items-center gap-2",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
177
|
+
children: [/* @__PURE__ */ _(g, {
|
|
179
178
|
size: 16,
|
|
180
179
|
className: "text-text-secondary"
|
|
181
|
-
}), /* @__PURE__ */
|
|
180
|
+
}), /* @__PURE__ */ v("span", { children: [e.members?.length || 0, " members"] })]
|
|
182
181
|
}),
|
|
183
|
-
/* @__PURE__ */
|
|
182
|
+
/* @__PURE__ */ v("div", {
|
|
184
183
|
className: "flex items-center gap-2",
|
|
185
|
-
children: [/* @__PURE__ */
|
|
184
|
+
children: [/* @__PURE__ */ _(u, {
|
|
186
185
|
size: 16,
|
|
187
186
|
className: "text-text-secondary"
|
|
188
|
-
}), /* @__PURE__ */
|
|
187
|
+
}), /* @__PURE__ */ v("span", { children: [
|
|
189
188
|
e.publishedApps,
|
|
190
189
|
" / ",
|
|
191
190
|
e.totalApps,
|
|
192
191
|
" apps"
|
|
193
192
|
] })]
|
|
194
193
|
}),
|
|
195
|
-
/* @__PURE__ */
|
|
194
|
+
/* @__PURE__ */ v("div", {
|
|
196
195
|
className: "flex items-center gap-2",
|
|
197
|
-
children: [/* @__PURE__ */
|
|
196
|
+
children: [/* @__PURE__ */ _(p, {
|
|
198
197
|
size: 16,
|
|
199
198
|
className: "text-text-secondary"
|
|
200
|
-
}), /* @__PURE__ */
|
|
199
|
+
}), /* @__PURE__ */ v("span", { children: ["$", (e.totalRevenue || 0).toLocaleString()] })]
|
|
201
200
|
})
|
|
202
201
|
]
|
|
203
202
|
})]
|
|
204
|
-
}), /* @__PURE__ */
|
|
203
|
+
}), /* @__PURE__ */ v("div", {
|
|
205
204
|
className: "mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4",
|
|
206
205
|
children: [
|
|
207
|
-
/* @__PURE__ */
|
|
206
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
208
207
|
className: "text-xs text-text-secondary",
|
|
209
208
|
children: "Total Installs"
|
|
210
|
-
}), /* @__PURE__ */
|
|
209
|
+
}), /* @__PURE__ */ _("p", {
|
|
211
210
|
className: "text-lg font-semibold",
|
|
212
211
|
children: (e.totalInstalls || 0).toLocaleString()
|
|
213
212
|
})] }),
|
|
214
|
-
/* @__PURE__ */
|
|
213
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
215
214
|
className: "text-xs text-text-secondary",
|
|
216
215
|
children: "Active Installs"
|
|
217
|
-
}), /* @__PURE__ */
|
|
216
|
+
}), /* @__PURE__ */ _("p", {
|
|
218
217
|
className: "text-lg font-semibold",
|
|
219
218
|
children: (e.activeInstalls || 0).toLocaleString()
|
|
220
219
|
})] }),
|
|
221
|
-
/* @__PURE__ */
|
|
220
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
222
221
|
className: "text-xs text-text-secondary",
|
|
223
222
|
children: "API Calls"
|
|
224
|
-
}), /* @__PURE__ */
|
|
223
|
+
}), /* @__PURE__ */ _("p", {
|
|
225
224
|
className: "text-lg font-semibold",
|
|
226
225
|
children: e.totalApiCalls ? `${(parseInt(e.totalApiCalls) / 1e6).toFixed(1)}M` : "0"
|
|
227
226
|
})] }),
|
|
228
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
229
228
|
className: "text-xs text-text-secondary",
|
|
230
229
|
children: "Avg Rating"
|
|
231
|
-
}), /* @__PURE__ */
|
|
230
|
+
}), /* @__PURE__ */ _("p", {
|
|
232
231
|
className: "text-lg font-semibold",
|
|
233
232
|
children: e.averageRating ? `${e.averageRating.toFixed(1)} ★` : "N/A"
|
|
234
233
|
})] })
|
|
@@ -236,6 +235,6 @@ var S = () => {
|
|
|
236
235
|
})]
|
|
237
236
|
});
|
|
238
237
|
//#endregion
|
|
239
|
-
export {
|
|
238
|
+
export { x as OrganizationsPage };
|
|
240
239
|
|
|
241
240
|
//# sourceMappingURL=OrganizationsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationsPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Building2,\n Users,\n AppWindow,\n DollarSign,\n CheckCircle,\n AlertCircle,\n Loader2,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatusBadge, VerifiedBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n useGetMyOrganizationsQuery,\n getErrorMessage,\n type OrganizationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Organizations listing page\n *\n * Displays all developer organizations the current user is a member of.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const OrganizationsPage: 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\n // Fetch organizations from GraphQL API\n const { data, loading, error, refetch } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations = data?.myDeveloperOrganizations ?? [];\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingOrganizations\", \"Loading organizations...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadOrganizations\",\n \"Failed to load organizations\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.ORG_READ}>\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n purpose={tr(\n \"devportal.organizationsPurpose\",\n \"An organization is the team that owns your apps, members, and revenue. Create one so collaborators can share access to the same applications, billing, and store presence instead of working in isolation.\",\n )}\n actions={\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 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n >\n {organizations.length > 0 && (\n <EmphasisPanel className=\"mb-6\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.organizations\", \"Organizations\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.totalApps\", \"Total Apps\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.totalApps ?? 0),\n 0,\n )}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.activeInstalls\", \"Active Installs\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations\n .reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.activeInstalls ?? 0),\n 0,\n )\n .toLocaleString()}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n )}\n {organizations.length > 0 ? (\n <div className=\"grid gap-6\">\n {organizations.map((org: OrganizationFieldsFragment) => (\n <OrganizationCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\"devportal.noOrganizationsYet\", \"No organizations yet\")}\n description={tr(\n \"devportal.createOrgToCollaborate\",\n \"Create an organization to collaborate with your team and manage apps together\",\n )}\n action={\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(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n />\n )}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Organization card component\nconst OrganizationCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, onClick }) => {\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onClick();\n }\n }}\n className=\"cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Left side - Info */}\n <div className=\"flex items-start gap-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-16 w-16 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={32} />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"text-lg font-semibold\">{org.name}</h3>\n {org.isVerified && <VerifiedBadge verified />}\n {org.isCertified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <CheckCircle size={12} /> Certified\n </span>\n )}\n </div>\n {org.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {org.description}\n </p>\n )}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={org.tier} type=\"tier\" />\n {org.partnerTier && (\n <StatusBadge status={org.partnerTier} type=\"partner\" />\n )}\n </div>\n </div>\n </div>\n\n {/* Right side - Stats */}\n <div className=\"flex flex-wrap gap-6 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Users size={16} className=\"text-text-secondary\" />\n <span>{org.members?.length || 0} members</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AppWindow size={16} className=\"text-text-secondary\" />\n <span>\n {org.publishedApps} / {org.totalApps} apps\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <DollarSign size={16} className=\"text-text-secondary\" />\n <span>${(org.totalRevenue || 0).toLocaleString()}</span>\n </div>\n </div>\n </div>\n\n {/* Stats bar */}\n <div className=\"mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Total Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Active Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.activeInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">API Calls</p>\n <p className=\"text-lg font-semibold\">\n {org.totalApiCalls\n ? `${(parseInt(org.totalApiCalls) / 1000000).toFixed(1)}M`\n : \"0\"}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Avg Rating</p>\n <p className=\"text-lg font-semibold\">\n {org.averageRating ? `${org.averageRating.toFixed(1)} ★` : \"N/A\"}\n </p>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OrganizationsPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Building2,\n Users,\n AppWindow,\n DollarSign,\n CheckCircle,\n AlertCircle,\n Loader2,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatusBadge, VerifiedBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n useGetMyOrganizationsQuery,\n getErrorMessage,\n type OrganizationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Organizations listing page\n *\n * Displays all developer organizations the current user is a member of.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const OrganizationsPage: 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\n // Fetch organizations from GraphQL API\n const { data, loading, error, refetch } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations = data?.myDeveloperOrganizations ?? [];\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingOrganizations\", \"Loading organizations...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadOrganizations\",\n \"Failed to load organizations\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n purpose={tr(\n \"devportal.organizationsPurpose\",\n \"An organization is the team that owns your apps, members, and revenue. Create one so collaborators can share access to the same applications, billing, and store presence instead of working in isolation.\",\n )}\n actions={\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 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n >\n {organizations.length > 0 && (\n <EmphasisPanel className=\"mb-6\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.organizations\", \"Organizations\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.totalApps\", \"Total Apps\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations.reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.totalApps ?? 0),\n 0,\n )}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.activeInstalls\", \"Active Installs\")}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {organizations\n .reduce(\n (acc: number, org: OrganizationFieldsFragment) =>\n acc + (org.activeInstalls ?? 0),\n 0,\n )\n .toLocaleString()}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n )}\n {organizations.length > 0 ? (\n <div className=\"grid gap-6\">\n {organizations.map((org: OrganizationFieldsFragment) => (\n <OrganizationCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\"devportal.noOrganizationsYet\", \"No organizations yet\")}\n description={tr(\n \"devportal.createOrgToCollaborate\",\n \"Create an organization to collaborate with your team and manage apps together\",\n )}\n action={\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(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n />\n )}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Organization card component\nconst OrganizationCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, onClick }) => {\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onClick();\n }\n }}\n className=\"cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Left side - Info */}\n <div className=\"flex items-start gap-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-16 w-16 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={32} />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"text-lg font-semibold\">{org.name}</h3>\n {org.isVerified && <VerifiedBadge verified />}\n {org.isCertified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <CheckCircle size={12} /> Certified\n </span>\n )}\n </div>\n {org.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {org.description}\n </p>\n )}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={org.tier} type=\"tier\" />\n {org.partnerTier && (\n <StatusBadge status={org.partnerTier} type=\"partner\" />\n )}\n </div>\n </div>\n </div>\n\n {/* Right side - Stats */}\n <div className=\"flex flex-wrap gap-6 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Users size={16} className=\"text-text-secondary\" />\n <span>{org.members?.length || 0} members</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AppWindow size={16} className=\"text-text-secondary\" />\n <span>\n {org.publishedApps} / {org.totalApps} apps\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <DollarSign size={16} className=\"text-text-secondary\" />\n <span>${(org.totalRevenue || 0).toLocaleString()}</span>\n </div>\n </div>\n </div>\n\n {/* Stats bar */}\n <div className=\"mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Total Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Active Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.activeInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">API Calls</p>\n <p className=\"text-lg font-semibold\">\n {org.totalApiCalls\n ? `${(parseInt(org.totalApiCalls) / 1000000).toFixed(1)}M`\n : \"0\"}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Avg Rating</p>\n <p className=\"text-lg font-semibold\">\n {org.averageRating ? `${org.averageRating.toFixed(1)} ★` : \"N/A\"}\n </p>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AA+BA,IAAa,UAA8B;CACzC,IAAM,EAAE,aAAU,gBAAa,GAAc,EACvC,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAI9B,EAAE,SAAM,YAAS,UAAO,eAAY,EAA2B,EACnE,aAAa,qBACd,CAAC,EAEI,IAAgB,GAAM,4BAA4B,EAAE,EAEpD,KAAkB,MAAiB;AACvC,MAAW,GAAG,IAAW,IAAO;;AA6DlC,QAzDI,KAAW,CAAC,IAEZ,kBAAC,GAAD;EACE,OAAO,EACL,oCACA,0BACD;EACD,aAAa,EACX,gCACA,gCACD;YAED,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAS,WAAU,4CAA6C,CAAA,EAChE,kBAAC,QAAD;IAAM,WAAU;cACb,EAAG,kCAAkC,2BAA2B;IAC5D,CAAA,CACH;;EACK,CAAA,GAKb,IAEA,kBAAC,GAAD;EACE,OAAO,EACL,oCACA,0BACD;EACD,aAAa,EACX,gCACA,gCACD;YAED,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD,EAAa,WAAU,0CAA2C,CAAA;IAClE,kBAAC,MAAD;KAAI,WAAU;eACX,EACC,uCACA,+BACD;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,UAAA;YACf,kBAAC,GAAD;GACE,OAAO,EACL,oCACA,0BACD;GACD,aAAa,EACX,gCACA,gCACD;GACD,SAAS,EACP,kCACA,6MACD;GACD,SACE,kBAAC,UAAD;IACE,eAAe,EAAe,qBAAqB;IACnD,WAAU;cAFZ,CAIE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,gCAAgC,sBAAsB,CACnD;;aApBb,CAuBG,EAAc,SAAS,KACtB,kBAAC,GAAD;IAAe,WAAU;cACvB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAG,2BAA2B,gBAAgB;QAC7C,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAc;QACb,CAAA,CACM;;MACZ,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAG,uBAAuB,aAAa;QACtC,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAc,QACZ,GAAa,MACZ,KAAO,EAAI,aAAa,IAC1B,EACD;QACC,CAAA,CACM;;MACZ,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAG,4BAA4B,kBAAkB;QAChD,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV,EACE,QACE,GAAa,MACZ,KAAO,EAAI,kBAAkB,IAC/B,EACD,CACA,gBAAgB;QACjB,CAAA,CACM;;MACR;;IACQ,CAAA,EAEjB,EAAc,SAAS,IACtB,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAc,KAAK,MAClB,kBAAC,GAAD;KAEO;KACL,eAAe,EAAe,kBAAkB,EAAI,KAAK;KACzD,EAHK,EAAI,GAGT,CACF;IACE,CAAA,GAEN,kBAAC,GAAD;IACE,cAAa;IACb,OAAO,EAAG,gCAAgC,uBAAuB;IACjE,aAAa,EACX,oCACA,gFACD;IACD,QACE,kBAAC,UAAD;KACE,eAAe,EAAe,qBAAqB;KACnD,WAAU;eAFZ,CAIE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,gCAAgC,sBAAsB,CACnD;;IAEX,CAAA,CAEO;;EACG,CAAA;GAKhB,KAGA,EAAE,QAAK,iBAET,kBAAC,OAAD;CACE,MAAK;CACL,UAAU;CACD;CACT,YAAY,MAAU;AACpB,GAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,GAAS;;CAGb,WAAU;WAVZ,CAYE,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAI,UACH,kBAAC,OAAD;IACE,KAAK,EAAI;IACT,KAAK,EAAI;IACT,WAAU;IACV,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;IACnB,CAAA,EAER,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBAAyB,EAAI;OAAU,CAAA;MACpD,EAAI,cAAc,kBAAC,GAAD,EAAe,UAAA,IAAW,CAAA;MAC5C,EAAI,eACH,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA,EAAA,aACpB;;MAEL;;IACL,EAAI,eACH,kBAAC,KAAD;KAAG,WAAU;eACV,EAAI;KACH,CAAA;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAa,QAAQ,EAAI;MAAM,MAAK;MAAS,CAAA,EAC5C,EAAI,eACH,kBAAC,GAAD;MAAa,QAAQ,EAAI;MAAa,MAAK;MAAY,CAAA,CAErD;;IACF,EAAA,CAAA,CACF;MAGN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAO,MAAM;MAAI,WAAU;MAAwB,CAAA,EACnD,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAI,SAAS,UAAU,GAAE,WAAe,EAAA,CAAA,CAC3C;;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAW,MAAM;MAAI,WAAU;MAAwB,CAAA,EACvD,kBAAC,QAAD,EAAA,UAAA;MACG,EAAI;MAAc;MAAI,EAAI;MAAU;MAChC,EAAA,CAAA,CACH;;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAY,MAAM;MAAI,WAAU;MAAwB,CAAA,EACxD,kBAAC,QAAD,EAAA,UAAA,CAAM,MAAG,EAAI,gBAAgB,GAAG,gBAAgB,CAAQ,EAAA,CAAA,CACpD;;IACF;KACF;KAGN,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAkB,CAAA,EAC7D,kBAAC,KAAD;IAAG,WAAU;eACT,EAAI,iBAAiB,GAAG,gBAAgB;IACxC,CAAA,CACA,EAAA,CAAA;GACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAmB,CAAA,EAC9D,kBAAC,KAAD;IAAG,WAAU;eACT,EAAI,kBAAkB,GAAG,gBAAgB;IACzC,CAAA,CACA,EAAA,CAAA;GACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAa,CAAA,EACxD,kBAAC,KAAD;IAAG,WAAU;cACV,EAAI,gBACD,IAAI,SAAS,EAAI,cAAc,GAAG,KAAS,QAAQ,EAAE,CAAC,KACtD;IACF,CAAA,CACA,EAAA,CAAA;GACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAc,CAAA,EACzD,kBAAC,KAAD;IAAG,WAAU;cACV,EAAI,gBAAgB,GAAG,EAAI,cAAc,QAAQ,EAAE,CAAC,MAAM;IACzD,CAAA,CACA,EAAA,CAAA;GACF;IACF"}
|