@burdenoff/microfe-devportal 2026.830.1 → 2026.831.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/AdminDevportalRoot.d.ts.map +1 -1
- package/dist/devportal/AdminDevportalRoot.js +16 -19
- package/dist/devportal/AdminDevportalRoot.js.map +1 -1
- package/dist/devportal/DevportalRoot.d.ts.map +1 -1
- package/dist/devportal/DevportalRoot.js +36 -39
- package/dist/devportal/DevportalRoot.js.map +1 -1
- package/dist/devportal/components/AppCard.js +41 -41
- package/dist/devportal/components/ConfirmDialog.d.ts.map +1 -1
- package/dist/devportal/components/ConfirmDialog.js +19 -22
- package/dist/devportal/components/ConfirmDialog.js.map +1 -1
- package/dist/devportal/components/DataTable.d.ts.map +1 -1
- package/dist/devportal/components/DataTable.js +31 -34
- package/dist/devportal/components/DataTable.js.map +1 -1
- package/dist/devportal/components/FeatureFlaggedRoute.js +8 -8
- package/dist/devportal/components/FormField.d.ts.map +1 -1
- package/dist/devportal/components/FormField.js +26 -32
- package/dist/devportal/components/FormField.js.map +1 -1
- package/dist/devportal/components/GrantDelegationModal.js +64 -64
- package/dist/devportal/components/GrantDelegationModal.js.map +1 -1
- package/dist/devportal/components/LoadingState.d.ts.map +1 -1
- package/dist/devportal/components/LoadingState.js +5 -8
- package/dist/devportal/components/LoadingState.js.map +1 -1
- package/dist/devportal/components/PageLayout.d.ts.map +1 -1
- package/dist/devportal/components/PageLayout.js +10 -13
- package/dist/devportal/components/PageLayout.js.map +1 -1
- package/dist/devportal/components/PermissionGuard.d.ts.map +1 -1
- package/dist/devportal/components/PermissionGuard.js +11 -14
- package/dist/devportal/components/PermissionGuard.js.map +1 -1
- package/dist/devportal/components/SecretDisplay.d.ts.map +1 -1
- package/dist/devportal/components/SecretDisplay.js +24 -30
- package/dist/devportal/components/SecretDisplay.js.map +1 -1
- package/dist/devportal/components/SectionNav.d.ts.map +1 -1
- package/dist/devportal/components/SectionNav.js +24 -27
- package/dist/devportal/components/SectionNav.js.map +1 -1
- package/dist/devportal/components/StatusBadge.d.ts.map +1 -1
- package/dist/devportal/components/StatusBadge.js +24 -33
- package/dist/devportal/components/StatusBadge.js.map +1 -1
- package/dist/devportal/index.d.ts +1 -0
- package/dist/devportal/index.d.ts.map +1 -1
- package/dist/devportal/index.js +1 -0
- package/dist/devportal/pages/AdminReviewPage.js +172 -172
- package/dist/devportal/pages/AnalyticsDashboardPage.js +43 -43
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/ApiKeysPage.js +119 -119
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +45 -45
- package/dist/devportal/pages/ApplicationDetailPage.js +607 -607
- package/dist/devportal/pages/ApplicationVersionsPage.js +13 -13
- package/dist/devportal/pages/ApplicationsPage.d.ts.map +1 -1
- package/dist/devportal/pages/ApplicationsPage.js +104 -101
- package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +45 -45
- package/dist/devportal/pages/CreateApplicationPage.js +38 -38
- package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
- package/dist/devportal/pages/CreateOAuthClientPage.js +52 -52
- package/dist/devportal/pages/CreateOrganizationPage.js +26 -26
- package/dist/devportal/pages/CreateWebhookPage.d.ts.map +1 -1
- package/dist/devportal/pages/CreateWebhookPage.js +48 -48
- package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
- package/dist/devportal/pages/DashboardPage.d.ts.map +1 -1
- package/dist/devportal/pages/DashboardPage.js +66 -72
- package/dist/devportal/pages/DashboardPage.js.map +1 -1
- package/dist/devportal/pages/DelegationsPage.js +174 -174
- package/dist/devportal/pages/DocumentationPage.js +93 -93
- package/dist/devportal/pages/EditApplicationPage.js +14 -14
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +76 -76
- package/dist/devportal/pages/OAuthClientDetailPage.js +75 -75
- package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientsPage.js +64 -64
- package/dist/devportal/pages/OrganizationDetailPage.js +189 -189
- package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationMembersPage.js +10 -10
- package/dist/devportal/pages/OrganizationsPage.d.ts.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +163 -154
- package/dist/devportal/pages/OrganizationsPage.js.map +1 -1
- package/dist/devportal/pages/PublishPage.js +104 -104
- package/dist/devportal/pages/PublishPage.js.map +1 -1
- package/dist/devportal/pages/PublisherProfilePage.js +55 -55
- package/dist/devportal/pages/ResourcesPage.js +60 -60
- package/dist/devportal/pages/RevenueDashboardPage.js +60 -60
- package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.js +83 -83
- package/dist/devportal/pages/SellerItemsPage.js +163 -163
- package/dist/devportal/pages/SellerItemsPage.js.map +1 -1
- package/dist/devportal/pages/SellerOrdersPage.js +63 -63
- package/dist/devportal/pages/SettingsPage.js +21 -21
- package/dist/devportal/pages/SetupPage.js +183 -183
- package/dist/devportal/pages/SetupPage.js.map +1 -1
- package/dist/devportal/pages/StoreSubmissionPage.js +5 -5
- package/dist/devportal/pages/WebhookDetailPage.js +123 -123
- package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +118 -118
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/dist/devportal/utils/i18n.d.ts +9 -2
- package/dist/devportal/utils/i18n.d.ts.map +1 -1
- package/dist/devportal/utils/i18n.js +13 -10
- package/dist/devportal/utils/i18n.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/translations/en.d.ts +1251 -0
- package/dist/translations/en.d.ts.map +1 -0
- package/dist/translations/en.js +1235 -0
- package/dist/translations/en.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminDevportalRoot.d.ts","sourceRoot":"","sources":["../../src/devportal/AdminDevportalRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,OAAO,KAAK,EAAW,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAG3D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"AdminDevportalRoot.d.ts","sourceRoot":"","sources":["../../src/devportal/AdminDevportalRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,OAAO,KAAK,EAAW,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAG3D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,kBAAkB,CA6FrD,CAAC"}
|
|
@@ -1,35 +1,32 @@
|
|
|
1
1
|
import { DevportalProvider as e } from "./providers/DevportalProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { useTr as t } from "./utils/i18n.js";
|
|
3
|
+
import { AdminDevportalRoutes as n } from "./AdminDevportalRoutes.js";
|
|
4
|
+
import { useEffect as r } from "react";
|
|
5
|
+
import { ErrorBoundary as i } from "@burdenoff/fe-libs/shared/components";
|
|
6
6
|
import { BadgeCheck as a, ClipboardList as o, ShieldCheck as s } from "lucide-react";
|
|
7
7
|
import { jsx as c } from "react/jsx-runtime";
|
|
8
8
|
import { FeatureFlagProvider as l } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
9
9
|
//#region src/devportal/AdminDevportalRoot.tsx
|
|
10
10
|
var u = (u) => {
|
|
11
|
-
let { registerNavItems: d, registerFooterItems: f, basePath: p = "/developer-portal" } = u,
|
|
12
|
-
|
|
13
|
-
return n === e ? t : n;
|
|
14
|
-
}, g = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
15
|
-
return n(() => {
|
|
11
|
+
let { registerNavItems: d, registerFooterItems: f, basePath: p = "/developer-portal" } = u, m = t(), h = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
12
|
+
return r(() => {
|
|
16
13
|
if (d) return d([{
|
|
17
14
|
id: "admin-devportal",
|
|
18
|
-
label:
|
|
15
|
+
label: m("devportal.developerPortal", "Developer Portal"),
|
|
19
16
|
path: p,
|
|
20
17
|
icon: /* @__PURE__ */ c(s, { size: 20 }),
|
|
21
18
|
order: 70,
|
|
22
19
|
group: "globalconsole",
|
|
23
20
|
children: [{
|
|
24
21
|
id: "admin-devportal-reviews",
|
|
25
|
-
label:
|
|
26
|
-
path:
|
|
22
|
+
label: m("devportal.appReviewQueue", "App Review Queue"),
|
|
23
|
+
path: h(p, "/reviews"),
|
|
27
24
|
icon: /* @__PURE__ */ c(o, { size: 16 }),
|
|
28
25
|
order: 10
|
|
29
26
|
}, {
|
|
30
27
|
id: "admin-devportal-verifications",
|
|
31
|
-
label:
|
|
32
|
-
path:
|
|
28
|
+
label: m("devportal.verificationRequests", "Verification Requests"),
|
|
29
|
+
path: h(p, "/verifications"),
|
|
33
30
|
icon: /* @__PURE__ */ c(a, { size: 16 }),
|
|
34
31
|
order: 20
|
|
35
32
|
}]
|
|
@@ -38,18 +35,18 @@ var u = (u) => {
|
|
|
38
35
|
d,
|
|
39
36
|
p,
|
|
40
37
|
m
|
|
41
|
-
]),
|
|
38
|
+
]), r(() => {
|
|
42
39
|
if (f) return f([{
|
|
43
40
|
id: "admin-devportal-version",
|
|
44
|
-
label:
|
|
41
|
+
label: m("devportal.adminDeveloperPortalReady", "Admin Developer Portal Ready"),
|
|
45
42
|
type: "status",
|
|
46
43
|
order: 30,
|
|
47
44
|
section: "left"
|
|
48
45
|
}]);
|
|
49
|
-
}, [f, m]), /* @__PURE__ */ c(
|
|
46
|
+
}, [f, m]), /* @__PURE__ */ c(i, {
|
|
50
47
|
fallback: /* @__PURE__ */ c("div", {
|
|
51
48
|
className: "p-6 text-center text-text-secondary",
|
|
52
|
-
children: "Something went wrong loading this module. Please refresh the page."
|
|
49
|
+
children: m("devportal.error.moduleLoadFailed", "Something went wrong loading this module. Please refresh the page.")
|
|
53
50
|
}),
|
|
54
51
|
children: /* @__PURE__ */ c(l, {
|
|
55
52
|
workspaceId: null,
|
|
@@ -58,7 +55,7 @@ var u = (u) => {
|
|
|
58
55
|
children: /* @__PURE__ */ c(e, {
|
|
59
56
|
...u,
|
|
60
57
|
basePath: p,
|
|
61
|
-
children: /* @__PURE__ */ c(
|
|
58
|
+
children: /* @__PURE__ */ c(n, {})
|
|
62
59
|
})
|
|
63
60
|
})
|
|
64
61
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminDevportalRoot.js","names":[],"sources":["../../src/devportal/AdminDevportalRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect } from \"react\";\nimport { ShieldCheck, ClipboardList, BadgeCheck } from \"lucide-react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport {
|
|
1
|
+
{"version":3,"file":"AdminDevportalRoot.js","names":[],"sources":["../../src/devportal/AdminDevportalRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect } from \"react\";\nimport { ShieldCheck, ClipboardList, BadgeCheck } from \"lucide-react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { DevportalProvider } from \"./providers/DevportalProvider\";\nimport { useTr } from \"./utils/i18n\";\nimport type { NavItem, DevportalRootProps } from \"./types\";\nimport { AdminDevportalRoutes } from \"./AdminDevportalRoutes\";\n\n/**\n * AdminDevportalRoot\n *\n * Admin-only root for the Developer Portal microfrontend, intended to be\n * mounted exclusively in `admin-app`. Exposes the platform-admin review\n * queue (and any future super-admin-only devportal surfaces).\n *\n * Mirrors the AdminOrganizationRoot pattern: same `DevportalRootProps` shape\n * so hosts can swap between user and admin roots without adapter code; nav\n * items registered with `admin-devportal-*` IDs and grouped under\n * `globalconsole`.\n */\nexport const AdminDevportalRoot: FC<DevportalRootProps> = (props) => {\n const {\n registerNavItems,\n registerFooterItems,\n basePath = \"/developer-portal\",\n } = props;\n const tr = useTr();\n\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: \"admin-devportal\",\n label: tr(\"devportal.developerPortal\", \"Developer Portal\"),\n path: basePath,\n icon: <ShieldCheck size={20} />,\n order: 70,\n group: \"globalconsole\",\n children: [\n {\n id: \"admin-devportal-reviews\",\n label: tr(\"devportal.appReviewQueue\", \"App Review Queue\"),\n path: joinPath(basePath, \"/reviews\"),\n icon: <ClipboardList size={16} />,\n order: 10,\n },\n {\n id: \"admin-devportal-verifications\",\n label: tr(\n \"devportal.verificationRequests\",\n \"Verification Requests\",\n ),\n path: joinPath(basePath, \"/verifications\"),\n icon: <BadgeCheck size={16} />,\n order: 20,\n },\n ],\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, tr]);\n\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"admin-devportal-version\",\n label: tr(\n \"devportal.adminDeveloperPortalReady\",\n \"Admin Developer Portal Ready\",\n ),\n type: \"status\" as const,\n order: 30,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n {tr(\n \"devportal.error.moduleLoadFailed\",\n \"Something went wrong loading this module. Please refresh the page.\",\n )}\n </div>\n }\n >\n <FeatureFlagProvider\n workspaceId={null}\n gateway=\"global\"\n defaultEnabled={true}\n >\n <DevportalProvider {...props} basePath={basePath}>\n <AdminDevportalRoutes />\n </DevportalProvider>\n </FeatureFlagProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;AAsBA,IAAa,KAA8C,MAAU;CACnE,IAAM,EACJ,qBACA,wBACA,cAAW,wBACT,GACE,IAAK,GAAO,EAEZ,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AA6DtD,QAzDA,QAAgB;AACT,QAiCL,QADgB,EA9BY,CAC1B;GACE,IAAI;GACJ,OAAO,EAAG,6BAA6B,mBAAmB;GAC1D,MAAM;GACN,MAAM,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA;GAC/B,OAAO;GACP,OAAO;GACP,UAAU,CACR;IACE,IAAI;IACJ,OAAO,EAAG,4BAA4B,mBAAmB;IACzD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;IACjC,OAAO;IACR,EACD;IACE,IAAI;IACJ,OAAO,EACL,kCACA,wBACD;IACD,MAAM,EAAS,GAAU,iBAAiB;IAC1C,MAAM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;IAC9B,OAAO;IACR,CACF;GACF,CACF,CAEyC;IAEzC;EAAC;EAAkB;EAAU;EAAG,CAAC,EAEpC,QAAgB;AACT,QAgBL,QADgB,EAbI,CAClB;GACE,IAAI;GACJ,OAAO,EACL,uCACA,+BACD;GACD,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAG,CAAC,EAG3B,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EACC,oCACA,qEACD;GACG,CAAA;YAGR,kBAAC,GAAD;GACE,aAAa;GACb,SAAQ;GACR,gBAAgB;aAEhB,kBAAC,GAAD;IAAmB,GAAI;IAAiB;cACtC,kBAAC,GAAD,EAAwB,CAAA;IACN,CAAA;GACA,CAAA;EACR,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevportalRoot.d.ts","sourceRoot":"","sources":["../../src/devportal/DevportalRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAqBhC,OAAO,KAAK,EAAW,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"DevportalRoot.d.ts","sourceRoot":"","sources":["../../src/devportal/DevportalRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAqBhC,OAAO,KAAK,EAAW,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA4LhD,CAAC"}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import { DevportalProvider as e } from "./providers/DevportalProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { useTr as t } from "./utils/i18n.js";
|
|
3
|
+
import { setDevportalEventBusBridge as n } from "./events/index.js";
|
|
4
|
+
import { DevportalRoutes as r } from "./DevportalRoutes.js";
|
|
5
|
+
import { useEffect as i } from "react";
|
|
6
|
+
import { ErrorBoundary as a } from "@burdenoff/fe-libs/shared/components";
|
|
7
7
|
import { AppWindow as o, BarChart3 as s, BookOpen as c, Building2 as l, Code2 as u, DollarSign as d, Key as f, LayoutDashboard as p, Settings as m, Shield as h, Webhook as g, Wrench as _ } from "lucide-react";
|
|
8
8
|
import { jsx as v } from "react/jsx-runtime";
|
|
9
9
|
import { FeatureFlagProvider as y } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
10
10
|
import { useEventBus as b } from "@burdenoff/fe-libs/shared/events";
|
|
11
11
|
//#region src/devportal/DevportalRoot.tsx
|
|
12
12
|
var x = (x) => {
|
|
13
|
-
let { registerNavItems: S, registerFooterItems: C, basePath: w = "/" } = x,
|
|
14
|
-
|
|
15
|
-
return n === e ? t : n;
|
|
16
|
-
}, D = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
17
|
-
r(() => {
|
|
13
|
+
let { registerNavItems: S, registerFooterItems: C, basePath: w = "/" } = x, T = t(), E = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
14
|
+
i(() => {
|
|
18
15
|
if (S) return S({
|
|
19
16
|
id: "devportal",
|
|
20
|
-
label:
|
|
17
|
+
label: T("devportal.developerPortal", "Developer Portal"),
|
|
21
18
|
path: w,
|
|
22
19
|
icon: /* @__PURE__ */ v(u, { size: 20 }),
|
|
23
20
|
order: 75,
|
|
@@ -25,78 +22,78 @@ var x = (x) => {
|
|
|
25
22
|
children: [
|
|
26
23
|
{
|
|
27
24
|
id: "devportal-dashboard",
|
|
28
|
-
label:
|
|
25
|
+
label: T("devportal.dashboard", "Dashboard"),
|
|
29
26
|
path: w,
|
|
30
27
|
icon: /* @__PURE__ */ v(p, { size: 16 }),
|
|
31
28
|
order: 10
|
|
32
29
|
},
|
|
33
30
|
{
|
|
34
31
|
id: "devportal-organizations",
|
|
35
|
-
label:
|
|
36
|
-
path:
|
|
32
|
+
label: T("devportal.organizations", "Organizations"),
|
|
33
|
+
path: E(w, "organizations"),
|
|
37
34
|
icon: /* @__PURE__ */ v(l, { size: 16 }),
|
|
38
35
|
order: 20
|
|
39
36
|
},
|
|
40
37
|
{
|
|
41
38
|
id: "devportal-apps",
|
|
42
|
-
label:
|
|
43
|
-
path:
|
|
39
|
+
label: T("devportal.myApps", "My Apps"),
|
|
40
|
+
path: E(w, "apps"),
|
|
44
41
|
icon: /* @__PURE__ */ v(o, { size: 16 }),
|
|
45
42
|
order: 30
|
|
46
43
|
},
|
|
47
44
|
{
|
|
48
45
|
id: "devportal-oauth",
|
|
49
|
-
label:
|
|
50
|
-
path:
|
|
46
|
+
label: T("devportal.oauthClients", "OAuth Clients"),
|
|
47
|
+
path: E(w, "oauth"),
|
|
51
48
|
icon: /* @__PURE__ */ v(h, { size: 16 }),
|
|
52
49
|
order: 40
|
|
53
50
|
},
|
|
54
51
|
{
|
|
55
52
|
id: "devportal-api-keys",
|
|
56
|
-
label:
|
|
57
|
-
path:
|
|
53
|
+
label: T("devportal.apiKeys", "API Keys"),
|
|
54
|
+
path: E(w, "api-keys"),
|
|
58
55
|
icon: /* @__PURE__ */ v(f, { size: 16 }),
|
|
59
56
|
order: 50
|
|
60
57
|
},
|
|
61
58
|
{
|
|
62
59
|
id: "devportal-webhooks",
|
|
63
|
-
label:
|
|
64
|
-
path:
|
|
60
|
+
label: T("devportal.webhooks", "Webhooks"),
|
|
61
|
+
path: E(w, "webhooks"),
|
|
65
62
|
icon: /* @__PURE__ */ v(g, { size: 16 }),
|
|
66
63
|
order: 60
|
|
67
64
|
},
|
|
68
65
|
{
|
|
69
66
|
id: "devportal-analytics",
|
|
70
|
-
label:
|
|
71
|
-
path:
|
|
67
|
+
label: T("devportal.analytics", "Analytics"),
|
|
68
|
+
path: E(w, "analytics"),
|
|
72
69
|
icon: /* @__PURE__ */ v(s, { size: 16 }),
|
|
73
70
|
order: 70
|
|
74
71
|
},
|
|
75
72
|
{
|
|
76
73
|
id: "devportal-revenue",
|
|
77
|
-
label:
|
|
74
|
+
label: T("devportal.revenue", "Revenue"),
|
|
78
75
|
path: "/billing/earnings",
|
|
79
76
|
icon: /* @__PURE__ */ v(d, { size: 16 }),
|
|
80
77
|
order: 80
|
|
81
78
|
},
|
|
82
79
|
{
|
|
83
80
|
id: "devportal-docs",
|
|
84
|
-
label:
|
|
85
|
-
path:
|
|
81
|
+
label: T("devportal.documentation", "Documentation"),
|
|
82
|
+
path: E(w, "docs"),
|
|
86
83
|
icon: /* @__PURE__ */ v(c, { size: 16 }),
|
|
87
84
|
order: 90
|
|
88
85
|
},
|
|
89
86
|
{
|
|
90
87
|
id: "devportal-resources",
|
|
91
|
-
label:
|
|
92
|
-
path:
|
|
88
|
+
label: T("devportal.resources", "Resources"),
|
|
89
|
+
path: E(w, "resources"),
|
|
93
90
|
icon: /* @__PURE__ */ v(_, { size: 16 }),
|
|
94
91
|
order: 100
|
|
95
92
|
},
|
|
96
93
|
{
|
|
97
94
|
id: "devportal-settings",
|
|
98
|
-
label:
|
|
99
|
-
path:
|
|
95
|
+
label: T("devportal.settings", "Settings"),
|
|
96
|
+
path: E(w, "settings"),
|
|
100
97
|
icon: /* @__PURE__ */ v(m, { size: 16 }),
|
|
101
98
|
order: 110
|
|
102
99
|
}
|
|
@@ -106,25 +103,25 @@ var x = (x) => {
|
|
|
106
103
|
S,
|
|
107
104
|
w,
|
|
108
105
|
T
|
|
109
|
-
]),
|
|
106
|
+
]), i(() => {
|
|
110
107
|
if (C) return C([{
|
|
111
108
|
id: "devportal-status",
|
|
112
|
-
label:
|
|
109
|
+
label: T("devportal.developerPortalReady", "Developer Portal Ready"),
|
|
113
110
|
type: "status",
|
|
114
111
|
order: 10,
|
|
115
112
|
section: "left"
|
|
116
113
|
}]);
|
|
117
|
-
}, [C, T]),
|
|
114
|
+
}, [C, T]), i(() => {
|
|
118
115
|
let e = window.__breadcrumbRegistry;
|
|
119
|
-
if (e) return e.register("oauth",
|
|
116
|
+
if (e) return e.register("oauth", T("devportal.nav.oauth", "OAuth Clients")), e.register("api-keys", T("devportal.nav.apiKeys", "API Keys")), () => {
|
|
120
117
|
e.unregister("oauth"), e.unregister("api-keys");
|
|
121
118
|
};
|
|
122
119
|
}, [T]);
|
|
123
|
-
let
|
|
124
|
-
return
|
|
120
|
+
let D = b();
|
|
121
|
+
return i(() => (n(D), () => n(null)), [D]), /* @__PURE__ */ v(a, {
|
|
125
122
|
fallback: /* @__PURE__ */ v("div", {
|
|
126
123
|
className: "p-6 text-center text-text-secondary",
|
|
127
|
-
children: "Something went wrong loading this module. Please refresh the page."
|
|
124
|
+
children: T("devportal.error.moduleLoadFailed", "Something went wrong loading this module. Please refresh the page.")
|
|
128
125
|
}),
|
|
129
126
|
children: /* @__PURE__ */ v(y, {
|
|
130
127
|
workspaceId: null,
|
|
@@ -132,7 +129,7 @@ var x = (x) => {
|
|
|
132
129
|
defaultEnabled: !0,
|
|
133
130
|
children: /* @__PURE__ */ v(e, {
|
|
134
131
|
...x,
|
|
135
|
-
children: /* @__PURE__ */ v(
|
|
132
|
+
children: /* @__PURE__ */ v(r, {})
|
|
136
133
|
})
|
|
137
134
|
})
|
|
138
135
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevportalRoot.js","names":[],"sources":["../../src/devportal/DevportalRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect } from \"react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Code2,\n LayoutDashboard,\n Building2,\n AppWindow,\n BookOpen,\n Settings,\n Webhook,\n Key,\n Shield,\n BarChart3,\n DollarSign,\n Wrench,\n} from \"lucide-react\";\nimport { DevportalProvider } from \"./providers/DevportalProvider\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport type { NavItem, DevportalRootProps } from \"./types\";\nimport { DevportalRoutes } from \"./DevportalRoutes\";\nimport { setDevportalEventBusBridge } from \"./events\";\n\n/**\n * Root component for the Developer Portal microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { DevportalRoot, type DevportalRootProps } from '@burdenoff/microfe-devportal';\n *\n * function App() {\n * const props: DevportalRootProps = {\n * basePath: '/devportal',\n * navigate: (path) => router.push(path),\n * currentUser: { id: '1', email: 'user@example.com' },\n * tenantId: 'tenant-123',\n * apiGatewayUrl: 'https://api.example.com',\n * authToken: 'token',\n * };\n *\n * return <DevportalRoot {...props} />;\n * }\n * ```\n */\nexport const DevportalRoot: FC<DevportalRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = \"/\" } = props;\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 // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n // Create a parent \"Developer Portal\" item with children for dropdown behavior\n const devportalNavItem: NavItem = {\n id: \"devportal\",\n label: tr(\"devportal.developerPortal\", \"Developer Portal\"),\n path: basePath,\n icon: <Code2 size={20} />,\n order: 75,\n group: \"global\",\n children: [\n {\n id: \"devportal-dashboard\",\n label: tr(\"devportal.dashboard\", \"Dashboard\"),\n path: basePath,\n icon: <LayoutDashboard size={16} />,\n order: 10,\n },\n {\n id: \"devportal-organizations\",\n label: tr(\"devportal.organizations\", \"Organizations\"),\n path: joinPath(basePath, \"organizations\"),\n icon: <Building2 size={16} />,\n order: 20,\n },\n {\n id: \"devportal-apps\",\n label: tr(\"devportal.myApps\", \"My Apps\"),\n path: joinPath(basePath, \"apps\"),\n icon: <AppWindow size={16} />,\n order: 30,\n },\n {\n id: \"devportal-oauth\",\n label: tr(\"devportal.oauthClients\", \"OAuth Clients\"),\n path: joinPath(basePath, \"oauth\"),\n icon: <Shield size={16} />,\n order: 40,\n },\n {\n id: \"devportal-api-keys\",\n label: tr(\"devportal.apiKeys\", \"API Keys\"),\n path: joinPath(basePath, \"api-keys\"),\n icon: <Key size={16} />,\n order: 50,\n },\n {\n id: \"devportal-webhooks\",\n label: tr(\"devportal.webhooks\", \"Webhooks\"),\n path: joinPath(basePath, \"webhooks\"),\n icon: <Webhook size={16} />,\n order: 60,\n },\n {\n id: \"devportal-analytics\",\n label: tr(\"devportal.analytics\", \"Analytics\"),\n path: joinPath(basePath, \"analytics\"),\n icon: <BarChart3 size={16} />,\n order: 70,\n },\n {\n id: \"devportal-revenue\",\n label: tr(\"devportal.revenue\", \"Revenue\"),\n path: \"/billing/earnings\",\n icon: <DollarSign size={16} />,\n order: 80,\n },\n {\n id: \"devportal-docs\",\n label: tr(\"devportal.documentation\", \"Documentation\"),\n path: joinPath(basePath, \"docs\"),\n icon: <BookOpen size={16} />,\n order: 90,\n },\n {\n id: \"devportal-resources\",\n label: tr(\"devportal.resources\", \"Resources\"),\n path: joinPath(basePath, \"resources\"),\n icon: <Wrench size={16} />,\n order: 100,\n },\n {\n id: \"devportal-settings\",\n label: tr(\"devportal.settings\", \"Settings\"),\n path: joinPath(basePath, \"settings\"),\n icon: <Settings size={16} />,\n order: 110,\n },\n ],\n };\n\n // Register and get cleanup function\n const cleanup = registerNavItems(devportalNavItem);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"devportal-status\",\n label: tr(\"devportal.developerPortalReady\", \"Developer Portal Ready\"),\n type: \"status\" as const,\n order: 10,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n // Register static breadcrumb labels for URL segments that need pretty names.\n // The AutoBreadcrumbs component reads window.__breadcrumbRegistry for all\n // segments (not just UUIDs), so segments like 'oauth' and 'api-keys' get\n // human-readable labels instead of the auto-cased URL segment.\n useEffect(() => {\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n if (!reg) return;\n reg.register(\"oauth\", tr(\"devportal.nav.oauth\", \"OAuth Clients\"));\n reg.register(\"api-keys\", tr(\"devportal.nav.apiKeys\", \"API Keys\"));\n return () => {\n reg.unregister(\"oauth\");\n reg.unregister(\"api-keys\");\n };\n }, [t]);\n\n // Bridge fe-libs event bus -> devportal event bus so MFE pages can emit\n // domain events (`devportal.app.created`, etc.) and the shell sinks\n // (RybbitSink / BackendAuditSink / OtelBrowserSink) consume them centrally.\n // Per memory rule + spec 47: MFEs must not call Rybbit/OTel/fetch directly.\n const sharedBus = useEventBus();\n useEffect(() => {\n setDevportalEventBusBridge(\n sharedBus as unknown as { emit: (n: string, p: unknown) => void },\n );\n return () => setDevportalEventBusBridge(null);\n }, [sharedBus]);\n\n // NOTE: When running in the shell (workspaces-app), the shell's MultiGatewayProvider\n // already provides an ApolloProvider via GatewayRoute. The devportal uses that context.\n // When running standalone, the main.tsx wraps with DevPortalProvider (ApolloProvider).\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n Something went wrong loading this module. Please refresh the page.\n </div>\n }\n >\n <FeatureFlagProvider\n workspaceId={null}\n gateway=\"global\"\n defaultEnabled={true}\n >\n <DevportalProvider {...props}>\n <DevportalRoutes />\n </DevportalProvider>\n </FeatureFlagProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DevportalRoot.js","names":[],"sources":["../../src/devportal/DevportalRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect } from \"react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport {\n Code2,\n LayoutDashboard,\n Building2,\n AppWindow,\n BookOpen,\n Settings,\n Webhook,\n Key,\n Shield,\n BarChart3,\n DollarSign,\n Wrench,\n} from \"lucide-react\";\nimport { DevportalProvider } from \"./providers/DevportalProvider\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport { useTr } from \"./utils/i18n\";\nimport type { NavItem, DevportalRootProps } from \"./types\";\nimport { DevportalRoutes } from \"./DevportalRoutes\";\nimport { setDevportalEventBusBridge } from \"./events\";\n\n/**\n * Root component for the Developer Portal microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { DevportalRoot, type DevportalRootProps } from '@burdenoff/microfe-devportal';\n *\n * function App() {\n * const props: DevportalRootProps = {\n * basePath: '/devportal',\n * navigate: (path) => router.push(path),\n * currentUser: { id: '1', email: 'user@example.com' },\n * tenantId: 'tenant-123',\n * apiGatewayUrl: 'https://api.example.com',\n * authToken: 'token',\n * };\n *\n * return <DevportalRoot {...props} />;\n * }\n * ```\n */\nexport const DevportalRoot: FC<DevportalRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = \"/\" } = props;\n const tr = useTr();\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n // Create a parent \"Developer Portal\" item with children for dropdown behavior\n const devportalNavItem: NavItem = {\n id: \"devportal\",\n label: tr(\"devportal.developerPortal\", \"Developer Portal\"),\n path: basePath,\n icon: <Code2 size={20} />,\n order: 75,\n group: \"global\",\n children: [\n {\n id: \"devportal-dashboard\",\n label: tr(\"devportal.dashboard\", \"Dashboard\"),\n path: basePath,\n icon: <LayoutDashboard size={16} />,\n order: 10,\n },\n {\n id: \"devportal-organizations\",\n label: tr(\"devportal.organizations\", \"Organizations\"),\n path: joinPath(basePath, \"organizations\"),\n icon: <Building2 size={16} />,\n order: 20,\n },\n {\n id: \"devportal-apps\",\n label: tr(\"devportal.myApps\", \"My Apps\"),\n path: joinPath(basePath, \"apps\"),\n icon: <AppWindow size={16} />,\n order: 30,\n },\n {\n id: \"devportal-oauth\",\n label: tr(\"devportal.oauthClients\", \"OAuth Clients\"),\n path: joinPath(basePath, \"oauth\"),\n icon: <Shield size={16} />,\n order: 40,\n },\n {\n id: \"devportal-api-keys\",\n label: tr(\"devportal.apiKeys\", \"API Keys\"),\n path: joinPath(basePath, \"api-keys\"),\n icon: <Key size={16} />,\n order: 50,\n },\n {\n id: \"devportal-webhooks\",\n label: tr(\"devportal.webhooks\", \"Webhooks\"),\n path: joinPath(basePath, \"webhooks\"),\n icon: <Webhook size={16} />,\n order: 60,\n },\n {\n id: \"devportal-analytics\",\n label: tr(\"devportal.analytics\", \"Analytics\"),\n path: joinPath(basePath, \"analytics\"),\n icon: <BarChart3 size={16} />,\n order: 70,\n },\n {\n id: \"devportal-revenue\",\n label: tr(\"devportal.revenue\", \"Revenue\"),\n path: \"/billing/earnings\",\n icon: <DollarSign size={16} />,\n order: 80,\n },\n {\n id: \"devportal-docs\",\n label: tr(\"devportal.documentation\", \"Documentation\"),\n path: joinPath(basePath, \"docs\"),\n icon: <BookOpen size={16} />,\n order: 90,\n },\n {\n id: \"devportal-resources\",\n label: tr(\"devportal.resources\", \"Resources\"),\n path: joinPath(basePath, \"resources\"),\n icon: <Wrench size={16} />,\n order: 100,\n },\n {\n id: \"devportal-settings\",\n label: tr(\"devportal.settings\", \"Settings\"),\n path: joinPath(basePath, \"settings\"),\n icon: <Settings size={16} />,\n order: 110,\n },\n ],\n };\n\n // Register and get cleanup function\n const cleanup = registerNavItems(devportalNavItem);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, tr]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"devportal-status\",\n label: tr(\"devportal.developerPortalReady\", \"Developer Portal Ready\"),\n type: \"status\" as const,\n order: 10,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n // Register static breadcrumb labels for URL segments that need pretty names.\n // The AutoBreadcrumbs component reads window.__breadcrumbRegistry for all\n // segments (not just UUIDs), so segments like 'oauth' and 'api-keys' get\n // human-readable labels instead of the auto-cased URL segment.\n useEffect(() => {\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n if (!reg) return;\n reg.register(\"oauth\", tr(\"devportal.nav.oauth\", \"OAuth Clients\"));\n reg.register(\"api-keys\", tr(\"devportal.nav.apiKeys\", \"API Keys\"));\n return () => {\n reg.unregister(\"oauth\");\n reg.unregister(\"api-keys\");\n };\n }, [tr]);\n\n // Bridge fe-libs event bus -> devportal event bus so MFE pages can emit\n // domain events (`devportal.app.created`, etc.) and the shell sinks\n // (RybbitSink / BackendAuditSink / OtelBrowserSink) consume them centrally.\n // Per memory rule + spec 47: MFEs must not call Rybbit/OTel/fetch directly.\n const sharedBus = useEventBus();\n useEffect(() => {\n setDevportalEventBusBridge(\n sharedBus as unknown as { emit: (n: string, p: unknown) => void },\n );\n return () => setDevportalEventBusBridge(null);\n }, [sharedBus]);\n\n // NOTE: When running in the shell (workspaces-app), the shell's MultiGatewayProvider\n // already provides an ApolloProvider via GatewayRoute. The devportal uses that context.\n // When running standalone, the main.tsx wraps with DevPortalProvider (ApolloProvider).\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n {tr(\n \"devportal.error.moduleLoadFailed\",\n \"Something went wrong loading this module. Please refresh the page.\",\n )}\n </div>\n }\n >\n <FeatureFlagProvider\n workspaceId={null}\n gateway=\"global\"\n defaultEnabled={true}\n >\n <DevportalProvider {...props}>\n <DevportalRoutes />\n </DevportalProvider>\n </FeatureFlagProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":"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"}
|
|
@@ -3,19 +3,19 @@ import { cn as t } from "../utils/cn.js";
|
|
|
3
3
|
import { APP_TYPE_LABELS as n } from "../utils/constants.js";
|
|
4
4
|
import { FeaturedBadge as r, StatusBadge as i, VerifiedBadge as a } from "./StatusBadge.js";
|
|
5
5
|
import { SelectionCheckbox as o } from "./SelectionCheckbox.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { AppWindow as s, Download as c, ExternalLink as l, Star as u } from "lucide-react";
|
|
7
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
|
+
import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
9
|
import { GlassCard as m } from "@burdenoff/fe-libs/ui";
|
|
10
10
|
//#region src/devportal/components/AppCard.tsx
|
|
11
11
|
var h = ({ app: h, onClick: g, className: _, showActions: v = !0, selected: y = !1, onToggleSelect: b }) => {
|
|
12
|
-
let { navigate: x, basePath: S } = e(), { t: C } =
|
|
12
|
+
let { navigate: x, basePath: S } = e(), { t: C } = p(), w = (e, t) => {
|
|
13
13
|
let n = C(e);
|
|
14
14
|
return n === e ? t : n;
|
|
15
15
|
}, T = () => {
|
|
16
16
|
g ? g() : x && x(`${S}/apps/${h.id}`);
|
|
17
17
|
};
|
|
18
|
-
return /* @__PURE__ */
|
|
18
|
+
return /* @__PURE__ */ f(m, {
|
|
19
19
|
treatment: "insight",
|
|
20
20
|
role: "button",
|
|
21
21
|
tabIndex: 0,
|
|
@@ -25,119 +25,119 @@ var h = ({ app: h, onClick: g, className: _, showActions: v = !0, selected: y =
|
|
|
25
25
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), T());
|
|
26
26
|
},
|
|
27
27
|
children: [
|
|
28
|
-
/* @__PURE__ */
|
|
28
|
+
/* @__PURE__ */ f("div", {
|
|
29
29
|
className: "flex items-start gap-3",
|
|
30
30
|
children: [
|
|
31
|
-
b && /* @__PURE__ */
|
|
31
|
+
b && /* @__PURE__ */ d("div", {
|
|
32
32
|
onClick: (e) => e.stopPropagation(),
|
|
33
|
-
children: /* @__PURE__ */
|
|
33
|
+
children: /* @__PURE__ */ d(o, {
|
|
34
34
|
checked: y,
|
|
35
35
|
onChange: b,
|
|
36
36
|
ariaLabel: `Select application ${h.name}`,
|
|
37
37
|
className: "mt-1"
|
|
38
38
|
})
|
|
39
39
|
}),
|
|
40
|
-
h.iconUrl ? /* @__PURE__ */
|
|
40
|
+
h.iconUrl ? /* @__PURE__ */ d("img", {
|
|
41
41
|
src: h.iconUrl,
|
|
42
42
|
alt: h.name,
|
|
43
43
|
className: "h-12 w-12 rounded-lg object-cover"
|
|
44
|
-
}) : /* @__PURE__ */
|
|
44
|
+
}) : /* @__PURE__ */ d("div", {
|
|
45
45
|
className: "flex h-12 w-12 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary",
|
|
46
|
-
children: /* @__PURE__ */
|
|
46
|
+
children: /* @__PURE__ */ d(s, { size: 24 })
|
|
47
47
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ f("div", {
|
|
49
49
|
className: "flex-1 min-w-0",
|
|
50
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ f("div", {
|
|
51
51
|
className: "flex items-center gap-2",
|
|
52
|
-
children: [/* @__PURE__ */
|
|
52
|
+
children: [/* @__PURE__ */ d("h3", {
|
|
53
53
|
className: "font-semibold truncate",
|
|
54
54
|
children: h.name
|
|
55
|
-
}), h.isVerified && /* @__PURE__ */
|
|
56
|
-
}), /* @__PURE__ */
|
|
55
|
+
}), h.isVerified && /* @__PURE__ */ d(a, { verified: !0 })]
|
|
56
|
+
}), /* @__PURE__ */ d("p", {
|
|
57
57
|
className: "text-sm text-text-secondary",
|
|
58
58
|
children: n[h.appType] || h.appType
|
|
59
59
|
})]
|
|
60
60
|
})
|
|
61
61
|
]
|
|
62
62
|
}),
|
|
63
|
-
h.shortDescription && /* @__PURE__ */
|
|
63
|
+
h.shortDescription && /* @__PURE__ */ d("p", {
|
|
64
64
|
className: "mt-3 text-sm text-text-secondary line-clamp-2",
|
|
65
65
|
children: h.shortDescription
|
|
66
66
|
}),
|
|
67
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ f("div", {
|
|
68
68
|
className: "mt-3 flex flex-wrap items-center gap-2",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ d(i, { status: h.status }), h.isFeatured && /* @__PURE__ */ d(r, {})]
|
|
70
70
|
}),
|
|
71
|
-
/* @__PURE__ */
|
|
71
|
+
/* @__PURE__ */ f("div", {
|
|
72
72
|
className: "mt-4 flex items-center gap-4 text-sm text-text-secondary",
|
|
73
|
-
children: [h.averageRating !== void 0 && h.averageRating > 0 && /* @__PURE__ */
|
|
73
|
+
children: [h.averageRating !== void 0 && h.averageRating > 0 && /* @__PURE__ */ f("span", {
|
|
74
74
|
className: "flex items-center gap-1",
|
|
75
|
-
children: [/* @__PURE__ */
|
|
75
|
+
children: [/* @__PURE__ */ d(u, {
|
|
76
76
|
size: 14,
|
|
77
77
|
className: "text-status-warning-text fill-status-warning-text"
|
|
78
78
|
}), h.averageRating.toFixed(1)]
|
|
79
|
-
}), /* @__PURE__ */
|
|
79
|
+
}), /* @__PURE__ */ f("span", {
|
|
80
80
|
className: "flex items-center gap-1",
|
|
81
81
|
children: [
|
|
82
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ d(c, { size: 14 }),
|
|
83
83
|
h.installCount.toLocaleString(),
|
|
84
84
|
" ",
|
|
85
85
|
w("devportal.installs", "installs")
|
|
86
86
|
]
|
|
87
87
|
})]
|
|
88
88
|
}),
|
|
89
|
-
v && /* @__PURE__ */
|
|
89
|
+
v && /* @__PURE__ */ d("div", {
|
|
90
90
|
className: "mt-4 flex items-center justify-between opacity-0 group-hover:opacity-100 transition-opacity",
|
|
91
|
-
children: /* @__PURE__ */
|
|
91
|
+
children: /* @__PURE__ */ f("button", {
|
|
92
92
|
className: "text-sm text-primary hover:underline flex items-center gap-1",
|
|
93
93
|
onClick: (e) => {
|
|
94
94
|
e.stopPropagation(), T();
|
|
95
95
|
},
|
|
96
|
-
children: [w("devportal.viewDetails", "View Details"), /* @__PURE__ */
|
|
96
|
+
children: [w("devportal.viewDetails", "View Details"), /* @__PURE__ */ d(l, { size: 14 })]
|
|
97
97
|
})
|
|
98
98
|
})
|
|
99
99
|
]
|
|
100
100
|
});
|
|
101
|
-
}, g = ({ app: r, onClick: a, className:
|
|
102
|
-
let { navigate:
|
|
103
|
-
a ? a() :
|
|
101
|
+
}, g = ({ app: r, onClick: a, className: c, selected: l = !1, onToggleSelect: u }) => {
|
|
102
|
+
let { navigate: p, basePath: m } = e(), h = () => {
|
|
103
|
+
a ? a() : p && p(`${m}/apps/${r.id}`);
|
|
104
104
|
};
|
|
105
|
-
return /* @__PURE__ */
|
|
105
|
+
return /* @__PURE__ */ f("div", {
|
|
106
106
|
role: "button",
|
|
107
107
|
tabIndex: 0,
|
|
108
|
-
className: t("flex items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-3 cursor-pointer transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", l && "border-primary bg-action-primary-bg/5",
|
|
108
|
+
className: t("flex items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-3 cursor-pointer transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", l && "border-primary bg-action-primary-bg/5", c),
|
|
109
109
|
onClick: h,
|
|
110
110
|
onKeyDown: (e) => {
|
|
111
111
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), h());
|
|
112
112
|
},
|
|
113
113
|
children: [
|
|
114
|
-
u && /* @__PURE__ */
|
|
114
|
+
u && /* @__PURE__ */ d("div", {
|
|
115
115
|
onClick: (e) => e.stopPropagation(),
|
|
116
|
-
children: /* @__PURE__ */
|
|
116
|
+
children: /* @__PURE__ */ d(o, {
|
|
117
117
|
checked: l,
|
|
118
118
|
onChange: u,
|
|
119
119
|
ariaLabel: `Select application ${r.name}`
|
|
120
120
|
})
|
|
121
121
|
}),
|
|
122
|
-
r.iconUrl ? /* @__PURE__ */
|
|
122
|
+
r.iconUrl ? /* @__PURE__ */ d("img", {
|
|
123
123
|
src: r.iconUrl,
|
|
124
124
|
alt: r.name,
|
|
125
125
|
className: "h-10 w-10 rounded-lg object-cover"
|
|
126
|
-
}) : /* @__PURE__ */
|
|
126
|
+
}) : /* @__PURE__ */ d("div", {
|
|
127
127
|
className: "flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary",
|
|
128
|
-
children: /* @__PURE__ */
|
|
128
|
+
children: /* @__PURE__ */ d(s, { size: 20 })
|
|
129
129
|
}),
|
|
130
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ f("div", {
|
|
131
131
|
className: "flex-1 min-w-0",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
132
|
+
children: [/* @__PURE__ */ d("p", {
|
|
133
133
|
className: "font-medium truncate",
|
|
134
134
|
children: r.name
|
|
135
|
-
}), /* @__PURE__ */
|
|
135
|
+
}), /* @__PURE__ */ d("p", {
|
|
136
136
|
className: "text-sm text-text-secondary truncate",
|
|
137
137
|
children: r.shortDescription || n[r.appType]
|
|
138
138
|
})]
|
|
139
139
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ d(i, { status: r.status })
|
|
141
141
|
]
|
|
142
142
|
});
|
|
143
143
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/devportal/components/ConfirmDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAK1E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/devportal/components/ConfirmDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAK1E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA4KhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAwCA,CAAC"}
|