@burdenoff/microfe-devportal 2026.716.2 → 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/hooks/usePackageUpload.d.ts.map +1 -1
- package/dist/devportal/hooks/usePackageUpload.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/CreateApplicationPage.d.ts.map +1 -1
- package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
- package/dist/devportal/pages/CreateOAuthClientPage.js +1 -1
- package/dist/devportal/pages/CreateOrganizationPage.js +1 -1
- package/dist/devportal/pages/CreatePhysicalItemPage.d.ts.map +1 -1
- package/dist/devportal/pages/CreatePhysicalItemPage.js +147 -116
- package/dist/devportal/pages/CreatePhysicalItemPage.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.d.ts.map +1 -1
- package/dist/devportal/pages/EditApplicationPage.js +4 -4
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- 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.d.ts.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/SellerDashboardPage.d.ts.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
- package/dist/devportal/pages/SellerItemsPage.d.ts.map +1 -1
- package/dist/devportal/pages/SellerItemsPage.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/dist/devportal/types/index.d.ts.map +1 -1
- package/dist/devportal/types/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,20 @@ import { FC, ReactNode } from 'react';
|
|
|
2
2
|
import { DevportalPermission } from '../constants/permissions';
|
|
3
3
|
|
|
4
4
|
interface PermissionGuardProps {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Required RBAC permission. Optional when `authOnly` is set — self-scoped
|
|
7
|
+
* developer surfaces gate on authentication only (see `authOnly`).
|
|
8
|
+
*/
|
|
9
|
+
permission?: DevportalPermission;
|
|
10
|
+
/**
|
|
11
|
+
* Self-scoped mode. The corresponding backend fields are gated with
|
|
12
|
+
* `@rbac(scopeType: "self")` — an authentication gate whose resolvers filter
|
|
13
|
+
* strictly to the caller's own resources. Such fields carry no RBAC
|
|
14
|
+
* permission in `myPermissions`, so a permission check would wrongly deny
|
|
15
|
+
* every normal member. In this mode we render for any authenticated user and
|
|
16
|
+
* let the backend self-enforce per resource.
|
|
17
|
+
*/
|
|
18
|
+
authOnly?: boolean;
|
|
6
19
|
children: ReactNode;
|
|
7
20
|
}
|
|
8
21
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PermissionGuard.d.ts","sourceRoot":"","sources":["../../../src/devportal/components/PermissionGuard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,UAAU,oBAAoB;IAC5B,UAAU,EAAE,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"PermissionGuard.d.ts","sourceRoot":"","sources":["../../../src/devportal/components/PermissionGuard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,UAAU,oBAAoB;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CA6FpD,CAAC"}
|
|
@@ -5,30 +5,33 @@ import { usePermissions as r } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
|
5
5
|
import { Fragment as i, jsx as a } from "react/jsx-runtime";
|
|
6
6
|
import { useAuth as o } from "@burdenoff/fe-libs/shared/providers/shell/AuthProvider";
|
|
7
7
|
//#region src/devportal/components/PermissionGuard.tsx
|
|
8
|
-
var s = ({ permission: s,
|
|
9
|
-
let
|
|
8
|
+
var s = ({ permission: s, authOnly: c = !1, children: l }) => {
|
|
9
|
+
let u = null, d = !1, f = !1, p = !1;
|
|
10
10
|
try {
|
|
11
11
|
let e = r();
|
|
12
|
-
|
|
12
|
+
u = e.hasPermission, d = e.isLoading, f = e.permissions?.permissions?.some((e) => e.resourceType === "rbac" && e.level === "ADMIN") ?? !1;
|
|
13
13
|
} catch {
|
|
14
|
-
|
|
14
|
+
u = null, d = !1, f = !1;
|
|
15
15
|
}
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
p = o().isAuthenticated;
|
|
18
18
|
} catch {
|
|
19
|
-
|
|
19
|
+
p = !1;
|
|
20
20
|
}
|
|
21
|
-
let
|
|
22
|
-
let n =
|
|
21
|
+
let m = typeof window < "u" && (window.location.hostname === "localhost" || window.location.hostname.endsWith(".local.burdenoff.com")) && p, { t: h } = n(), g = (e, t) => {
|
|
22
|
+
let n = h(e);
|
|
23
23
|
return n === e ? t : n;
|
|
24
24
|
};
|
|
25
|
-
return
|
|
25
|
+
return d ? /* @__PURE__ */ a("div", {
|
|
26
26
|
className: "flex min-h-screen items-center justify-center bg-bg-canvas",
|
|
27
27
|
children: /* @__PURE__ */ a(e, {})
|
|
28
|
-
}) :
|
|
29
|
-
title:
|
|
30
|
-
description:
|
|
31
|
-
}) : /* @__PURE__ */ a(i, { children:
|
|
28
|
+
}) : c ? u !== null && !p && !m ? /* @__PURE__ */ a(t, {
|
|
29
|
+
title: g("devportal.accessDenied", "Access Denied"),
|
|
30
|
+
description: g("devportal.noPermissionView", "You don't have permission to view this page.")
|
|
31
|
+
}) : /* @__PURE__ */ a(i, { children: l }) : s && u && !u(s) && !f && !m ? /* @__PURE__ */ a(t, {
|
|
32
|
+
title: g("devportal.accessDenied", "Access Denied"),
|
|
33
|
+
description: g("devportal.noPermissionView", "You don't have permission to view this page.")
|
|
34
|
+
}) : /* @__PURE__ */ a(i, { children: l });
|
|
32
35
|
};
|
|
33
36
|
//#endregion
|
|
34
37
|
export { s as PermissionGuard };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PermissionGuard.js","names":[],"sources":["../../../src/devportal/components/PermissionGuard.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { usePermissions } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuth } from \"@burdenoff/fe-libs/shared/providers/shell/AuthProvider\";\nimport { AccessDenied } from \"@burdenoff/fe-libs/shared/components\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLoadingState } from \"./LoadingState\";\nimport type { DevportalPermission } from \"../constants/permissions\";\n\ninterface PermissionGuardProps {\n permission
|
|
1
|
+
{"version":3,"file":"PermissionGuard.js","names":[],"sources":["../../../src/devportal/components/PermissionGuard.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { usePermissions } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuth } from \"@burdenoff/fe-libs/shared/providers/shell/AuthProvider\";\nimport { AccessDenied } from \"@burdenoff/fe-libs/shared/components\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLoadingState } from \"./LoadingState\";\nimport type { DevportalPermission } from \"../constants/permissions\";\n\ninterface PermissionGuardProps {\n /**\n * Required RBAC permission. Optional when `authOnly` is set — self-scoped\n * developer surfaces gate on authentication only (see `authOnly`).\n */\n permission?: DevportalPermission;\n /**\n * Self-scoped mode. The corresponding backend fields are gated with\n * `@rbac(scopeType: \"self\")` — an authentication gate whose resolvers filter\n * strictly to the caller's own resources. Such fields carry no RBAC\n * permission in `myPermissions`, so a permission check would wrongly deny\n * every normal member. In this mode we render for any authenticated user and\n * let the backend self-enforce per resource.\n */\n authOnly?: boolean;\n children: ReactNode;\n}\n\n/**\n * Wraps page content with a permission check.\n * Shows a loading state while permissions resolve, then either\n * renders children (if permitted) or an AccessDenied screen.\n */\nexport const PermissionGuard: FC<PermissionGuardProps> = ({\n permission,\n authOnly = false,\n children,\n}) => {\n let hasPermission: ((permission: DevportalPermission) => boolean) | null =\n null;\n let isLoading = false;\n let isRbacAdmin = false;\n let isAuthenticated = false;\n\n try {\n const permissions = usePermissions();\n hasPermission = permissions.hasPermission as (\n permission: DevportalPermission,\n ) => boolean;\n isLoading = permissions.isLoading;\n isRbacAdmin =\n permissions.permissions?.permissions?.some(\n (entry) => entry.resourceType === \"rbac\" && entry.level === \"ADMIN\",\n ) ?? false;\n } catch {\n // Standalone/dev mode intentionally allows rendering without shell RBAC context.\n hasPermission = null;\n isLoading = false;\n isRbacAdmin = false;\n }\n\n try {\n const auth = useAuth();\n isAuthenticated = auth.isAuthenticated;\n } catch {\n isAuthenticated = false;\n }\n\n const isLocalShellDev =\n typeof window !== \"undefined\" &&\n (window.location.hostname === \"localhost\" ||\n window.location.hostname.endsWith(\".local.burdenoff.com\"));\n\n const allowLocalShellBypass = isLocalShellDev && isAuthenticated;\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 if (isLoading) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-bg-canvas\">\n <PageLoadingState />\n </div>\n );\n }\n\n // Self-scoped surface: gate on authentication only. The backend\n // (@rbac scopeType: \"self\") filters to the caller's own resources, so we\n // must not require an RBAC permission the member legitimately lacks.\n if (authOnly) {\n // When the shell RBAC context is unavailable (standalone/dev), render.\n if (hasPermission !== null && !isAuthenticated && !allowLocalShellBypass) {\n return (\n <AccessDenied\n title={tr(\"devportal.accessDenied\", \"Access Denied\")}\n description={tr(\n \"devportal.noPermissionView\",\n \"You don't have permission to view this page.\",\n )}\n />\n );\n }\n return <>{children}</>;\n }\n\n if (\n permission &&\n hasPermission &&\n !hasPermission(permission) &&\n !isRbacAdmin &&\n !allowLocalShellBypass\n ) {\n return (\n <AccessDenied\n title={tr(\"devportal.accessDenied\", \"Access Denied\")}\n description={tr(\n \"devportal.noPermissionView\",\n \"You don't have permission to view this page.\",\n )}\n />\n );\n }\n\n return <>{children}</>;\n};\n"],"mappings":";;;;;;;AA+BA,IAAa,KAA6C,EACxD,eACA,cAAW,IACX,kBACI;CACJ,IAAI,IACF,MACE,IAAY,IACZ,IAAc,IACd,IAAkB;AAEtB,KAAI;EACF,IAAM,IAAc,GAAgB;AAKpC,EAJA,IAAgB,EAAY,eAG5B,IAAY,EAAY,WACxB,IACE,EAAY,aAAa,aAAa,MACnC,MAAU,EAAM,iBAAiB,UAAU,EAAM,UAAU,QAC7D,IAAI;SACD;AAIN,EAFA,IAAgB,MAChB,IAAY,IACZ,IAAc;;AAGhB,KAAI;AAEF,MADa,GAAS,CACC;SACjB;AACN,MAAkB;;CAQpB,IAAM,IAJJ,OAAO,SAAW,QACjB,OAAO,SAAS,aAAa,eAC5B,OAAO,SAAS,SAAS,SAAS,uBAAuB,KAEZ,GAC3C,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;;AAgDpC,QA7CI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAoB,CAAA;EAChB,CAAA,GAON,IAEE,MAAkB,QAAQ,CAAC,KAAmB,CAAC,IAE/C,kBAAC,GAAD;EACE,OAAO,EAAG,0BAA0B,gBAAgB;EACpD,aAAa,EACX,8BACA,+CACD;EACD,CAAA,GAGC,kBAAA,GAAA,EAAG,aAAY,CAAA,GAItB,KACA,KACA,CAAC,EAAc,EAAW,IAC1B,CAAC,KACD,CAAC,IAGC,kBAAC,GAAD;EACE,OAAO,EAAG,0BAA0B,gBAAgB;EACpD,aAAa,EACX,8BACA,+CACD;EACD,CAAA,GAIC,kBAAA,GAAA,EAAG,aAAY,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePackageUpload.d.ts","sourceRoot":"","sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"usePackageUpload.d.ts","sourceRoot":"","sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AA6JD,wBAAgB,gBAAgB,CAC9B,oBAAoB,EAAE,MAAM,GAAG,SAAS,EACxC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,iBAAiB,EAAE,CAAC,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EAC7D,UAAU,SAAwB;eArKvB,OAAO;cACR,MAAM;WACT,MAAM,GAAG,IAAI;mBA4KL,IAAI,KAAG,OAAO,CAAC,mBAAmB,CAAC;EAoDnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePackageUpload.js","names":[],"sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"sourcesContent":["/**\n * usePackageUpload — uploads a zip package to wspace-files-svc and returns a\n * stable downloadUrl to store as ApplicationVersion.packageUrl.\n *\n * Flow (mirrors uploadBlobToFiles in @burdenoff/fe-libs/storage):\n * 1. ensureFolderByPath(\"/DevPortal/Packages\") → folderId\n * 2. initiateUpload → { sessionId, presignedUrl }\n * 3. PUT blob to presignedUrl (progress tracked via XHR)\n * 4. completeUpload → { file.downloadUrl }\n *\n * Uses raw fetch for GraphQL mutations so we can target the workspace gateway\n * without a second ApolloProvider.\n */\nimport { useCallback, useState } from \"react\";\n\nexport interface PackageUploadResult {\n fileId: string;\n downloadUrl: string;\n}\n\nexport interface PackageUploadState {\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\ntype GqlFetcher = (\n query: string,\n variables: Record<string, unknown>,\n) => Promise<Record<string, unknown>>;\n\nfunction makeFetcher(\n workspacesGatewayUrl: string,\n authToken: string | undefined,\n workspaceId: string | undefined,\n workspaceToken: string | undefined,\n): GqlFetcher {\n return async (query, variables) => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (authToken) headers[\"Authorization\"] = `Bearer ${authToken}`;\n if (workspaceToken)\n headers[\"X-Workspace-Authorization\"] = `Bearer ${workspaceToken}`;\n if (workspaceId) headers[\"x-workspace-id\"] = workspaceId;\n\n const endpoint = workspacesGatewayUrl.endsWith(\"/graphql\")\n ? workspacesGatewayUrl\n : `${workspacesGatewayUrl}/workspaces/graphql`;\n\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n credentials: \"include\",\n body: JSON.stringify({ query, variables }),\n });\n if (!res.ok) {\n throw new Error(\n `GraphQL request failed: ${res.status} ${res.statusText}`,\n );\n }\n const json = (await res.json()) as {\n data?: Record<string, unknown>;\n errors?: Array<{ message: string }>;\n };\n if (json.errors?.length) {\n throw new Error(json.errors.map((e) => e.message).join(\"; \"));\n }\n return json.data ?? {};\n };\n}\n\nasync function ensureFolder(gql: GqlFetcher, path: string): Promise<string> {\n const data = await gql(\n `mutation DevPortal_EnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) { id }\n }`,\n { path },\n );\n const id = (data.ensureFolderByPath as { id?: string } | undefined)?.id;\n if (!id) throw new Error(\"ensureFolderByPath returned no id\");\n return id;\n}\n\nasync function initiateUpload(\n gql: GqlFetcher,\n file: File,\n folderId: string,\n): Promise<{ sessionId: string; uploadUrl: string }> {\n const ext = file.name.includes(\".\")\n ? file.name.substring(file.name.lastIndexOf(\".\") + 1)\n : \"zip\";\n const data = await gql(\n `mutation DevPortal_InitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session { id }\n }\n }`,\n {\n input: {\n fileName: file.name,\n fileSize: String(file.size),\n mimeType: file.type || \"application/zip\",\n extension: ext,\n folderId,\n visibility: \"PUBLIC\",\n },\n },\n );\n const result = data.initiateUpload as\n { uploadUrl?: string; session?: { id?: string } } | undefined;\n const sessionId = result?.session?.id;\n const uploadUrl = result?.uploadUrl;\n if (!sessionId || !uploadUrl) {\n throw new Error(\"initiateUpload did not return sessionId or uploadUrl\");\n }\n return { sessionId, uploadUrl };\n}\n\nasync function putToPresignedUrl(\n file: File,\n uploadUrl: string,\n onProgress: (pct: number) => void,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", (evt) => {\n if (evt.lengthComputable) {\n onProgress(10 + Math.round((evt.loaded / evt.total) * 80));\n }\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`S3 PUT failed: ${xhr.status}`));\n }\n });\n xhr.addEventListener(\"error\", () =>\n reject(new Error(\"S3 PUT network error\")),\n );\n xhr.addEventListener(\"abort\", () => reject(new Error(\"S3 PUT aborted\")));\n xhr.open(\"PUT\", uploadUrl);\n xhr.setRequestHeader(\"Content-Type\", file.type || \"application/zip\");\n xhr.send(file);\n });\n}\n\nasync function completeUpload(\n gql: GqlFetcher,\n sessionId: string,\n folderId: string,\n fileSize: number,\n): Promise<PackageUploadResult> {\n const data = await gql(\n `mutation DevPortal_CompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n file { id downloadUrl }\n }\n }`,\n {\n input: {\n sessionId,\n folderId,\n fileSize: String(fileSize),\n },\n },\n );\n const file = (\n data.completeUpload as\n { file?: { id?: string; downloadUrl?: string } } | undefined\n )?.file;\n if (!file?.id || !file.downloadUrl) {\n throw new Error(\"completeUpload did not return file id or downloadUrl\");\n }\n return { fileId: file.id, downloadUrl: file.downloadUrl };\n}\n\nexport function usePackageUpload(\n workspacesGatewayUrl: string | undefined,\n authToken: string | undefined,\n workspaceId: string | undefined,\n getWorkspaceToken: (() => Promise<string | null>) | undefined,\n folderPath = \"/DevPortal/Packages\",\n) {\n const [state, setState] = useState<PackageUploadState>({\n uploading: false,\n progress: 0,\n error: null,\n });\n\n const upload = useCallback(\n async (file: File): Promise<PackageUploadResult> => {\n if (!workspacesGatewayUrl) {\n throw new Error(\n \"workspacesGatewayUrl is not configured. Pass it as a prop to DevportalRoot.\",\n );\n }\n\n const freshToken = getWorkspaceToken\n ? await getWorkspaceToken()\n : undefined;\n const gql = makeFetcher(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n freshToken ?? undefined,\n );\n\n setState({ uploading: true, progress: 0, error: null });\n try {\n const folderId = await ensureFolder(gql, folderPath);\n setState((s) => ({ ...s, progress: 5 }));\n\n const { sessionId, uploadUrl } = await initiateUpload(\n gql,\n file,\n folderId,\n );\n setState((s) => ({ ...s, progress: 10 }));\n\n await putToPresignedUrl(file, uploadUrl, (pct) =>\n setState((s) => ({ ...s, progress: pct })),\n );\n setState((s) => ({ ...s, progress: 90 }));\n\n const result = await completeUpload(\n gql,\n sessionId,\n folderId,\n file.size,\n );\n setState({ uploading: false, progress: 100, error: null });\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState({ uploading: false, progress: 0, error: message });\n throw err;\n }\n },\n [workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken],\n );\n\n return { upload, ...state };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePackageUpload.js","names":[],"sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"sourcesContent":["/**\n * usePackageUpload — uploads a zip package to wspace-files-svc and returns a\n * stable downloadUrl to store as ApplicationVersion.packageUrl.\n *\n * Flow (mirrors uploadBlobToFiles in @burdenoff/fe-libs/storage):\n * 1. ensureFolderByPath(\"/DevPortal/Packages\") → folderId\n * 2. initiateUpload → { sessionId, presignedUrl }\n * 3. PUT blob to presignedUrl (progress tracked via XHR)\n * 4. completeUpload → { file.downloadUrl }\n *\n * Uses raw fetch for GraphQL mutations so we can target the workspace gateway\n * without a second ApolloProvider.\n */\nimport { useCallback, useState } from \"react\";\n\nexport interface PackageUploadResult {\n fileId: string;\n downloadUrl: string;\n}\n\nexport interface PackageUploadState {\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\ntype GqlFetcher = (\n query: string,\n variables: Record<string, unknown>,\n) => Promise<Record<string, unknown>>;\n\nfunction makeFetcher(\n workspacesGatewayUrl: string,\n authToken: string | undefined,\n workspaceId: string | undefined,\n workspaceToken: string | undefined,\n): GqlFetcher {\n return async (query, variables) => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (authToken) headers[\"Authorization\"] = `Bearer ${authToken}`;\n if (workspaceToken)\n headers[\"X-Workspace-Authorization\"] = `Bearer ${workspaceToken}`;\n if (workspaceId) headers[\"x-workspace-id\"] = workspaceId;\n\n const endpoint = workspacesGatewayUrl.endsWith(\"/graphql\")\n ? workspacesGatewayUrl\n : `${workspacesGatewayUrl}/workspaces/graphql`;\n\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n credentials: \"include\",\n body: JSON.stringify({ query, variables }),\n });\n if (!res.ok) {\n throw new Error(\n `GraphQL request failed: ${res.status} ${res.statusText}`,\n );\n }\n const json = (await res.json()) as {\n data?: Record<string, unknown>;\n errors?: Array<{ message: string }>;\n };\n if (json.errors?.length) {\n throw new Error(json.errors.map((e) => e.message).join(\"; \"));\n }\n return json.data ?? {};\n };\n}\n\nasync function ensureFolder(gql: GqlFetcher, path: string): Promise<string> {\n const data = await gql(\n `mutation DevPortal_EnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) { id }\n }`,\n { path },\n );\n const id = (data.ensureFolderByPath as { id?: string } | undefined)?.id;\n if (!id) throw new Error(\"ensureFolderByPath returned no id\");\n return id;\n}\n\nasync function initiateUpload(\n gql: GqlFetcher,\n file: File,\n folderId: string,\n): Promise<{ sessionId: string; uploadUrl: string }> {\n const ext = file.name.includes(\".\")\n ? file.name.substring(file.name.lastIndexOf(\".\") + 1)\n : \"zip\";\n const data = await gql(\n `mutation DevPortal_InitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session { id }\n }\n }`,\n {\n input: {\n fileName: file.name,\n fileSize: String(file.size),\n mimeType: file.type || \"application/zip\",\n extension: ext,\n folderId,\n visibility: \"PUBLIC\",\n },\n },\n );\n const result = data.initiateUpload as\n | { uploadUrl?: string; session?: { id?: string } }\n | undefined;\n const sessionId = result?.session?.id;\n const uploadUrl = result?.uploadUrl;\n if (!sessionId || !uploadUrl) {\n throw new Error(\"initiateUpload did not return sessionId or uploadUrl\");\n }\n return { sessionId, uploadUrl };\n}\n\nasync function putToPresignedUrl(\n file: File,\n uploadUrl: string,\n onProgress: (pct: number) => void,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", (evt) => {\n if (evt.lengthComputable) {\n onProgress(10 + Math.round((evt.loaded / evt.total) * 80));\n }\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`S3 PUT failed: ${xhr.status}`));\n }\n });\n xhr.addEventListener(\"error\", () =>\n reject(new Error(\"S3 PUT network error\")),\n );\n xhr.addEventListener(\"abort\", () => reject(new Error(\"S3 PUT aborted\")));\n xhr.open(\"PUT\", uploadUrl);\n xhr.setRequestHeader(\"Content-Type\", file.type || \"application/zip\");\n xhr.send(file);\n });\n}\n\nasync function completeUpload(\n gql: GqlFetcher,\n sessionId: string,\n folderId: string,\n fileSize: number,\n): Promise<PackageUploadResult> {\n const data = await gql(\n `mutation DevPortal_CompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n file { id downloadUrl }\n }\n }`,\n {\n input: {\n sessionId,\n folderId,\n fileSize: String(fileSize),\n },\n },\n );\n const file = (\n data.completeUpload as\n | { file?: { id?: string; downloadUrl?: string } }\n | undefined\n )?.file;\n if (!file?.id || !file.downloadUrl) {\n throw new Error(\"completeUpload did not return file id or downloadUrl\");\n }\n return { fileId: file.id, downloadUrl: file.downloadUrl };\n}\n\nexport function usePackageUpload(\n workspacesGatewayUrl: string | undefined,\n authToken: string | undefined,\n workspaceId: string | undefined,\n getWorkspaceToken: (() => Promise<string | null>) | undefined,\n folderPath = \"/DevPortal/Packages\",\n) {\n const [state, setState] = useState<PackageUploadState>({\n uploading: false,\n progress: 0,\n error: null,\n });\n\n const upload = useCallback(\n async (file: File): Promise<PackageUploadResult> => {\n if (!workspacesGatewayUrl) {\n throw new Error(\n \"workspacesGatewayUrl is not configured. Pass it as a prop to DevportalRoot.\",\n );\n }\n\n const freshToken = getWorkspaceToken\n ? await getWorkspaceToken()\n : undefined;\n const gql = makeFetcher(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n freshToken ?? undefined,\n );\n\n setState({ uploading: true, progress: 0, error: null });\n try {\n const folderId = await ensureFolder(gql, folderPath);\n setState((s) => ({ ...s, progress: 5 }));\n\n const { sessionId, uploadUrl } = await initiateUpload(\n gql,\n file,\n folderId,\n );\n setState((s) => ({ ...s, progress: 10 }));\n\n await putToPresignedUrl(file, uploadUrl, (pct) =>\n setState((s) => ({ ...s, progress: pct })),\n );\n setState((s) => ({ ...s, progress: 90 }));\n\n const result = await completeUpload(\n gql,\n sessionId,\n folderId,\n file.size,\n );\n setState({ uploading: false, progress: 100, error: null });\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState({ uploading: false, progress: 0, error: message });\n throw err;\n }\n },\n [workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken],\n );\n\n return { upload, ...state };\n}\n"],"mappings":"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"}
|
|
@@ -5,9 +5,9 @@ import { getErrorMessage as l } from "../hooks/useGraphQL.js";
|
|
|
5
5
|
import { PageLayout as u, PageSection as d } from "../components/PageLayout.js";
|
|
6
6
|
import { PermissionGuard as f } from "../components/PermissionGuard.js";
|
|
7
7
|
import "../components/index.js";
|
|
8
|
-
import {
|
|
9
|
-
import { useDevportalPermission as m } from "../hooks/usePermission.js";
|
|
8
|
+
import { useDevportalPermission as p } from "../hooks/usePermission.js";
|
|
10
9
|
import "../hooks/index.js";
|
|
10
|
+
import { DEVPORTAL_PERMISSIONS as m } from "../constants/permissions.js";
|
|
11
11
|
import { useState as h } from "react";
|
|
12
12
|
import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
13
13
|
import { AlertCircle as _, CheckCircle as v, ChevronDown as y, ChevronUp as b, Clock as x, Download as S, Eye as C, FileJson as w, GitBranch as T, Loader2 as E, Package as D, Search as O, XCircle as k } from "lucide-react";
|
|
@@ -66,7 +66,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
66
66
|
let { navigate: s, basePath: c } = e(), { t: l } = g(), u = (e, t) => {
|
|
67
67
|
let n = l(e);
|
|
68
68
|
return n === e ? t : n;
|
|
69
|
-
}, [d, f] = h(!1), [_, x] = h(""), w = m
|
|
69
|
+
}, [d, f] = h(!1), [_, x] = h(""), w = p(m.APP_APPROVE), D = p(m.APP_REJECT), { data: O } = i({
|
|
70
70
|
variables: { id: t.id },
|
|
71
71
|
skip: !d,
|
|
72
72
|
fetchPolicy: "cache-first"
|
|
@@ -380,7 +380,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
380
380
|
})]
|
|
381
381
|
});
|
|
382
382
|
}, L = ({ version: e, appId: t, appType: n, onApprove: r, onReject: i, processing: a, tr: o }) => {
|
|
383
|
-
let [s, c] = h(""), l = m
|
|
383
|
+
let [s, c] = h(""), l = p(m.APP_APPROVE), u = p(m.APP_REJECT);
|
|
384
384
|
return /* @__PURE__ */ j("div", {
|
|
385
385
|
className: "rounded-md border bg-bg-surface p-4 space-y-3",
|
|
386
386
|
children: [
|
|
@@ -487,7 +487,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
487
487
|
let { t: e } = g(), i = (t, n) => {
|
|
488
488
|
let r = e(t);
|
|
489
489
|
return r === t ? n : r;
|
|
490
|
-
}, [
|
|
490
|
+
}, [p, y] = h(""), [b, S] = h(/* @__PURE__ */ new Set()), [C, w] = h(/* @__PURE__ */ new Set()), [D, k] = h(null), [M, N] = h(null), P = (e) => S((t) => new Set(t).add(e)), L = (e) => S((t) => {
|
|
491
491
|
let n = new Set(t);
|
|
492
492
|
return n.delete(e), n;
|
|
493
493
|
}), R = (e) => w((t) => new Set(t).add(e)), z = (e) => w((t) => {
|
|
@@ -502,7 +502,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
502
502
|
}), { data: W, refetch: G } = o({
|
|
503
503
|
variables: { limit: 100 },
|
|
504
504
|
fetchPolicy: "cache-and-network"
|
|
505
|
-
}), [K] = n(), [q] = s(), [J] = r(), [Y] = c(), X = B?.applications?.edges?.map((e) => e.node) ?? [], Z = W?.applicationsWithPendingVersions?.edges?.map((e) => e.node) ?? [], Q = new Set(Z.map((e) => e.id)), $ =
|
|
505
|
+
}), [K] = n(), [q] = s(), [J] = r(), [Y] = c(), X = B?.applications?.edges?.map((e) => e.node) ?? [], Z = W?.applicationsWithPendingVersions?.edges?.map((e) => e.node) ?? [], Q = new Set(Z.map((e) => e.id)), $ = p ? X.filter((e) => e.name.toLowerCase().includes(p.toLowerCase()) || (e.shortDescription ?? "").toLowerCase().includes(p.toLowerCase())) : X, ee = async (e, t) => {
|
|
506
506
|
P(e), k(null), N(null);
|
|
507
507
|
try {
|
|
508
508
|
let n = await K({ variables: {
|
|
@@ -589,7 +589,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
589
589
|
]
|
|
590
590
|
})
|
|
591
591
|
}) : /* @__PURE__ */ A(f, {
|
|
592
|
-
permission:
|
|
592
|
+
permission: m.REVIEW_MANAGE,
|
|
593
593
|
children: /* @__PURE__ */ j(u, {
|
|
594
594
|
title: i("devportal.appReviewQueue", "App Review Queue"),
|
|
595
595
|
description: i("devportal.appReviewQueueFullDescription", "Review submitted applications for approval or rejection"),
|
|
@@ -658,7 +658,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
658
658
|
}), /* @__PURE__ */ A("input", {
|
|
659
659
|
type: "text",
|
|
660
660
|
placeholder: i("devportal.searchSubmittedApps", "Search submitted apps..."),
|
|
661
|
-
value:
|
|
661
|
+
value: p,
|
|
662
662
|
onChange: (e) => y(e.target.value),
|
|
663
663
|
className: "w-full rounded-md border bg-bg-surface pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
664
664
|
})]
|
|
@@ -669,7 +669,7 @@ var M = ({ manifest: e, tr: t }) => {
|
|
|
669
669
|
illustration: "empty-data",
|
|
670
670
|
icon: /* @__PURE__ */ A(v, { size: 32 }),
|
|
671
671
|
title: i("devportal.noAppsPendingReview", "No apps pending review"),
|
|
672
|
-
description:
|
|
672
|
+
description: p ? i("devportal.noAppsMatchSearch", "No apps match your search") : i("devportal.allApplicationsReviewed", "All submitted applications have been reviewed")
|
|
673
673
|
}) : /* @__PURE__ */ A("div", {
|
|
674
674
|
className: "space-y-3",
|
|
675
675
|
children: $.map((e) => /* @__PURE__ */ A(F, {
|