@burdenoff/microfe-devportal 2026.1109.1 → 2026.1109.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/pages/ApplicationVersionsPage.js +229 -217
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/NodeLifecyclePage.js +2 -0
- package/dist/devportal/pages/NodeLifecyclePage.js.map +1 -1
- package/dist/generated/global-operations.d.ts +21 -0
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.d.ts +24 -2
- package/dist/generated/global-types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeLifecyclePage.js","names":["_Fragment","LIFECYCLE_POLL_INTERVAL_MS","STEP_LABELS","STEP_REASONS","CHECK_META","Package","FileCode2","ShieldCheck","Server","FlaskConical","CHECK_BADGE","BLOCKER_COPY","stepReason","tr","step","StepIndicator","base","cn","Check","XCircle","Loader2","index","Stepper","lifecycle","key","fallback","tone","checkDetail","check","passed","total","ChecksPanel","showLogs","setShowLogs","useState","smoke","operations","finishedAt","meta","badge","detail","issue","value","jsx","ChevronUp","ChevronDown","op","CheckCircle2","MinusCircle","ManifestPreview","copied","setCopied","text","useMemo","manifest","lines","Copy","line","NodeLifecyclePage","useTr","useParams","useDevportal","canPublish","useDevportalPermission","DEVPORTAL_PERMISSIONS","canUpdate","useGetApplicationQuery","appId","app","data","versions","edge","version","v","versionId","appVisibility","visibility","visibilityForApp","deriveNodeLifecycle","busy","startPolling","stopPolling","otherVersionPending","updateVersion","useUpdateApplicationVersionMutation","submitForReview","submitting","usePublishApplicationVersionMutation","publishToOrganization","publishingPrivately","usePublishApplicationVersionToOrganizationMutation","uploadPackage","uploadError","usePackageUpload","workspacesGatewayUrl","authToken","workspaceId","getWorkspaceToken","zipInputRef","useRef","actionError","setActionError","actionSuccess","setActionSuccess","copiedId","setCopiedId","replacingPackage","setReplacingPackage","go","useCallback","navigate","basePath","path","handlePackageSelected","file","event","uploaded","result","err","storeNeedsAppSubmission","blocker","deployBlocker","handleDeploy","copyVersionId","versionsPath","loading","LoadingState","error","PageLayout","EmptyState","status","editable","deploying","deployDisabled","blockerKey","blockerFallback","deployLabel","AlertTriangle","Upload","uploading","progress","Fragment","Lock","Globe","icon","label","selected","BookOpen","Building2","Rocket"],"sources":["../../../src/devportal/pages/NodeLifecyclePage.tsx"],"sourcesContent":["/**\n * NodeLifecyclePage — \"Publish a custom node\" (BOFF-4076).\n *\n * One page that walks a custom-node version through its whole lifecycle:\n * upload ZIP → validate manifest → run tests → approval → deploy. It is a view\n * over the ApplicationVersion that global-devportal-svc already maintains (see\n * utils/nodeLifecycle.ts), plus the three developer actions the lifecycle\n * needs: upload or replace the package, publish a workspace-private node to\n * the developer's organization, and submit a store node for platform review.\n *\n * The page polls while the platform is working (validating, building,\n * testing, reviewing) so each stage flips as soon as the service records it.\n */\nimport type { FC, ReactNode } from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useParams } from \"react-router\";\nimport {\n AlertTriangle,\n BookOpen,\n Building2,\n Check,\n CheckCircle2,\n ChevronDown,\n ChevronUp,\n Copy,\n FileCode2,\n FlaskConical,\n Globe,\n Loader2,\n Lock,\n MinusCircle,\n Package,\n Rocket,\n Server,\n ShieldCheck,\n Upload,\n XCircle,\n} from \"lucide-react\";\n\nimport { PageLayout } from \"../components/PageLayout\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { cn } from \"../utils/cn\";\nimport { useTr } from \"../utils/i18n\";\nimport {\n useGetApplicationQuery,\n useUpdateApplicationVersionMutation,\n usePublishApplicationVersionMutation,\n usePublishApplicationVersionToOrganizationMutation,\n type ApplicationVersionFieldsFragment,\n} from \"../hooks\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { usePackageUpload } from \"../hooks/usePackageUpload\";\nimport {\n deployBlocker,\n deriveNodeLifecycle,\n visibilityForApp,\n type CheckStatus,\n type DeployBlocker,\n type LifecycleCheck,\n type LifecycleStep,\n type NodeLifecycle,\n} from \"../utils/nodeLifecycle\";\n\n/** Poll every 10 s while the platform is still working on the version. */\nexport const LIFECYCLE_POLL_INTERVAL_MS = 10_000;\n\ntype Tr = ReturnType<typeof useTr>;\n\nconst STEP_LABELS: Record<LifecycleStep[\"id\"], [string, string]> = {\n upload: [\"devportal.nodeLifecycle.step.upload\", \"Upload ZIP\"],\n validate: [\"devportal.nodeLifecycle.step.validate\", \"Validate manifest\"],\n test: [\"devportal.nodeLifecycle.step.test\", \"Run tests\"],\n approval: [\"devportal.nodeLifecycle.step.approval\", \"Approval\"],\n deploy: [\"devportal.nodeLifecycle.step.deploy\", \"Deploy\"],\n};\n\nconst STEP_REASONS: Record<string, string> = {\n uploaded: \"Completed\",\n noPackage: \"Upload the node package\",\n waitingForPackage: \"Pending\",\n passed: \"Completed\",\n failed: \"Failed — see checks\",\n validating: \"In progress\",\n notValidated: \"Upload the package again to validate it\",\n waitingForValidation: \"Pending\",\n building: \"Building sandbox image\",\n buildFailed: \"Build failed\",\n testing: \"Testing operations\",\n testsFailed: \"Tests failed\",\n testsSkipped: \"Completed (tests not run here)\",\n testsPassed: \"Completed\",\n built: \"Completed\",\n organization: \"Approved by your organization\",\n approved: \"Approved\",\n inReview: \"Awaiting platform review\",\n rejected: \"Changes requested\",\n waitingForTests: \"Pending\",\n readyForOrganization: \"Auto-approved when you deploy\",\n readyToSubmit: \"Submit for platform review\",\n deprecated: \"Deprecated\",\n store: \"Live in the Node Store\",\n deployedToOrganization: \"Installable in your organization's workspaces\",\n ready: \"Ready to deploy\",\n waitingForApproval: \"Pending\",\n};\n\nconst CHECK_META: Record<\n LifecycleCheck[\"id\"],\n { icon: ReactNode; key: string; label: string }\n> = {\n structure: {\n icon: <Package size={16} />,\n key: \"devportal.nodeLifecycle.check.structure\",\n label: \"Package structure\",\n },\n manifest: {\n icon: <FileCode2 size={16} />,\n key: \"devportal.nodeLifecycle.check.manifest\",\n label: \"Manifest & operations\",\n },\n security: {\n icon: <ShieldCheck size={16} />,\n key: \"devportal.nodeLifecycle.check.security\",\n label: \"Security scan\",\n },\n build: {\n icon: <Server size={16} />,\n key: \"devportal.nodeLifecycle.check.build\",\n label: \"Sandbox image build\",\n },\n tests: {\n icon: <FlaskConical size={16} />,\n key: \"devportal.nodeLifecycle.check.tests\",\n label: \"Automated operation tests\",\n },\n};\n\nconst CHECK_BADGE: Record<CheckStatus, { label: string; className: string }> = {\n pass: {\n label: \"PASS\",\n className: \"bg-status-success-bg-subtle text-status-success-text\",\n },\n warn: {\n label: \"REVIEW\",\n className: \"bg-status-warning-bg-subtle text-status-warning-text\",\n },\n fail: {\n label: \"FAIL\",\n className: \"bg-status-error-bg-subtle text-status-error-text\",\n },\n running: {\n label: \"RUNNING\",\n className: \"bg-status-info-bg-subtle text-status-info-text\",\n },\n not_run: {\n label: \"NOT RUN\",\n className: \"bg-bg-sunken text-text-secondary\",\n },\n};\n\nconst BLOCKER_COPY: Record<DeployBlocker, [string, string]> = {\n noPermission: [\n \"devportal.nodeLifecycle.blocker.noPermission\",\n \"You do not have permission to publish versions of this node.\",\n ],\n notDraft: [\n \"devportal.nodeLifecycle.blocker.notDraft\",\n \"This version has already been submitted or deployed. Create a new version to ship a change.\",\n ],\n visibilityMismatch: [\n \"devportal.nodeLifecycle.blocker.visibilityMismatch\",\n \"This node's visibility does not allow that. Change it under Edit application.\",\n ],\n noPackage: [\n \"devportal.nodeLifecycle.blocker.noPackage\",\n \"Upload the node package first.\",\n ],\n validationNotPassed: [\n \"devportal.nodeLifecycle.blocker.validationNotPassed\",\n \"The package must pass validation first.\",\n ],\n buildNotReady: [\n \"devportal.nodeLifecycle.blocker.buildNotReady\",\n \"Waiting for the sandbox image to build.\",\n ],\n testsNotPassed: [\n \"devportal.nodeLifecycle.blocker.testsNotPassed\",\n \"The operation tests must finish without failures first.\",\n ],\n noWorkspace: [\n \"devportal.nodeLifecycle.blocker.noWorkspace\",\n \"Open the developer portal from a workspace of your organization to publish privately.\",\n ],\n pendingVersion: [\n \"devportal.nodeLifecycle.blocker.pendingVersion\",\n \"Another version of this node is already in review.\",\n ],\n};\n\nfunction stepReason(tr: Tr, step: LifecycleStep): string {\n return tr(\n `devportal.nodeLifecycle.reason.${step.reason}`,\n STEP_REASONS[step.reason] ?? step.reason,\n );\n}\n\nconst StepIndicator: FC<{ step: LifecycleStep; index: number }> = ({\n step,\n index,\n}) => {\n const base =\n \"flex h-11 w-11 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold\";\n switch (step.status) {\n case \"complete\":\n return (\n <span\n className={cn(\n base,\n \"border-status-success-text bg-status-success-bg-subtle text-status-success-text\",\n )}\n >\n <Check size={20} />\n </span>\n );\n case \"failed\":\n return (\n <span\n className={cn(\n base,\n \"border-status-error-text bg-status-error-bg-subtle text-status-error-text\",\n )}\n >\n <XCircle size={20} />\n </span>\n );\n case \"in_progress\":\n return (\n <span\n className={cn(\n base,\n \"border-action-primary-bg bg-action-primary-bg text-action-primary-text\",\n )}\n >\n <Loader2 size={18} className=\"animate-spin\" />\n </span>\n );\n case \"action\":\n return (\n <span\n className={cn(\n base,\n \"border-action-primary-bg bg-action-primary-bg text-action-primary-text\",\n )}\n >\n {index + 1}\n </span>\n );\n default:\n return (\n <span className={cn(base, \"border-border-seam text-text-secondary\")}>\n {index + 1}\n </span>\n );\n }\n};\n\nconst Stepper: FC<{ lifecycle: NodeLifecycle; tr: Tr }> = ({\n lifecycle,\n tr,\n}) => (\n <ol\n className=\"grid grid-cols-1 gap-4 sm:grid-cols-5\"\n data-testid=\"node-lifecycle-stepper\"\n >\n {lifecycle.steps.map((step, index) => {\n const [key, fallback] = STEP_LABELS[step.id];\n const tone =\n step.status === \"complete\"\n ? \"text-status-success-text\"\n : step.status === \"failed\"\n ? \"text-status-error-text\"\n : step.status === \"in_progress\" || step.status === \"action\"\n ? \"text-status-info-text\"\n : \"text-text-secondary\";\n return (\n <li\n key={step.id}\n className=\"flex items-center gap-3 sm:flex-col sm:text-center\"\n data-step={step.id}\n data-status={step.status}\n aria-current={index === lifecycle.currentIndex ? \"step\" : undefined}\n >\n <StepIndicator step={step} index={index} />\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {index + 1}. {tr(key, fallback)}\n </span>\n <span className={cn(\"text-xs\", tone)}>{stepReason(tr, step)}</span>\n </div>\n </li>\n );\n })}\n </ol>\n);\n\nfunction checkDetail(tr: Tr, check: LifecycleCheck): string | null {\n if (check.id === \"tests\" && check.status === \"pass\" && check.detail) {\n const [passed, total] = check.detail.split(\"/\");\n return tr(\n \"devportal.nodeLifecycle.testsPassing\",\n \"{{passed}} / {{total}} passing\",\n { passed: passed ?? \"0\", total: total ?? \"0\" },\n );\n }\n if (check.detail === \"notValidated\") {\n return tr(\n \"devportal.nodeLifecycle.notValidated\",\n \"Uploaded before validation existed\",\n );\n }\n if (check.detail === \"blockedByValidation\") {\n return tr(\n \"devportal.nodeLifecycle.blockedByValidation\",\n \"Not built: the package failed validation\",\n );\n }\n return check.detail;\n}\n\nconst ChecksPanel: FC<{ lifecycle: NodeLifecycle; tr: Tr }> = ({\n lifecycle,\n tr,\n}) => {\n const [showLogs, setShowLogs] = useState(false);\n const smoke = lifecycle.smoke;\n const operations =\n smoke.kind === \"passed\" ||\n smoke.kind === \"failed\" ||\n smoke.kind === \"skipped\"\n ? smoke.operations\n : [];\n const finishedAt =\n smoke.kind === \"passed\" ||\n smoke.kind === \"failed\" ||\n smoke.kind === \"skipped\"\n ? smoke.finishedAt\n : null;\n\n return (\n <section\n className=\"flex flex-col rounded-card border border-border-seam bg-bg-surface\"\n data-testid=\"node-lifecycle-checks\"\n >\n <h2 className=\"border-b border-border-seam px-5 py-4 text-base font-semibold\">\n {tr(\"devportal.nodeLifecycle.checks\", \"Checks\")}\n </h2>\n <ul className=\"divide-y divide-border-seam\">\n {lifecycle.checks.map((check) => {\n const meta = CHECK_META[check.id];\n const badge = CHECK_BADGE[check.status];\n const detail = checkDetail(tr, check);\n return (\n <li\n key={check.id}\n className=\"px-5 py-3\"\n data-check={check.id}\n data-status={check.status}\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"text-text-secondary\">{meta.icon}</span>\n <span className=\"flex-1 text-sm font-medium\">\n {tr(meta.key, meta.label)}\n {detail && (\n <span className=\"ml-2 text-xs font-normal text-text-secondary\">\n {detail}\n </span>\n )}\n </span>\n <span\n className={cn(\n \"inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-semibold\",\n badge.className,\n )}\n >\n {check.status === \"running\" && (\n <Loader2 size={11} className=\"animate-spin\" />\n )}\n {tr(\n `devportal.nodeLifecycle.badge.${check.status}`,\n badge.label,\n )}\n </span>\n </div>\n {check.issues.length > 0 && (\n <ul className=\"mt-2 space-y-1 pl-7\">\n {check.issues.map((issue, index) => (\n <li\n key={`${issue.code}-${issue.path}-${index}`}\n className=\"text-xs leading-snug\"\n >\n {issue.path && (\n <code className=\"mr-1 rounded bg-bg-sunken px-1 py-0.5 font-mono text-text-primary\">\n {issue.path}\n </code>\n )}\n <span\n className={\n issue.severity === \"error\"\n ? \"text-status-error-text\"\n : \"text-status-warning-text\"\n }\n >\n {issue.message}\n </span>\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n <div className=\"mt-auto border-t border-border-seam px-5 py-3\">\n <div className=\"flex items-center justify-between gap-2 text-xs text-text-secondary\">\n <span>\n {finishedAt\n ? tr(\n \"devportal.nodeLifecycle.testsFinished\",\n \"Tests finished {{time}}\",\n { time: new Date(finishedAt).toLocaleString() },\n )\n : tr(\n \"devportal.nodeLifecycle.testsNotFinished\",\n \"No test run recorded yet\",\n )}\n </span>\n {operations.length > 0 && (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 font-medium text-status-info-text hover:underline\"\n onClick={() => setShowLogs((value) => !value)}\n aria-expanded={showLogs}\n >\n {showLogs\n ? tr(\"devportal.nodeLifecycle.hideTestLogs\", \"Hide test logs\")\n : tr(\"devportal.nodeLifecycle.viewTestLogs\", \"View test logs\")}\n {showLogs ? <ChevronUp size={12} /> : <ChevronDown size={12} />}\n </button>\n )}\n </div>\n {showLogs && (\n <ul\n className=\"mt-3 space-y-1 rounded-md bg-bg-sunken p-3 font-mono text-xs\"\n data-testid=\"node-lifecycle-test-logs\"\n >\n {operations.map((op, index) => (\n <li key={`${op.name}-${index}`} className=\"flex gap-2\">\n {op.status === \"PASS\" ? (\n <CheckCircle2\n size={12}\n className=\"mt-0.5 shrink-0 text-status-success-text\"\n />\n ) : op.status === \"SKIP\" ? (\n <MinusCircle\n size={12}\n className=\"mt-0.5 shrink-0 text-text-secondary\"\n />\n ) : (\n <XCircle\n size={12}\n className=\"mt-0.5 shrink-0 text-status-error-text\"\n />\n )}\n <span className=\"text-text-primary\">{op.name}</span>\n <span className=\"text-text-secondary\">\n {op.status} · {op.durationMs} ms\n </span>\n {(op.error ?? op.detail) && (\n <span className=\"break-all text-text-secondary\">\n {op.error ?? op.detail}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n </section>\n );\n};\n\nconst ManifestPreview: FC<{ manifest: unknown; tr: Tr }> = ({\n manifest,\n tr,\n}) => {\n const [copied, setCopied] = useState(false);\n const text = useMemo(\n () => (manifest ? JSON.stringify(manifest, null, 2) : \"\"),\n [manifest],\n );\n const lines = text ? text.split(\"\\n\") : [];\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n window.setTimeout(() => setCopied(false), 2000);\n } catch {\n setCopied(false);\n }\n };\n\n return (\n <section\n className=\"flex min-w-0 flex-col rounded-card border border-border-seam bg-bg-surface\"\n data-testid=\"node-lifecycle-manifest\"\n >\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam px-5 py-3\">\n <h2 className=\"text-base font-semibold\">\n {tr(\"devportal.nodeLifecycle.manifestPreview\", \"Manifest preview\")}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n (manifest.json)\n </span>\n </h2>\n {text && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-seam px-3 py-1.5 text-xs font-medium hover:bg-accent\"\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n {copied\n ? tr(\"devportal.copied\", \"Copied\")\n : tr(\"devportal.copy\", \"Copy\")}\n </button>\n )}\n </div>\n {lines.length > 0 ? (\n <pre className=\"max-h-[28rem] flex-1 overflow-auto px-0 py-3 font-mono text-xs leading-5\">\n {lines.map((line, index) => (\n <div key={index} className=\"flex\">\n <span className=\"w-10 shrink-0 select-none pr-3 text-right text-text-tertiary\">\n {index + 1}\n </span>\n <span className=\"whitespace-pre text-text-primary\">{line}</span>\n </div>\n ))}\n </pre>\n ) : (\n <p className=\"px-5 py-6 text-sm text-text-secondary\">\n {tr(\n \"devportal.nodeLifecycle.noManifest\",\n \"This version has no manifest yet. Add one from the versions page.\",\n )}\n </p>\n )}\n </section>\n );\n};\n\nexport const NodeLifecyclePage: FC = () => {\n const tr = useTr();\n const { appId, versionId } = useParams<{\n appId: string;\n versionId: string;\n }>();\n const {\n basePath,\n navigate,\n workspaceId,\n workspacesGatewayUrl,\n authToken,\n getWorkspaceToken,\n } = useDevportal();\n const { allowed: canPublish } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_PUBLISH,\n );\n const { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_UPDATE,\n );\n\n const { data, loading, error, startPolling, stopPolling } =\n useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const app = data?.application;\n const versions: ApplicationVersionFieldsFragment[] = useMemo(\n () =>\n app?.versions?.edges?.map(\n (edge: { node: ApplicationVersionFieldsFragment }) => edge.node,\n ) ?? [],\n [app?.versions],\n );\n const version = versions.find((v) => v.id === versionId) ?? null;\n const appVisibility = app?.visibility ?? null;\n const visibility = visibilityForApp(appVisibility);\n\n const lifecycle = useMemo(\n () => (version ? deriveNodeLifecycle(version, visibility) : null),\n [version, visibility],\n );\n\n // Poll only while the platform is working; stop once every stage settles.\n const busy = lifecycle?.busy ?? false;\n useEffect(() => {\n if (!busy) return undefined;\n startPolling(LIFECYCLE_POLL_INTERVAL_MS);\n return () => stopPolling();\n }, [busy, startPolling, stopPolling]);\n\n const otherVersionPending = versions.some(\n (v) => v.id !== versionId && v.status === \"pending_review\",\n );\n\n // Wait for the refetch so the page shows the new package's (pending)\n // validation before the replacement counts as finished.\n const [updateVersion] = useUpdateApplicationVersionMutation({\n refetchQueries: [\"GetApplication\"],\n awaitRefetchQueries: true,\n });\n const [submitForReview, { loading: submitting }] =\n usePublishApplicationVersionMutation({\n refetchQueries: [\"GetApplication\"],\n });\n const [publishToOrganization, { loading: publishingPrivately }] =\n usePublishApplicationVersionToOrganizationMutation({\n refetchQueries: [\"GetApplication\"],\n });\n const {\n upload: uploadPackage,\n uploading,\n progress,\n error: uploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n );\n const zipInputRef = useRef<HTMLInputElement>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [actionSuccess, setActionSuccess] = useState<string | null>(null);\n const [copiedId, setCopiedId] = useState(false);\n // True from the moment a package is picked until the version carries it and\n // has been re-read. Deploy stays disabled meanwhile: the readiness shown is\n // still the old package's, and deploying now would ship the old package.\n const [replacingPackage, setReplacingPackage] = useState(false);\n\n const go = useCallback(\n (path: string) => navigate?.(`${basePath}${path}`),\n [navigate, basePath],\n );\n\n const handlePackageSelected = async (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const file = event.target.files?.[0];\n event.target.value = \"\";\n if (!file || !version) return;\n setActionError(null);\n setActionSuccess(null);\n if (!file.name.toLowerCase().endsWith(\".zip\")) {\n setActionError(\n tr(\n \"devportal.nodeLifecycle.zipOnly\",\n \"Upload the node as a .zip package.\",\n ),\n );\n return;\n }\n setReplacingPackage(true);\n try {\n const uploaded = await uploadPackage(file);\n const result = await updateVersion({\n variables: {\n id: version.id,\n input: {\n packageUrl: uploaded.downloadUrl,\n packageSize: String(file.size),\n },\n },\n });\n if (result.error || !result.data?.updateApplicationVersion) {\n throw (\n result.error ??\n new Error(\n tr(\n \"devportal.nodeLifecycle.uploadFailed\",\n \"Failed to attach the package to this version\",\n ),\n )\n );\n }\n setActionSuccess(\n tr(\n \"devportal.nodeLifecycle.uploaded\",\n \"Package uploaded. Validation and tests start automatically.\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.nodeLifecycle.uploadFailed\",\n \"Failed to attach the package to this version\",\n ),\n );\n } finally {\n setReplacingPackage(false);\n }\n };\n\n const storeNeedsAppSubmission =\n visibility === \"store\" && app?.status !== \"PUBLISHED\";\n\n const blocker =\n version && lifecycle\n ? deployBlocker({\n lifecycle,\n version,\n visibility,\n appVisibility,\n workspaceId,\n otherVersionPending,\n canPublish,\n })\n : \"notDraft\";\n\n const handleDeploy = async () => {\n if (!version || blocker || replacingPackage) return;\n setActionError(null);\n setActionSuccess(null);\n if (storeNeedsAppSubmission) {\n // A node's first store release is submitted together with its listing\n // and pricing from the publish page; later versions are submitted here.\n go(`/apps/${appId}/publish`);\n return;\n }\n try {\n if (visibility === \"private\") {\n if (!workspaceId) return;\n const result = await publishToOrganization({\n variables: { id: version.id, workspaceId },\n });\n if (\n result.error ||\n !result.data?.publishApplicationVersionToOrganization\n ) {\n throw (\n result.error ??\n new Error(\n tr(\n \"devportal.versionPublishToOrganizationFailed\",\n \"Failed to publish the version to your organization\",\n ),\n )\n );\n }\n setActionSuccess(\n tr(\n \"devportal.nodeLifecycle.deployedPrivately\",\n \"Deployed to your organization. Workspace admins can now install it from the Node Store.\",\n ),\n );\n } else {\n const result = await submitForReview({\n variables: { id: version.id },\n });\n if (result.error || !result.data?.publishApplicationVersion) {\n throw (\n result.error ??\n new Error(\n tr(\n \"devportal.versionPublishFailed\",\n \"Failed to submit version for review\",\n ),\n )\n );\n }\n setActionSuccess(\n tr(\n \"devportal.nodeLifecycle.submitted\",\n \"Submitted for platform review. It deploys to the Node Store as soon as it is approved.\",\n ),\n );\n }\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.nodeLifecycle.deployFailed\", \"Deploy failed\"),\n );\n }\n };\n\n const copyVersionId = async () => {\n if (!version) return;\n try {\n await navigator.clipboard.writeText(version.id);\n setCopiedId(true);\n window.setTimeout(() => setCopiedId(false), 2000);\n } catch {\n setCopiedId(false);\n }\n };\n\n const versionsPath = `${basePath}/apps/${appId}/versions`;\n\n if (loading && !data) {\n return <LoadingState />;\n }\n\n if (error && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.nodeLifecycle.title\", \"Publish a custom node\")}\n backLink={versionsPath}\n backLabel={tr(\"devportal.backToVersions\", \"Back to versions\")}\n >\n <EmptyState\n title={tr(\n \"devportal.nodeLifecycle.loadFailed\",\n \"Could not load this version\",\n )}\n description={error.message}\n />\n </PageLayout>\n );\n }\n\n if (!app || !version || !lifecycle || app.appType !== \"NODE\") {\n return (\n <PageLayout\n title={tr(\"devportal.nodeLifecycle.title\", \"Publish a custom node\")}\n backLink={versionsPath}\n backLabel={tr(\"devportal.backToVersions\", \"Back to versions\")}\n >\n <EmptyState\n title={tr(\n \"devportal.nodeLifecycle.notFound\",\n \"Custom node version not found\",\n )}\n description={tr(\n \"devportal.nodeLifecycle.notFoundDescription\",\n \"This page shows the lifecycle of a version of a Node application. Pick a version from the versions page.\",\n )}\n />\n </PageLayout>\n );\n }\n\n const status = version.status.toLowerCase();\n const editable = status === \"draft\" || status === \"rejected\";\n const deploying = submitting || publishingPrivately;\n const deployDisabled = Boolean(blocker) || deploying || replacingPackage;\n const [blockerKey, blockerFallback] = blocker\n ? BLOCKER_COPY[blocker]\n : [\"\", \"\"];\n const deployLabel =\n visibility === \"private\"\n ? tr(\"devportal.nodeLifecycle.deployPrivate\", \"Deploy to my organization\")\n : storeNeedsAppSubmission\n ? tr(\n \"devportal.nodeLifecycle.continueToStore\",\n \"Continue to store submission\",\n )\n : tr(\"devportal.nodeLifecycle.submitToStore\", \"Submit for review\");\n\n return (\n <PageLayout\n title={\n <span className=\"flex flex-col gap-2\">\n <span className=\"w-fit rounded-md bg-status-info-bg-subtle px-2 py-0.5 text-xs font-semibold uppercase tracking-wide text-status-info-text\">\n {tr(\"devportal.nodeLifecycle.badge\", \"Custom node\")}\n </span>\n <span>\n {tr(\"devportal.nodeLifecycle.title\", \"Publish a custom node\")}\n {\" · \"}\n <span className=\"font-mono\">\n {app.slug} v{version.version}\n </span>\n </span>\n </span>\n }\n backLink={versionsPath}\n backLabel={tr(\"devportal.backToVersions\", \"Back to versions\")}\n purpose={tr(\n \"devportal.nodeLifecycle.purpose\",\n \"Every custom node goes through the same five stages before workflows can use it. Validation, the sandbox build and the operation tests run automatically after you upload the package.\",\n )}\n fullWidth\n >\n <div className=\"flex flex-wrap items-center gap-2 text-sm text-text-secondary\">\n <span>{tr(\"devportal.nodeLifecycle.versionId\", \"Version ID\")}</span>\n <code\n className=\"rounded-md border border-border-seam bg-bg-sunken px-2 py-0.5 font-mono text-text-primary\"\n data-testid=\"node-lifecycle-version-id\"\n >\n {version.id}\n </code>\n <button\n type=\"button\"\n onClick={copyVersionId}\n aria-label={tr(\n \"devportal.nodeLifecycle.copyVersionId\",\n \"Copy version ID\",\n )}\n className=\"rounded-md p-1 hover:bg-accent\"\n >\n {copiedId ? <Check size={14} /> : <Copy size={14} />}\n </button>\n </div>\n\n {actionError && (\n <div\n role=\"alert\"\n className=\"flex items-start gap-2 rounded-md bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text\"\n >\n <AlertTriangle size={16} className=\"mt-0.5 shrink-0\" />\n {actionError}\n </div>\n )}\n {actionSuccess && (\n <div\n role=\"status\"\n className=\"flex items-start gap-2 rounded-md bg-status-success-bg-subtle px-4 py-3 text-sm text-status-success-text\"\n >\n <CheckCircle2 size={16} className=\"mt-0.5 shrink-0\" />\n {actionSuccess}\n </div>\n )}\n\n <section className=\"rounded-card border border-border-seam bg-bg-surface p-5\">\n <Stepper lifecycle={lifecycle} tr={tr} />\n {status === \"rejected\" && version.reviewNotes && (\n <p className=\"mt-4 rounded-md bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {tr(\"devportal.nodeLifecycle.reviewNotes\", \"Reviewer notes:\")}{\" \"}\n {version.reviewNotes}\n </p>\n )}\n </section>\n\n <section className=\"flex flex-col gap-3 rounded-card border border-border-seam bg-bg-surface p-5 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <Upload size={18} className=\"text-text-secondary\" />\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">\n {version.packageUrl\n ? tr(\n \"devportal.nodeLifecycle.packageAttached\",\n \"Package attached\",\n )\n : tr(\n \"devportal.nodeLifecycle.packageMissing\",\n \"No package yet\",\n )}\n </span>\n <span className=\"text-xs text-text-secondary\">\n {version.packageUrl\n ? [\n version.packageSize &&\n tr(\"devportal.nodeLifecycle.packageSize\", \"{{size}} KB\", {\n size: Math.max(\n 1,\n Math.round(Number(version.packageSize) / 1024),\n ),\n }),\n version.packageHash &&\n `sha256 ${version.packageHash.slice(0, 12)}…`,\n ]\n .filter(Boolean)\n .join(\" · \")\n : tr(\n \"devportal.nodeLifecycle.packageHint\",\n \"A .zip with manifest.json and the node's server (fluidgrids-node new scaffolds one).\",\n )}\n </span>\n {uploading && (\n <span className=\"text-xs text-status-info-text\">\n {tr(\n \"devportal.nodeLifecycle.uploading\",\n \"Uploading… {{progress}}%\",\n {\n progress: Math.round(progress),\n },\n )}\n </span>\n )}\n {uploadError && (\n <span className=\"text-xs text-status-error-text\">\n {uploadError}\n </span>\n )}\n </div>\n </div>\n {editable && canUpdate && (\n <>\n <input\n ref={zipInputRef}\n type=\"file\"\n accept=\".zip,application/zip\"\n className=\"hidden\"\n data-testid=\"node-lifecycle-zip-input\"\n onChange={handlePackageSelected}\n />\n <button\n type=\"button\"\n disabled={uploading || replacingPackage}\n onClick={() => zipInputRef.current?.click()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-seam px-4 py-2 text-sm font-medium hover:bg-accent disabled:opacity-50\"\n >\n {uploading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Upload size={16} />\n )}\n {version.packageUrl\n ? tr(\"devportal.nodeLifecycle.replaceZip\", \"Replace ZIP\")\n : tr(\"devportal.nodeLifecycle.uploadZip\", \"Upload ZIP\")}\n </button>\n </>\n )}\n </section>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <ChecksPanel lifecycle={lifecycle} tr={tr} />\n <ManifestPreview manifest={version.manifest} tr={tr} />\n </div>\n\n <section\n className=\"flex flex-col gap-4 rounded-card border border-border-seam bg-bg-surface p-5 lg:flex-row lg:items-center lg:justify-between\"\n data-testid=\"node-lifecycle-deploy\"\n >\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-sm font-semibold\">\n {tr(\"devportal.nodeLifecycle.visibility\", \"Visibility\")}\n </span>\n <div\n role=\"radiogroup\"\n aria-label={tr(\"devportal.nodeLifecycle.visibility\", \"Visibility\")}\n className=\"inline-flex w-fit overflow-hidden rounded-md border border-border-seam\"\n >\n {(\n [\n [\n \"private\",\n <Lock key=\"i\" size={14} />,\n tr(\"devportal.nodeLifecycle.private\", \"Workspace-private\"),\n ],\n [\n \"store\",\n <Globe key=\"i\" size={14} />,\n tr(\"devportal.nodeLifecycle.store\", \"Submit to store\"),\n ],\n ] as const\n ).map(([value, icon, label]) => {\n const selected = visibility === value;\n return (\n <span\n key={value}\n role=\"radio\"\n aria-checked={selected}\n aria-disabled={!selected}\n data-visibility={value}\n className={cn(\n \"inline-flex items-center gap-2 px-4 py-2 text-sm\",\n selected\n ? \"bg-status-info-bg-subtle font-medium text-status-info-text\"\n : \"text-text-secondary\",\n )}\n >\n {icon}\n {label}\n </span>\n );\n })}\n </div>\n <p className=\"max-w-xl text-xs text-text-secondary\">\n {visibility === \"private\"\n ? tr(\n \"devportal.nodeLifecycle.privateHint\",\n \"Private nodes skip platform review: deploying approves the version for your organization and only its workspaces can install it.\",\n )\n : tr(\n \"devportal.nodeLifecycle.storeHint\",\n \"Store nodes are reviewed by the platform team and deploy to the public Node Store once approved.\",\n )}{\" \"}\n <button\n type=\"button\"\n className=\"font-medium text-status-info-text hover:underline\"\n onClick={() => go(`/apps/${appId}/edit`)}\n >\n {tr(\n \"devportal.nodeLifecycle.changeVisibility\",\n \"Change visibility\",\n )}\n </button>\n </p>\n </div>\n <div className=\"flex flex-col items-stretch gap-2 lg:items-end\">\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => go(`/apps/${appId}/versions`)}\n className=\"inline-flex items-center justify-center gap-2 rounded-md border border-border-seam px-4 py-2 text-sm font-medium hover:bg-accent\"\n >\n <BookOpen size={16} />\n {tr(\"devportal.nodeLifecycle.allVersions\", \"All versions\")}\n </button>\n {lifecycle.steps[4].status !== \"complete\" && (\n <button\n type=\"button\"\n onClick={handleDeploy}\n disabled={deployDisabled}\n aria-disabled={deployDisabled}\n data-testid=\"node-lifecycle-deploy-button\"\n className=\"inline-flex items-center justify-center gap-2 rounded-md bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {deploying ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : visibility === \"private\" ? (\n <Building2 size={16} />\n ) : (\n <Rocket size={16} />\n )}\n {deployLabel}\n </button>\n )}\n </div>\n {blocker && lifecycle.steps[4].status !== \"complete\" && (\n <p\n className=\"max-w-sm text-xs text-text-secondary lg:text-right\"\n data-testid=\"node-lifecycle-deploy-blocker\"\n data-blocker={blocker}\n >\n {tr(blockerKey, blockerFallback)}\n </p>\n )}\n {lifecycle.steps[4].status === \"complete\" && (\n <p className=\"inline-flex items-center gap-1 text-sm font-medium text-status-success-text\">\n <CheckCircle2 size={16} />\n {stepReason(tr, lifecycle.steps[4])}\n </p>\n )}\n </div>\n </section>\n </PageLayout>\n );\n};\n\nexport default NodeLifecyclePage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NodeLifecyclePage.js","names":["_Fragment","LIFECYCLE_POLL_INTERVAL_MS","STEP_LABELS","STEP_REASONS","CHECK_META","Package","FileCode2","ShieldCheck","Server","FlaskConical","CHECK_BADGE","BLOCKER_COPY","stepReason","tr","step","StepIndicator","base","cn","Check","XCircle","Loader2","index","Stepper","lifecycle","key","fallback","tone","checkDetail","check","passed","total","ChecksPanel","showLogs","setShowLogs","useState","smoke","operations","finishedAt","meta","badge","detail","issue","value","jsx","ChevronUp","ChevronDown","op","CheckCircle2","MinusCircle","ManifestPreview","copied","setCopied","text","useMemo","manifest","lines","Copy","line","NodeLifecyclePage","useTr","useParams","useDevportal","canPublish","useDevportalPermission","DEVPORTAL_PERMISSIONS","canUpdate","useGetApplicationQuery","appId","app","data","versions","edge","version","v","versionId","appVisibility","visibility","visibilityForApp","deriveNodeLifecycle","busy","startPolling","stopPolling","otherVersionPending","updateVersion","useUpdateApplicationVersionMutation","submitForReview","submitting","usePublishApplicationVersionMutation","publishToOrganization","publishingPrivately","usePublishApplicationVersionToOrganizationMutation","uploadPackage","uploadError","usePackageUpload","workspacesGatewayUrl","authToken","workspaceId","getWorkspaceToken","zipInputRef","useRef","actionError","setActionError","actionSuccess","setActionSuccess","copiedId","setCopiedId","replacingPackage","setReplacingPackage","go","useCallback","navigate","basePath","path","handlePackageSelected","file","event","uploaded","result","err","storeNeedsAppSubmission","blocker","deployBlocker","handleDeploy","copyVersionId","versionsPath","loading","LoadingState","error","PageLayout","EmptyState","status","editable","deploying","deployDisabled","blockerKey","blockerFallback","deployLabel","AlertTriangle","Upload","uploading","progress","Fragment","Lock","Globe","icon","label","selected","BookOpen","Building2","Rocket"],"sources":["../../../src/devportal/pages/NodeLifecyclePage.tsx"],"sourcesContent":["/**\n * NodeLifecyclePage — \"Publish a custom node\" (BOFF-4076).\n *\n * One page that walks a custom-node version through its whole lifecycle:\n * upload ZIP → validate manifest → run tests → approval → deploy. It is a view\n * over the ApplicationVersion that global-devportal-svc already maintains (see\n * utils/nodeLifecycle.ts), plus the three developer actions the lifecycle\n * needs: upload or replace the package, publish a workspace-private node to\n * the developer's organization, and submit a store node for platform review.\n *\n * The page polls while the platform is working (validating, building,\n * testing, reviewing) so each stage flips as soon as the service records it.\n */\nimport type { FC, ReactNode } from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useParams } from \"react-router\";\nimport {\n AlertTriangle,\n BookOpen,\n Building2,\n Check,\n CheckCircle2,\n ChevronDown,\n ChevronUp,\n Copy,\n FileCode2,\n FlaskConical,\n Globe,\n Loader2,\n Lock,\n MinusCircle,\n Package,\n Rocket,\n Server,\n ShieldCheck,\n Upload,\n XCircle,\n} from \"lucide-react\";\n\nimport { PageLayout } from \"../components/PageLayout\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { cn } from \"../utils/cn\";\nimport { useTr } from \"../utils/i18n\";\nimport {\n useGetApplicationQuery,\n useUpdateApplicationVersionMutation,\n usePublishApplicationVersionMutation,\n usePublishApplicationVersionToOrganizationMutation,\n type ApplicationVersionFieldsFragment,\n} from \"../hooks\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { usePackageUpload } from \"../hooks/usePackageUpload\";\nimport {\n deployBlocker,\n deriveNodeLifecycle,\n visibilityForApp,\n type CheckStatus,\n type DeployBlocker,\n type LifecycleCheck,\n type LifecycleStep,\n type NodeLifecycle,\n} from \"../utils/nodeLifecycle\";\n\n/** Poll every 10 s while the platform is still working on the version. */\nexport const LIFECYCLE_POLL_INTERVAL_MS = 10_000;\n\ntype Tr = ReturnType<typeof useTr>;\n\nconst STEP_LABELS: Record<LifecycleStep[\"id\"], [string, string]> = {\n upload: [\"devportal.nodeLifecycle.step.upload\", \"Upload ZIP\"],\n validate: [\"devportal.nodeLifecycle.step.validate\", \"Validate manifest\"],\n test: [\"devportal.nodeLifecycle.step.test\", \"Run tests\"],\n approval: [\"devportal.nodeLifecycle.step.approval\", \"Approval\"],\n deploy: [\"devportal.nodeLifecycle.step.deploy\", \"Deploy\"],\n};\n\nconst STEP_REASONS: Record<string, string> = {\n uploaded: \"Completed\",\n noPackage: \"Upload the node package\",\n waitingForPackage: \"Pending\",\n passed: \"Completed\",\n failed: \"Failed — see checks\",\n validating: \"In progress\",\n notValidated: \"Upload the package again to validate it\",\n waitingForValidation: \"Pending\",\n building: \"Building sandbox image\",\n buildFailed: \"Build failed\",\n testing: \"Testing operations\",\n testsFailed: \"Tests failed\",\n testsSkipped: \"Completed (tests not run here)\",\n testsPassed: \"Completed\",\n built: \"Completed\",\n organization: \"Approved by your organization\",\n approved: \"Approved\",\n inReview: \"Awaiting platform review\",\n rejected: \"Changes requested\",\n waitingForTests: \"Pending\",\n readyForOrganization: \"Auto-approved when you deploy\",\n readyToSubmit: \"Submit for platform review\",\n deprecated: \"Deprecated\",\n store: \"Live in the Node Store\",\n deployedToOrganization: \"Installable in your organization's workspaces\",\n ready: \"Ready to deploy\",\n waitingForApproval: \"Pending\",\n};\n\nconst CHECK_META: Record<\n LifecycleCheck[\"id\"],\n { icon: ReactNode; key: string; label: string }\n> = {\n structure: {\n icon: <Package size={16} />,\n key: \"devportal.nodeLifecycle.check.structure\",\n label: \"Package structure\",\n },\n manifest: {\n icon: <FileCode2 size={16} />,\n key: \"devportal.nodeLifecycle.check.manifest\",\n label: \"Manifest & operations\",\n },\n security: {\n icon: <ShieldCheck size={16} />,\n key: \"devportal.nodeLifecycle.check.security\",\n label: \"Security scan\",\n },\n build: {\n icon: <Server size={16} />,\n key: \"devportal.nodeLifecycle.check.build\",\n label: \"Sandbox image build\",\n },\n tests: {\n icon: <FlaskConical size={16} />,\n key: \"devportal.nodeLifecycle.check.tests\",\n label: \"Automated operation tests\",\n },\n};\n\nconst CHECK_BADGE: Record<CheckStatus, { label: string; className: string }> = {\n pass: {\n label: \"PASS\",\n className: \"bg-status-success-bg-subtle text-status-success-text\",\n },\n warn: {\n label: \"REVIEW\",\n className: \"bg-status-warning-bg-subtle text-status-warning-text\",\n },\n fail: {\n label: \"FAIL\",\n className: \"bg-status-error-bg-subtle text-status-error-text\",\n },\n running: {\n label: \"RUNNING\",\n className: \"bg-status-info-bg-subtle text-status-info-text\",\n },\n not_run: {\n label: \"NOT RUN\",\n className: \"bg-bg-sunken text-text-secondary\",\n },\n};\n\nconst BLOCKER_COPY: Record<DeployBlocker, [string, string]> = {\n noPermission: [\n \"devportal.nodeLifecycle.blocker.noPermission\",\n \"You do not have permission to publish versions of this node.\",\n ],\n notDraft: [\n \"devportal.nodeLifecycle.blocker.notDraft\",\n \"This version has already been submitted or deployed. Create a new version to ship a change.\",\n ],\n visibilityMismatch: [\n \"devportal.nodeLifecycle.blocker.visibilityMismatch\",\n \"This node's visibility does not allow that. Change it under Edit application.\",\n ],\n noPackage: [\n \"devportal.nodeLifecycle.blocker.noPackage\",\n \"Upload the node package first.\",\n ],\n validationNotPassed: [\n \"devportal.nodeLifecycle.blocker.validationNotPassed\",\n \"The package must pass validation first.\",\n ],\n buildNotReady: [\n \"devportal.nodeLifecycle.blocker.buildNotReady\",\n \"Waiting for the sandbox image to build.\",\n ],\n testsNotPassed: [\n \"devportal.nodeLifecycle.blocker.testsNotPassed\",\n \"The operation tests must finish without failures first.\",\n ],\n noWorkspace: [\n \"devportal.nodeLifecycle.blocker.noWorkspace\",\n \"Open the developer portal from a workspace of your organization to publish privately.\",\n ],\n pendingVersion: [\n \"devportal.nodeLifecycle.blocker.pendingVersion\",\n \"Another version of this node is already in review.\",\n ],\n};\n\nfunction stepReason(tr: Tr, step: LifecycleStep): string {\n return tr(\n `devportal.nodeLifecycle.reason.${step.reason}`,\n STEP_REASONS[step.reason] ?? step.reason,\n );\n}\n\nconst StepIndicator: FC<{ step: LifecycleStep; index: number }> = ({\n step,\n index,\n}) => {\n const base =\n \"flex h-11 w-11 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold\";\n switch (step.status) {\n case \"complete\":\n return (\n <span\n className={cn(\n base,\n \"border-status-success-text bg-status-success-bg-subtle text-status-success-text\",\n )}\n >\n <Check size={20} />\n </span>\n );\n case \"failed\":\n return (\n <span\n className={cn(\n base,\n \"border-status-error-text bg-status-error-bg-subtle text-status-error-text\",\n )}\n >\n <XCircle size={20} />\n </span>\n );\n case \"in_progress\":\n return (\n <span\n className={cn(\n base,\n \"border-action-primary-bg bg-action-primary-bg text-action-primary-text\",\n )}\n >\n <Loader2 size={18} className=\"animate-spin\" />\n </span>\n );\n case \"action\":\n return (\n <span\n className={cn(\n base,\n \"border-action-primary-bg bg-action-primary-bg text-action-primary-text\",\n )}\n >\n {index + 1}\n </span>\n );\n default:\n return (\n <span className={cn(base, \"border-border-seam text-text-secondary\")}>\n {index + 1}\n </span>\n );\n }\n};\n\nconst Stepper: FC<{ lifecycle: NodeLifecycle; tr: Tr }> = ({\n lifecycle,\n tr,\n}) => (\n <ol\n className=\"grid grid-cols-1 gap-4 sm:grid-cols-5\"\n data-testid=\"node-lifecycle-stepper\"\n >\n {lifecycle.steps.map((step, index) => {\n const [key, fallback] = STEP_LABELS[step.id];\n const tone =\n step.status === \"complete\"\n ? \"text-status-success-text\"\n : step.status === \"failed\"\n ? \"text-status-error-text\"\n : step.status === \"in_progress\" || step.status === \"action\"\n ? \"text-status-info-text\"\n : \"text-text-secondary\";\n return (\n <li\n key={step.id}\n className=\"flex items-center gap-3 sm:flex-col sm:text-center\"\n data-step={step.id}\n data-status={step.status}\n aria-current={index === lifecycle.currentIndex ? \"step\" : undefined}\n >\n <StepIndicator step={step} index={index} />\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {index + 1}. {tr(key, fallback)}\n </span>\n <span className={cn(\"text-xs\", tone)}>{stepReason(tr, step)}</span>\n </div>\n </li>\n );\n })}\n </ol>\n);\n\nfunction checkDetail(tr: Tr, check: LifecycleCheck): string | null {\n if (check.id === \"tests\" && check.status === \"pass\" && check.detail) {\n const [passed, total] = check.detail.split(\"/\");\n return tr(\n \"devportal.nodeLifecycle.testsPassing\",\n \"{{passed}} / {{total}} passing\",\n { passed: passed ?? \"0\", total: total ?? \"0\" },\n );\n }\n if (check.detail === \"notValidated\") {\n return tr(\n \"devportal.nodeLifecycle.notValidated\",\n \"Uploaded before validation existed\",\n );\n }\n if (check.detail === \"blockedByValidation\") {\n return tr(\n \"devportal.nodeLifecycle.blockedByValidation\",\n \"Not built: the package failed validation\",\n );\n }\n return check.detail;\n}\n\nconst ChecksPanel: FC<{ lifecycle: NodeLifecycle; tr: Tr }> = ({\n lifecycle,\n tr,\n}) => {\n const [showLogs, setShowLogs] = useState(false);\n const smoke = lifecycle.smoke;\n const operations =\n smoke.kind === \"passed\" ||\n smoke.kind === \"failed\" ||\n smoke.kind === \"skipped\"\n ? smoke.operations\n : [];\n const finishedAt =\n smoke.kind === \"passed\" ||\n smoke.kind === \"failed\" ||\n smoke.kind === \"skipped\"\n ? smoke.finishedAt\n : null;\n\n return (\n <section\n className=\"flex flex-col rounded-card border border-border-seam bg-bg-surface\"\n data-testid=\"node-lifecycle-checks\"\n >\n <h2 className=\"border-b border-border-seam px-5 py-4 text-base font-semibold\">\n {tr(\"devportal.nodeLifecycle.checks\", \"Checks\")}\n </h2>\n <ul className=\"divide-y divide-border-seam\">\n {lifecycle.checks.map((check) => {\n const meta = CHECK_META[check.id];\n const badge = CHECK_BADGE[check.status];\n const detail = checkDetail(tr, check);\n return (\n <li\n key={check.id}\n className=\"px-5 py-3\"\n data-check={check.id}\n data-status={check.status}\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"text-text-secondary\">{meta.icon}</span>\n <span className=\"flex-1 text-sm font-medium\">\n {tr(meta.key, meta.label)}\n {detail && (\n <span className=\"ml-2 text-xs font-normal text-text-secondary\">\n {detail}\n </span>\n )}\n </span>\n <span\n className={cn(\n \"inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-semibold\",\n badge.className,\n )}\n >\n {check.status === \"running\" && (\n <Loader2 size={11} className=\"animate-spin\" />\n )}\n {tr(\n `devportal.nodeLifecycle.badge.${check.status}`,\n badge.label,\n )}\n </span>\n </div>\n {check.issues.length > 0 && (\n <ul className=\"mt-2 space-y-1 pl-7\">\n {check.issues.map((issue, index) => (\n <li\n key={`${issue.code}-${issue.path}-${index}`}\n className=\"text-xs leading-snug\"\n >\n {issue.path && (\n <code className=\"mr-1 rounded bg-bg-sunken px-1 py-0.5 font-mono text-text-primary\">\n {issue.path}\n </code>\n )}\n <span\n className={\n issue.severity === \"error\"\n ? \"text-status-error-text\"\n : \"text-status-warning-text\"\n }\n >\n {issue.message}\n </span>\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n <div className=\"mt-auto border-t border-border-seam px-5 py-3\">\n <div className=\"flex items-center justify-between gap-2 text-xs text-text-secondary\">\n <span>\n {finishedAt\n ? tr(\n \"devportal.nodeLifecycle.testsFinished\",\n \"Tests finished {{time}}\",\n { time: new Date(finishedAt).toLocaleString() },\n )\n : tr(\n \"devportal.nodeLifecycle.testsNotFinished\",\n \"No test run recorded yet\",\n )}\n </span>\n {operations.length > 0 && (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 font-medium text-status-info-text hover:underline\"\n onClick={() => setShowLogs((value) => !value)}\n aria-expanded={showLogs}\n >\n {showLogs\n ? tr(\"devportal.nodeLifecycle.hideTestLogs\", \"Hide test logs\")\n : tr(\"devportal.nodeLifecycle.viewTestLogs\", \"View test logs\")}\n {showLogs ? <ChevronUp size={12} /> : <ChevronDown size={12} />}\n </button>\n )}\n </div>\n {showLogs && (\n <ul\n className=\"mt-3 space-y-1 rounded-md bg-bg-sunken p-3 font-mono text-xs\"\n data-testid=\"node-lifecycle-test-logs\"\n >\n {operations.map((op, index) => (\n <li key={`${op.name}-${index}`} className=\"flex gap-2\">\n {op.status === \"PASS\" ? (\n <CheckCircle2\n size={12}\n className=\"mt-0.5 shrink-0 text-status-success-text\"\n />\n ) : op.status === \"SKIP\" ? (\n <MinusCircle\n size={12}\n className=\"mt-0.5 shrink-0 text-text-secondary\"\n />\n ) : (\n <XCircle\n size={12}\n className=\"mt-0.5 shrink-0 text-status-error-text\"\n />\n )}\n <span className=\"text-text-primary\">{op.name}</span>\n <span className=\"text-text-secondary\">\n {op.status} · {op.durationMs} ms\n </span>\n {(op.error ?? op.detail) && (\n <span className=\"break-all text-text-secondary\">\n {op.error ?? op.detail}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n </section>\n );\n};\n\nconst ManifestPreview: FC<{ manifest: unknown; tr: Tr }> = ({\n manifest,\n tr,\n}) => {\n const [copied, setCopied] = useState(false);\n const text = useMemo(\n () => (manifest ? JSON.stringify(manifest, null, 2) : \"\"),\n [manifest],\n );\n const lines = text ? text.split(\"\\n\") : [];\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n window.setTimeout(() => setCopied(false), 2000);\n } catch {\n setCopied(false);\n }\n };\n\n return (\n <section\n className=\"flex min-w-0 flex-col rounded-card border border-border-seam bg-bg-surface\"\n data-testid=\"node-lifecycle-manifest\"\n >\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam px-5 py-3\">\n <h2 className=\"text-base font-semibold\">\n {tr(\"devportal.nodeLifecycle.manifestPreview\", \"Manifest preview\")}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n (manifest.json)\n </span>\n </h2>\n {text && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-seam px-3 py-1.5 text-xs font-medium hover:bg-accent\"\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n {copied\n ? tr(\"devportal.copied\", \"Copied\")\n : tr(\"devportal.copy\", \"Copy\")}\n </button>\n )}\n </div>\n {lines.length > 0 ? (\n <pre className=\"max-h-[28rem] flex-1 overflow-auto px-0 py-3 font-mono text-xs leading-5\">\n {lines.map((line, index) => (\n <div key={index} className=\"flex\">\n <span className=\"w-10 shrink-0 select-none pr-3 text-right text-text-tertiary\">\n {index + 1}\n </span>\n <span className=\"whitespace-pre text-text-primary\">{line}</span>\n </div>\n ))}\n </pre>\n ) : (\n <p className=\"px-5 py-6 text-sm text-text-secondary\">\n {tr(\n \"devportal.nodeLifecycle.noManifest\",\n \"This version has no manifest yet. Add one from the versions page.\",\n )}\n </p>\n )}\n </section>\n );\n};\n\nexport const NodeLifecyclePage: FC = () => {\n const tr = useTr();\n const { appId, versionId } = useParams<{\n appId: string;\n versionId: string;\n }>();\n const {\n basePath,\n navigate,\n workspaceId,\n workspacesGatewayUrl,\n authToken,\n getWorkspaceToken,\n } = useDevportal();\n const { allowed: canPublish } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_PUBLISH,\n );\n const { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_UPDATE,\n );\n\n const { data, loading, error, startPolling, stopPolling } =\n useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const app = data?.application;\n const versions: ApplicationVersionFieldsFragment[] = useMemo(\n () =>\n app?.versions?.edges?.map(\n (edge: { node: ApplicationVersionFieldsFragment }) => edge.node,\n ) ?? [],\n [app?.versions],\n );\n const version = versions.find((v) => v.id === versionId) ?? null;\n const appVisibility = app?.visibility ?? null;\n const visibility = visibilityForApp(appVisibility);\n\n const lifecycle = useMemo(\n () => (version ? deriveNodeLifecycle(version, visibility) : null),\n [version, visibility],\n );\n\n // Poll only while the platform is working; stop once every stage settles.\n const busy = lifecycle?.busy ?? false;\n useEffect(() => {\n if (!busy) return undefined;\n startPolling(LIFECYCLE_POLL_INTERVAL_MS);\n return () => stopPolling();\n }, [busy, startPolling, stopPolling]);\n\n const otherVersionPending = versions.some(\n (v) => v.id !== versionId && v.status === \"pending_review\",\n );\n\n // Wait for the refetch so the page shows the new package's (pending)\n // validation before the replacement counts as finished.\n const [updateVersion] = useUpdateApplicationVersionMutation({\n refetchQueries: [\"GetApplication\"],\n awaitRefetchQueries: true,\n });\n const [submitForReview, { loading: submitting }] =\n usePublishApplicationVersionMutation({\n refetchQueries: [\"GetApplication\"],\n });\n const [publishToOrganization, { loading: publishingPrivately }] =\n usePublishApplicationVersionToOrganizationMutation({\n refetchQueries: [\"GetApplication\"],\n });\n const {\n upload: uploadPackage,\n uploading,\n progress,\n error: uploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n );\n const zipInputRef = useRef<HTMLInputElement>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [actionSuccess, setActionSuccess] = useState<string | null>(null);\n const [copiedId, setCopiedId] = useState(false);\n // True from the moment a package is picked until the version carries it and\n // has been re-read. Deploy stays disabled meanwhile: the readiness shown is\n // still the old package's, and deploying now would ship the old package.\n const [replacingPackage, setReplacingPackage] = useState(false);\n\n const go = useCallback(\n (path: string) => navigate?.(`${basePath}${path}`),\n [navigate, basePath],\n );\n\n const handlePackageSelected = async (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const file = event.target.files?.[0];\n event.target.value = \"\";\n if (!file || !version) return;\n setActionError(null);\n setActionSuccess(null);\n if (!file.name.toLowerCase().endsWith(\".zip\")) {\n setActionError(\n tr(\n \"devportal.nodeLifecycle.zipOnly\",\n \"Upload the node as a .zip package.\",\n ),\n );\n return;\n }\n setReplacingPackage(true);\n try {\n const uploaded = await uploadPackage(file);\n const result = await updateVersion({\n variables: {\n id: version.id,\n input: {\n packageUrl: uploaded.downloadUrl,\n packageFileId: uploaded.fileId || undefined,\n packageWorkspaceId: workspaceId || undefined,\n packageSize: String(file.size),\n },\n },\n });\n if (result.error || !result.data?.updateApplicationVersion) {\n throw (\n result.error ??\n new Error(\n tr(\n \"devportal.nodeLifecycle.uploadFailed\",\n \"Failed to attach the package to this version\",\n ),\n )\n );\n }\n setActionSuccess(\n tr(\n \"devportal.nodeLifecycle.uploaded\",\n \"Package uploaded. Validation and tests start automatically.\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.nodeLifecycle.uploadFailed\",\n \"Failed to attach the package to this version\",\n ),\n );\n } finally {\n setReplacingPackage(false);\n }\n };\n\n const storeNeedsAppSubmission =\n visibility === \"store\" && app?.status !== \"PUBLISHED\";\n\n const blocker =\n version && lifecycle\n ? deployBlocker({\n lifecycle,\n version,\n visibility,\n appVisibility,\n workspaceId,\n otherVersionPending,\n canPublish,\n })\n : \"notDraft\";\n\n const handleDeploy = async () => {\n if (!version || blocker || replacingPackage) return;\n setActionError(null);\n setActionSuccess(null);\n if (storeNeedsAppSubmission) {\n // A node's first store release is submitted together with its listing\n // and pricing from the publish page; later versions are submitted here.\n go(`/apps/${appId}/publish`);\n return;\n }\n try {\n if (visibility === \"private\") {\n if (!workspaceId) return;\n const result = await publishToOrganization({\n variables: { id: version.id, workspaceId },\n });\n if (\n result.error ||\n !result.data?.publishApplicationVersionToOrganization\n ) {\n throw (\n result.error ??\n new Error(\n tr(\n \"devportal.versionPublishToOrganizationFailed\",\n \"Failed to publish the version to your organization\",\n ),\n )\n );\n }\n setActionSuccess(\n tr(\n \"devportal.nodeLifecycle.deployedPrivately\",\n \"Deployed to your organization. Workspace admins can now install it from the Node Store.\",\n ),\n );\n } else {\n const result = await submitForReview({\n variables: { id: version.id },\n });\n if (result.error || !result.data?.publishApplicationVersion) {\n throw (\n result.error ??\n new Error(\n tr(\n \"devportal.versionPublishFailed\",\n \"Failed to submit version for review\",\n ),\n )\n );\n }\n setActionSuccess(\n tr(\n \"devportal.nodeLifecycle.submitted\",\n \"Submitted for platform review. It deploys to the Node Store as soon as it is approved.\",\n ),\n );\n }\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.nodeLifecycle.deployFailed\", \"Deploy failed\"),\n );\n }\n };\n\n const copyVersionId = async () => {\n if (!version) return;\n try {\n await navigator.clipboard.writeText(version.id);\n setCopiedId(true);\n window.setTimeout(() => setCopiedId(false), 2000);\n } catch {\n setCopiedId(false);\n }\n };\n\n const versionsPath = `${basePath}/apps/${appId}/versions`;\n\n if (loading && !data) {\n return <LoadingState />;\n }\n\n if (error && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.nodeLifecycle.title\", \"Publish a custom node\")}\n backLink={versionsPath}\n backLabel={tr(\"devportal.backToVersions\", \"Back to versions\")}\n >\n <EmptyState\n title={tr(\n \"devportal.nodeLifecycle.loadFailed\",\n \"Could not load this version\",\n )}\n description={error.message}\n />\n </PageLayout>\n );\n }\n\n if (!app || !version || !lifecycle || app.appType !== \"NODE\") {\n return (\n <PageLayout\n title={tr(\"devportal.nodeLifecycle.title\", \"Publish a custom node\")}\n backLink={versionsPath}\n backLabel={tr(\"devportal.backToVersions\", \"Back to versions\")}\n >\n <EmptyState\n title={tr(\n \"devportal.nodeLifecycle.notFound\",\n \"Custom node version not found\",\n )}\n description={tr(\n \"devportal.nodeLifecycle.notFoundDescription\",\n \"This page shows the lifecycle of a version of a Node application. Pick a version from the versions page.\",\n )}\n />\n </PageLayout>\n );\n }\n\n const status = version.status.toLowerCase();\n const editable = status === \"draft\" || status === \"rejected\";\n const deploying = submitting || publishingPrivately;\n const deployDisabled = Boolean(blocker) || deploying || replacingPackage;\n const [blockerKey, blockerFallback] = blocker\n ? BLOCKER_COPY[blocker]\n : [\"\", \"\"];\n const deployLabel =\n visibility === \"private\"\n ? tr(\"devportal.nodeLifecycle.deployPrivate\", \"Deploy to my organization\")\n : storeNeedsAppSubmission\n ? tr(\n \"devportal.nodeLifecycle.continueToStore\",\n \"Continue to store submission\",\n )\n : tr(\"devportal.nodeLifecycle.submitToStore\", \"Submit for review\");\n\n return (\n <PageLayout\n title={\n <span className=\"flex flex-col gap-2\">\n <span className=\"w-fit rounded-md bg-status-info-bg-subtle px-2 py-0.5 text-xs font-semibold uppercase tracking-wide text-status-info-text\">\n {tr(\"devportal.nodeLifecycle.badge\", \"Custom node\")}\n </span>\n <span>\n {tr(\"devportal.nodeLifecycle.title\", \"Publish a custom node\")}\n {\" · \"}\n <span className=\"font-mono\">\n {app.slug} v{version.version}\n </span>\n </span>\n </span>\n }\n backLink={versionsPath}\n backLabel={tr(\"devportal.backToVersions\", \"Back to versions\")}\n purpose={tr(\n \"devportal.nodeLifecycle.purpose\",\n \"Every custom node goes through the same five stages before workflows can use it. Validation, the sandbox build and the operation tests run automatically after you upload the package.\",\n )}\n fullWidth\n >\n <div className=\"flex flex-wrap items-center gap-2 text-sm text-text-secondary\">\n <span>{tr(\"devportal.nodeLifecycle.versionId\", \"Version ID\")}</span>\n <code\n className=\"rounded-md border border-border-seam bg-bg-sunken px-2 py-0.5 font-mono text-text-primary\"\n data-testid=\"node-lifecycle-version-id\"\n >\n {version.id}\n </code>\n <button\n type=\"button\"\n onClick={copyVersionId}\n aria-label={tr(\n \"devportal.nodeLifecycle.copyVersionId\",\n \"Copy version ID\",\n )}\n className=\"rounded-md p-1 hover:bg-accent\"\n >\n {copiedId ? <Check size={14} /> : <Copy size={14} />}\n </button>\n </div>\n\n {actionError && (\n <div\n role=\"alert\"\n className=\"flex items-start gap-2 rounded-md bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text\"\n >\n <AlertTriangle size={16} className=\"mt-0.5 shrink-0\" />\n {actionError}\n </div>\n )}\n {actionSuccess && (\n <div\n role=\"status\"\n className=\"flex items-start gap-2 rounded-md bg-status-success-bg-subtle px-4 py-3 text-sm text-status-success-text\"\n >\n <CheckCircle2 size={16} className=\"mt-0.5 shrink-0\" />\n {actionSuccess}\n </div>\n )}\n\n <section className=\"rounded-card border border-border-seam bg-bg-surface p-5\">\n <Stepper lifecycle={lifecycle} tr={tr} />\n {status === \"rejected\" && version.reviewNotes && (\n <p className=\"mt-4 rounded-md bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {tr(\"devportal.nodeLifecycle.reviewNotes\", \"Reviewer notes:\")}{\" \"}\n {version.reviewNotes}\n </p>\n )}\n </section>\n\n <section className=\"flex flex-col gap-3 rounded-card border border-border-seam bg-bg-surface p-5 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <Upload size={18} className=\"text-text-secondary\" />\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">\n {version.packageUrl\n ? tr(\n \"devportal.nodeLifecycle.packageAttached\",\n \"Package attached\",\n )\n : tr(\n \"devportal.nodeLifecycle.packageMissing\",\n \"No package yet\",\n )}\n </span>\n <span className=\"text-xs text-text-secondary\">\n {version.packageUrl\n ? [\n version.packageSize &&\n tr(\"devportal.nodeLifecycle.packageSize\", \"{{size}} KB\", {\n size: Math.max(\n 1,\n Math.round(Number(version.packageSize) / 1024),\n ),\n }),\n version.packageHash &&\n `sha256 ${version.packageHash.slice(0, 12)}…`,\n ]\n .filter(Boolean)\n .join(\" · \")\n : tr(\n \"devportal.nodeLifecycle.packageHint\",\n \"A .zip with manifest.json and the node's server (fluidgrids-node new scaffolds one).\",\n )}\n </span>\n {uploading && (\n <span className=\"text-xs text-status-info-text\">\n {tr(\n \"devportal.nodeLifecycle.uploading\",\n \"Uploading… {{progress}}%\",\n {\n progress: Math.round(progress),\n },\n )}\n </span>\n )}\n {uploadError && (\n <span className=\"text-xs text-status-error-text\">\n {uploadError}\n </span>\n )}\n </div>\n </div>\n {editable && canUpdate && (\n <>\n <input\n ref={zipInputRef}\n type=\"file\"\n accept=\".zip,application/zip\"\n className=\"hidden\"\n data-testid=\"node-lifecycle-zip-input\"\n onChange={handlePackageSelected}\n />\n <button\n type=\"button\"\n disabled={uploading || replacingPackage}\n onClick={() => zipInputRef.current?.click()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-seam px-4 py-2 text-sm font-medium hover:bg-accent disabled:opacity-50\"\n >\n {uploading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Upload size={16} />\n )}\n {version.packageUrl\n ? tr(\"devportal.nodeLifecycle.replaceZip\", \"Replace ZIP\")\n : tr(\"devportal.nodeLifecycle.uploadZip\", \"Upload ZIP\")}\n </button>\n </>\n )}\n </section>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <ChecksPanel lifecycle={lifecycle} tr={tr} />\n <ManifestPreview manifest={version.manifest} tr={tr} />\n </div>\n\n <section\n className=\"flex flex-col gap-4 rounded-card border border-border-seam bg-bg-surface p-5 lg:flex-row lg:items-center lg:justify-between\"\n data-testid=\"node-lifecycle-deploy\"\n >\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-sm font-semibold\">\n {tr(\"devportal.nodeLifecycle.visibility\", \"Visibility\")}\n </span>\n <div\n role=\"radiogroup\"\n aria-label={tr(\"devportal.nodeLifecycle.visibility\", \"Visibility\")}\n className=\"inline-flex w-fit overflow-hidden rounded-md border border-border-seam\"\n >\n {(\n [\n [\n \"private\",\n <Lock key=\"i\" size={14} />,\n tr(\"devportal.nodeLifecycle.private\", \"Workspace-private\"),\n ],\n [\n \"store\",\n <Globe key=\"i\" size={14} />,\n tr(\"devportal.nodeLifecycle.store\", \"Submit to store\"),\n ],\n ] as const\n ).map(([value, icon, label]) => {\n const selected = visibility === value;\n return (\n <span\n key={value}\n role=\"radio\"\n aria-checked={selected}\n aria-disabled={!selected}\n data-visibility={value}\n className={cn(\n \"inline-flex items-center gap-2 px-4 py-2 text-sm\",\n selected\n ? \"bg-status-info-bg-subtle font-medium text-status-info-text\"\n : \"text-text-secondary\",\n )}\n >\n {icon}\n {label}\n </span>\n );\n })}\n </div>\n <p className=\"max-w-xl text-xs text-text-secondary\">\n {visibility === \"private\"\n ? tr(\n \"devportal.nodeLifecycle.privateHint\",\n \"Private nodes skip platform review: deploying approves the version for your organization and only its workspaces can install it.\",\n )\n : tr(\n \"devportal.nodeLifecycle.storeHint\",\n \"Store nodes are reviewed by the platform team and deploy to the public Node Store once approved.\",\n )}{\" \"}\n <button\n type=\"button\"\n className=\"font-medium text-status-info-text hover:underline\"\n onClick={() => go(`/apps/${appId}/edit`)}\n >\n {tr(\n \"devportal.nodeLifecycle.changeVisibility\",\n \"Change visibility\",\n )}\n </button>\n </p>\n </div>\n <div className=\"flex flex-col items-stretch gap-2 lg:items-end\">\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => go(`/apps/${appId}/versions`)}\n className=\"inline-flex items-center justify-center gap-2 rounded-md border border-border-seam px-4 py-2 text-sm font-medium hover:bg-accent\"\n >\n <BookOpen size={16} />\n {tr(\"devportal.nodeLifecycle.allVersions\", \"All versions\")}\n </button>\n {lifecycle.steps[4].status !== \"complete\" && (\n <button\n type=\"button\"\n onClick={handleDeploy}\n disabled={deployDisabled}\n aria-disabled={deployDisabled}\n data-testid=\"node-lifecycle-deploy-button\"\n className=\"inline-flex items-center justify-center gap-2 rounded-md bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {deploying ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : visibility === \"private\" ? (\n <Building2 size={16} />\n ) : (\n <Rocket size={16} />\n )}\n {deployLabel}\n </button>\n )}\n </div>\n {blocker && lifecycle.steps[4].status !== \"complete\" && (\n <p\n className=\"max-w-sm text-xs text-text-secondary lg:text-right\"\n data-testid=\"node-lifecycle-deploy-blocker\"\n data-blocker={blocker}\n >\n {tr(blockerKey, blockerFallback)}\n </p>\n )}\n {lifecycle.steps[4].status === \"complete\" && (\n <p className=\"inline-flex items-center gap-1 text-sm font-medium text-status-success-text\">\n <CheckCircle2 size={16} />\n {stepReason(tr, lifecycle.steps[4])}\n </p>\n )}\n </div>\n </section>\n </PageLayout>\n );\n};\n\nexport default NodeLifecyclePage;\n"],"mappings":";;;;;;;;;;;;;;;;;AAmEA,IAAaC,IAA6B,KAIpCC,IAA6D;CACjE,QAAQ,CAAC,uCAAuC,YAAY;CAC5D,UAAU,CAAC,yCAAyC,mBAAmB;CACvE,MAAM,CAAC,qCAAqC,WAAW;CACvD,UAAU,CAAC,yCAAyC,UAAU;CAC9D,QAAQ,CAAC,uCAAuC,QAAQ;AAC1D,GAEMC,IAAuC;CAC3C,UAAU;CACV,WAAW;CACX,mBAAmB;CACnB,QAAQ;CACR,QAAQ;CACR,YAAY;CACZ,cAAc;CACd,sBAAsB;CACtB,UAAU;CACV,aAAa;CACb,SAAS;CACT,aAAa;CACb,cAAc;CACd,aAAa;CACb,OAAO;CACP,cAAc;CACd,UAAU;CACV,UAAU;CACV,UAAU;CACV,iBAAiB;CACjB,sBAAsB;CACtB,eAAe;CACf,YAAY;CACZ,OAAO;CACP,wBAAwB;CACxB,OAAO;CACP,oBAAoB;AACtB,GAEMC,IAGF;CACF,WAAW;EACT,MAAM,kBAACC,GAAD,EAAS,MAAM,GAAK,CAAA;EAC1B,KAAK;EACL,OAAO;CACT;CACA,UAAU;EACR,MAAM,kBAACC,GAAD,EAAW,MAAM,GAAK,CAAA;EAC5B,KAAK;EACL,OAAO;CACT;CACA,UAAU;EACR,MAAM,kBAACC,IAAD,EAAa,MAAM,GAAK,CAAA;EAC9B,KAAK;EACL,OAAO;CACT;CACA,OAAO;EACL,MAAM,kBAACC,GAAD,EAAQ,MAAM,GAAK,CAAA;EACzB,KAAK;EACL,OAAO;CACT;CACA,OAAO;EACL,MAAM,kBAACC,GAAD,EAAc,MAAM,GAAK,CAAA;EAC/B,KAAK;EACL,OAAO;CACT;AACF,GAEMC,KAAyE;CAC7E,MAAM;EACJ,OAAO;EACP,WAAW;CACb;CACA,MAAM;EACJ,OAAO;EACP,WAAW;CACb;CACA,MAAM;EACJ,OAAO;EACP,WAAW;CACb;CACA,SAAS;EACP,OAAO;EACP,WAAW;CACb;CACA,SAAS;EACP,OAAO;EACP,WAAW;CACb;AACF,GAEMC,KAAwD;CAC5D,cAAc,CACZ,gDACA,8DACF;CACA,UAAU,CACR,4CACA,6FACF;CACA,oBAAoB,CAClB,sDACA,+EACF;CACA,WAAW,CACT,6CACA,gCACF;CACA,qBAAqB,CACnB,uDACA,yCACF;CACA,eAAe,CACb,iDACA,yCACF;CACA,gBAAgB,CACd,kDACA,yDACF;CACA,aAAa,CACX,+CACA,uFACF;CACA,gBAAgB,CACd,kDACA,oDACF;AACF;AAEA,SAASC,GAAW,GAAQ,GAA6B;CACvD,OAAOC,EACL,kCAAkCC,EAAK,UACvCX,EAAaW,EAAK,WAAWA,EAAK,MACpC;AACF;AAEA,IAAMC,KAA6D,EACjE,SACA,eACI;CACJ,IAAMC,IACJ;CACF,QAAQF,EAAK,QAAb;EACE,KAAK,YACH,OACE,kBAAC,QAAD;GACE,WAAWG,EACTD,GACA,iFACF;GAEA,UAAA,kBAACE,GAAD,EAAO,MAAM,GAAK,CAAA;EACd,CAAA;EAEV,KAAK,UACH,OACE,kBAAC,QAAD;GACE,WAAWD,EACTD,GACA,2EACF;GAEA,UAAA,kBAACG,GAAD,EAAS,MAAM,GAAK,CAAA;EAChB,CAAA;EAEV,KAAK,eACH,OACE,kBAAC,QAAD;GACE,WAAWF,EACTD,GACA,wEACF;GAEA,UAAA,kBAACI,GAAD;IAAS,MAAM;IAAI,WAAU;GAAgB,CAAA;EACzC,CAAA;EAEV,KAAK,UACH,OACE,kBAAC,QAAD;GACE,WAAWH,EACTD,GACA,wEACF;GAEC,UAAAK,IAAQ;EACL,CAAA;EAEV,SACE,OACE,kBAAC,QAAD;GAAM,WAAWJ,EAAGD,GAAM,wCAAwC;GAC/D,UAAAK,IAAQ;EACL,CAAA;CAEZ;AACF,GAEMC,MAAqD,EACzD,cACA,YAEA,kBAAC,MAAD;CACE,WAAU;CACV,eAAY;CAEX,UAAAC,EAAU,MAAM,KAAK,GAAM,MAAU;EACpC,IAAM,CAACC,GAAKC,KAAYvB,EAAYY,EAAK,KACnCY,IACJZ,EAAK,WAAW,aACZ,6BACAA,EAAK,WAAW,WACd,2BACAA,EAAK,WAAW,iBAAiBA,EAAK,WAAW,WAC/C,0BACA;EACV,OACE,kBAAC,MAAD;GAEE,WAAU;GACV,aAAWA,EAAK;GAChB,eAAaA,EAAK;GAClB,gBAAcO,MAAUE,EAAU,eAAe,SAAS,KAAA;GAL5D,UAAA,CAOE,kBAACR,GAAD;IAAqB;IAAa;GAAQ,CAAA,GAC1C,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACGM,IAAQ;MAAE;MAAGR,EAAGW,GAAKC,CAAQ;KAC1B;IACN,CAAA,GAAA,kBAAC,QAAD;KAAM,WAAWR,EAAG,WAAWS,CAAI;KAAI,UAAAd,GAAWC,GAAIC,CAAI;IAAQ,CAAA,CAC/D;GACH,CAAA,CAAA;EAbG,GAAAA,EAAK,EAaR;CAER,CAAC;AACC,CAAA;AAGN,SAASa,EAAY,GAAQ,GAAsC;CACjE,IAAIC,EAAM,OAAO,WAAWA,EAAM,WAAW,UAAUA,EAAM,QAAQ;EACnE,IAAM,CAACC,GAAQC,KAASF,EAAM,OAAO,MAAM,GAAG;EAC9C,OAAOf,EACL,wCACA,kCACA;GAAE,QAAQgB,KAAU;GAAK,OAAOC,KAAS;EAAI,CAC/C;CACF;CAaA,OAZIF,EAAM,WAAW,iBACZf,EACL,wCACA,oCACF,IAEEe,EAAM,WAAW,wBACZf,EACL,+CACA,0CACF,IAEKe,EAAM;AACf;AAEA,IAAMG,MAAyD,EAC7D,cACA,YACI;CACJ,IAAM,CAACC,GAAUC,KAAeC,EAAS,EAAK,GACxCC,IAAQZ,EAAU,OAClBa,IACJD,EAAM,SAAS,YACfA,EAAM,SAAS,YACfA,EAAM,SAAS,YACXA,EAAM,aACN,CAAC,GACDE,IACJF,EAAM,SAAS,YACfA,EAAM,SAAS,YACfA,EAAM,SAAS,YACXA,EAAM,aACN;CAEN,OACE,kBAAC,WAAD;EACE,WAAU;EACV,eAAY;EAFd,UAAA;GAIE,kBAAC,MAAD;IAAI,WAAU;IACX,UAAAtB,EAAG,kCAAkC,QAAQ;GAC5C,CAAA;GACJ,kBAAC,MAAD;IAAI,WAAU;IACX,UAAAU,EAAU,OAAO,KAAK,MAAU;KAC/B,IAAMe,IAAOlC,EAAWwB,EAAM,KACxBW,IAAQ7B,GAAYkB,EAAM,SAC1BY,IAASb,EAAYd,GAAIe,CAAK;KACpC,OACE,kBAAC,MAAD;MAEE,WAAU;MACV,cAAYA,EAAM;MAClB,eAAaA,EAAM;MAJrB,UAAA,CAME,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,kBAAC,QAAD;SAAM,WAAU;SAAuB,UAAAU,EAAK;QAAW,CAAA;QACvD,kBAAC,QAAD;SAAM,WAAU;SAAhB,UAAA,CACGzB,EAAGyB,EAAK,KAAKA,EAAK,KAAK,GACvBE,KACC,kBAAC,QAAD;UAAM,WAAU;UACb,UAAAA;SACG,CAAA,CAEJ;;QACN,kBAAC,QAAD;SACE,WAAWvB,EACT,+EACAsB,EAAM,SACR;SAJF,UAAA,CAMGX,EAAM,WAAW,aAChB,kBAACR,GAAD;UAAS,MAAM;UAAI,WAAU;SAAgB,CAAA,GAE9CP,EACC,iCAAiCe,EAAM,UACvCW,EAAM,KACR,CACI;;OACH;MACJ,CAAA,GAAAX,EAAM,OAAO,SAAS,KACrB,kBAAC,MAAD;OAAI,WAAU;OACX,UAAAA,EAAM,OAAO,KAAK,GAAO,MACxB,kBAAC,MAAD;QAEE,WAAU;QAFZ,UAAA,CAIGa,EAAM,QACL,kBAAC,QAAD;SAAM,WAAU;SACb,UAAAA,EAAM;QACH,CAAA,GAER,kBAAC,QAAD;SACE,WACEA,EAAM,aAAa,UACf,2BACA;SAGL,UAAAA,EAAM;QACH,CAAA,CACJ;OAjBG,GAAA,GAAGA,EAAM,KAAK,GAAGA,EAAM,KAAK,GAAGpB,GAiBlC,CACL;MACC,CAAA,CAEJ;KAvDG,GAAAO,EAAM,EAuDT;IAER,CAAC;GACC,CAAA;GACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,QAAD,EAAA,UACGS,IACGxB,EACE,yCACA,2BACA,EAAE,MAAM,IAAI,KAAKwB,CAAU,CAAC,CAAC,eAAe,EAAE,CAChD,IACAxB,EACE,4CACA,0BACF,EACA,CAAA,GACLuB,EAAW,SAAS,KACnB,kBAAC,UAAD;MACE,MAAK;MACL,WAAU;MACV,eAAeH,GAAa,MAAU,CAACS,CAAK;MAC5C,iBAAeV;MAJjB,UAAA,CAMGA,IACGnB,EAAG,wCAAwC,gBAAgB,IAC3DA,EAAG,wCAAwC,gBAAgB,GACnD8B,EAAXX,IAAYY,IAA0BC,GAA3B,EAAW,MAAM,GAAK,CAA4B,CACxD;KAEP,CAAA,CAAA;IACJ,CAAA,GAAAb,KACC,kBAAC,MAAD;KACE,WAAU;KACV,eAAY;KAEX,UAAAI,EAAW,KAAK,GAAI,MACnB,kBAAC,MAAD;MAAgC,WAAU;MAA1C,UAAA;OACGU,EAAG,WAAW,SACb,kBAACC,GAAD;QACE,MAAM;QACN,WAAU;OACX,CAAA,IACCD,EAAG,WAAW,SAChB,kBAACE,GAAD;QACE,MAAM;QACN,WAAU;OACX,CAAA,IAED,kBAAC7B,GAAD;QACE,MAAM;QACN,WAAU;OACX,CAAA;OAEH,kBAAC,QAAD;QAAM,WAAU;QAAqB,UAAA2B,EAAG;OAAW,CAAA;OACnD,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SACGA,EAAG;SAAO;SAAIA,EAAG;SAAW;QACzB;;QACJA,EAAG,SAASA,EAAG,WACf,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAA,EAAG,SAASA,EAAG;OACZ,CAAA;MAEN;KA1BK,GAAA,GAAGA,EAAG,KAAK,GAAGzB,GA0BnB,CACL;IACC,CAAA,CAEH;;EACE;;AAEb,GAEM4B,MAAsD,EAC1D,aACA,YACI;CACJ,IAAM,CAACC,GAAQC,KAAajB,EAAS,EAAK,GACpCkB,IAAOC,QACJC,IAAW,KAAK,UAAUA,GAAU,MAAM,CAAC,IAAI,IACtD,CAACA,CAAQ,CACX,GACMC,IAAQH,IAAOA,EAAK,MAAM,IAAI,IAAI,CAAC;CAYzC,OACE,kBAAC,WAAD;EACE,WAAU;EACV,eAAY;EAFd,UAAA,CAIE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;IAAd,UAAA;KACGvC,EAAG,2CAA2C,kBAAkB;KAAG;KACpE,kBAAC,QAAD;MAAM,WAAU;MAAkC,UAAA;KAE5C,CAAA;IACJ;GACH,CAAA,GAAAuC,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS,YAzBY;KAC7B,IAAI;MAGF,AAFA,MAAM,UAAU,UAAU,UAAUA,CAAI,GACxCD,EAAU,EAAI,GACd,OAAO,iBAAiBA,EAAU,EAAK,GAAG,GAAI;KAChD,QAAQ;MACN,EAAU,EAAK;KACjB;IACF;IAkBU,WAAU;IAHZ,UAAA,CAKYR,EAATO,IAAUhC,IAAsBsC,GAAvB,EAAO,MAAM,GAAK,CAAqB,GAChDN,IACGrC,EAAG,oBAAoB,QAAQ,IAC/BA,EAAG,kBAAkB,MAAM,CACzB;GAEP,CAAA,CAAA;EACJ,CAAA,GAAA0C,EAAM,SAAS,IACd,kBAAC,OAAD;GAAK,WAAU;GACZ,UAAAA,EAAM,KAAK,GAAM,MAChB,kBAAC,OAAD;IAAiB,WAAU;IAA3B,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KACb,UAAAlC,IAAQ;IACL,CAAA,GACN,kBAAC,QAAD;KAAM,WAAU;KAAoC,UAAAoC;IAAW,CAAA,CAC5D;GALK,GAAApC,CAKL,CACN;EACE,CAAA,IAEL,kBAAC,KAAD;GAAG,WAAU;GACV,UAAAR,EACC,sCACA,mEACF;EACC,CAAA,CAEE;;AAEb,GAEa6C,UAA8B;CACzC,IAAM7C,IAAK8C,EAAM,GACX,EAAE,UAAO,iBAAcC,GAG1B,GACG,EACJ,aACA,aACA,gBACA,yBACA,eACA,yBACEC,GAAa,GACX,EAAE,SAASC,MAAeC,EAC9BC,EAAsB,mBACxB,GACM,EAAE,SAASC,MAAcF,EAC7BC,EAAsB,kBACxB,GAEM,EAAE,SAAM,aAAS,UAAO,iBAAc,mBAC1CE,EAAuB;EACrB,WAAW,EAAE,IAAIC,KAAS,GAAG;EAC7B,MAAM,CAACA;EACP,aAAa;CACf,CAAC,GAEGC,IAAMC,GAAM,aACZC,IAA+CjB,QAEjDe,GAAK,UAAU,OAAO,KACnB,MAAqDG,EAAK,IAC7D,KAAK,CAAC,GACR,CAACH,GAAK,QAAQ,CAChB,GACMI,IAAUF,EAAS,MAAM,MAAMG,EAAE,OAAOC,CAAS,KAAK,MACtDC,IAAgBP,GAAK,cAAc,MACnCQ,IAAaC,GAAiBF,CAAa,GAE3CpD,IAAY8B,QACTmB,IAAUM,GAAoBN,GAASI,CAAU,IAAI,MAC5D,CAACJ,GAASI,CAAU,CACtB,GAGMG,IAAOxD,GAAW,QAAQ;CAChC,SAAgB;EACd,IAAKwD,GAEL,OADAC,EAAa/E,CAA0B,SAC1BgF,EAAY;CAC3B,GAAG;EAACF;EAAMC;EAAcC;CAAW,CAAC;CAEpC,IAAMC,KAAsBZ,EAAS,MAClC,MAAMG,EAAE,OAAOC,KAAaD,EAAE,WAAW,gBAC5C,GAIM,CAACU,MAAiBC,GAAoC;EAC1D,gBAAgB,CAAC,gBAAgB;EACjC,qBAAqB;CACvB,CAAC,GACK,CAACC,IAAiB,EAAE,SAASC,QACjCC,EAAqC,EACnC,gBAAgB,CAAC,gBAAgB,EACnC,CAAC,GACG,CAACC,IAAuB,EAAE,SAASC,QACvCC,EAAmD,EACjD,gBAAgB,CAAC,gBAAgB,EACnC,CAAC,GACG,EACJ,QAAQC,IACR,cACA,cACA,OAAOC,MACLC,GACFC,GACAC,IACAC,GACAC,CACF,GACMC,IAAcC,GAAyB,IAAI,GAC3C,CAACC,GAAaC,KAAkBnE,EAAwB,IAAI,GAC5D,CAACoE,GAAeC,KAAoBrE,EAAwB,IAAI,GAChE,CAACsE,IAAUC,KAAevE,EAAS,EAAK,GAIxC,CAACwE,GAAkBC,KAAuBzE,EAAS,EAAK,GAExD0E,IAAKC,IACR,MAAiBC,IAAW,GAAGC,IAAWC,GAAM,GACjD,CAACF,GAAUC,CAAQ,CACrB,GAEME,KAAwB,OAC5B,MACG;EACH,IAAMC,IAAOC,EAAM,OAAO,QAAQ;EAElC,IADA,EAAM,OAAO,QAAQ,IAChBD,KAAS1C,GAGd;OAFA6B,EAAe,IAAI,GACnBE,EAAiB,IAAI,GACjB,CAACW,EAAK,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,GAC1C,EACErG,EACE,mCACA,oCACF,CACF;QAGF;MAAoB,EAAI;IACxB,IAAI;KACF,IAAMuG,IAAW,MAAMzB,GAAcuB,CAAI,GACnCG,IAAS,MAAMlC,GAAc,EACjC,WAAW;MACT,IAAIX,EAAQ;MACZ,OAAO;OACL,YAAY4C,EAAS;OACrB,eAAeA,EAAS,UAAU,KAAA;OAClC,oBAAoBpB,KAAe,KAAA;OACnC,aAAa,OAAOkB,EAAK,IAAI;MAC/B;KACF,EACF,CAAC;KACD,IAAIG,EAAO,SAAS,CAACA,EAAO,MAAM,0BAChC,MACEA,EAAO,SACH,MACFxG,EACE,wCACA,8CACF,CACF;KAGJ,EACEA,EACE,oCACA,6DACF,CACF;IACF,SAASyG,GAAK;KACZ,EACEA,aAAe,QACXA,EAAI,UACJzG,EACE,wCACA,8CACF,CACN;IACF,UAAU;KACR,EAAoB,EAAK;IAC3B;GA1CwB;EADxB;CA4CF,GAEM0G,KACJ3C,MAAe,WAAWR,GAAK,WAAW,aAEtCoD,IACJhD,KAAWjD,IACPkG,GAAc;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,IACD,YAEAC,KAAe,YAAY;EAC/B,IAAI,GAAClD,KAAWgD,KAAWd,IAG3B;OAFAL,EAAe,IAAI,GACnBE,EAAiB,IAAI,GACjBgB,IAGF,EAAG,SAASpD,EAAM,SAAS;QAG7B,IAAI;IACF,IAAIS,MAAe,WAAW;KAC5B,IAAI,CAACoB,GAAa;KAClB,IAAMqB,IAAS,MAAM7B,GAAsB,EACzC,WAAW;MAAE,IAAIhB,EAAQ;MAAI;KAAY,EAC3C,CAAC;KACD,IACE6C,EAAO,SACP,CAACA,EAAO,MAAM,yCAEd,MACEA,EAAO,SACH,MACFxG,EACE,gDACA,oDACF,CACF;KAGJ,EACEA,EACE,6CACA,yFACF,CACF;IACF,OAAO;KACL,IAAMwG,IAAS,MAAMhC,GAAgB,EACnC,WAAW,EAAE,IAAIb,EAAQ,GAAG,EAC9B,CAAC;KACD,IAAI6C,EAAO,SAAS,CAACA,EAAO,MAAM,2BAChC,MACEA,EAAO,SACH,MACFxG,EACE,kCACA,qCACF,CACF;KAGJ,EACEA,EACE,qCACA,wFACF,CACF;IACF;GACF,SAASyG,GAAK;IACZ,EACEA,aAAe,QACXA,EAAI,UACJzG,EAAG,wCAAwC,eAAe,CAChE;GACF;EAvDA;CAwDF,GAEM8G,KAAgB,YAAY;EAChC,IAAKnD,GACL,IAAI;GAGF,AAFA,MAAM,UAAU,UAAU,UAAUA,EAAQ,EAAE,GAC9CiC,EAAY,EAAI,GAChB,OAAO,iBAAiBA,EAAY,EAAK,GAAG,GAAI;EAClD,QAAQ;GACN,EAAY,EAAK;EACnB;CACF,GAEMmB,IAAe,GAAGb,EAAS,QAAQ5C,EAAM;CAE/C,IAAI0D,MAAW,CAACxD,GACd,OAAO,kBAACyD,GAAD,CAAe,CAAA;CAGxB,IAAIC,KAAS,CAAC1D,GACZ,OACE,kBAAC2D,GAAD;EACE,OAAOnH,EAAG,iCAAiC,uBAAuB;EAClE,UAAU+G;EACV,WAAW/G,EAAG,4BAA4B,kBAAkB;EAE5D,UAAA,kBAACoH,GAAD;GACE,OAAOpH,EACL,sCACA,6BACF;GACA,aAAakH,EAAM;EACpB,CAAA;CACS,CAAA;CAIhB,IAAI,CAAC3D,KAAO,CAACI,KAAW,CAACjD,KAAa6C,EAAI,YAAY,QACpD,OACE,kBAAC4D,GAAD;EACE,OAAOnH,EAAG,iCAAiC,uBAAuB;EAClE,UAAU+G;EACV,WAAW/G,EAAG,4BAA4B,kBAAkB;EAE5D,UAAA,kBAACoH,GAAD;GACE,OAAOpH,EACL,oCACA,+BACF;GACA,aAAaA,EACX,+CACA,0GACF;EACD,CAAA;CACS,CAAA;CAIhB,IAAMqH,IAAS1D,EAAQ,OAAO,YAAY,GACpC2D,KAAWD,MAAW,WAAWA,MAAW,YAC5CE,KAAY9C,MAAcG,IAC1B4C,KAAiB,EAAQb,KAAYY,MAAa1B,GAClD,CAAC4B,IAAYC,MAAmBf,IAClC7G,GAAa6G,KACb,CAAC,IAAI,EAAE,GACLgB,KACJ5D,MAAe,YACX/D,EAAG,yCAAyC,2BAA2B,IACvE0G,KACE1G,EACE,2CACA,8BACF,IACAA,EAAG,yCAAyC,mBAAmB;CAEvE,OACE,kBAACmH,GAAD;EACE,OACE,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IACb,UAAAnH,EAAG,iCAAiC,aAAa;GAC9C,CAAA,GACN,kBAAC,QAAD,EAAA,UAAA;IACGA,EAAG,iCAAiC,uBAAuB;IAC3D;IACD,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACGuD,EAAI;MAAK;MAAGI,EAAQ;KACjB;;GACF,EAAA,CAAA,CACF;;EAER,UAAUoD;EACV,WAAW/G,EAAG,4BAA4B,kBAAkB;EAC5D,SAASA,EACP,mCACA,wLACF;EACA,WAAA;EArBF,UAAA;GAuBE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,QAAD,EAAA,UAAOA,EAAG,qCAAqC,YAAY,EAAQ,CAAA;KACnE,kBAAC,QAAD;MACE,WAAU;MACV,eAAY;MAEX,UAAA2D,EAAQ;KACL,CAAA;KACN,kBAAC,UAAD;MACE,MAAK;MACL,SAASmD;MACT,cAAY9G,EACV,yCACA,iBACF;MACA,WAAU;MAET,UAAW8B,EAAX6D,KAAYtF,IAAsBsC,GAAvB,EAAO,MAAM,GAAK,CAAqB;KAC7C,CAAA;IACL;;GAEJ4C,KACC,kBAAC,OAAD;IACE,MAAK;IACL,WAAU;IAFZ,UAAA,CAIE,kBAACqC,IAAD;KAAe,MAAM;KAAI,WAAU;IAAmB,CAAA,GACrDrC,CACE;;GAENE,KACC,kBAAC,OAAD;IACE,MAAK;IACL,WAAU;IAFZ,UAAA,CAIE,kBAACvD,GAAD;KAAc,MAAM;KAAI,WAAU;IAAmB,CAAA,GACpDuD,CACE;;GAGP,kBAAC,WAAD;IAAS,WAAU;IAAnB,UAAA,CACE,kBAAChF,IAAD;KAAoB;KAAe;IAAK,CAAA,GACvC4G,MAAW,cAAc1D,EAAQ,eAChC,kBAAC,KAAD;KAAG,WAAU;KAAb,UAAA;MACG3D,EAAG,uCAAuC,iBAAiB;MAAG;MAC9D2D,EAAQ;KACR;IAEE,CAAA,CAAA;;GAET,kBAAC,WAAD;IAAS,WAAU;IAAnB,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAACkE,IAAD;MAAQ,MAAM;MAAI,WAAU;KAAuB,CAAA,GACnD,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAlE,EAAQ,aACL3D,EACE,2CACA,kBACF,IACAA,EACE,0CACA,gBACF;OACA,CAAA;OACN,kBAAC,QAAD;QAAM,WAAU;QACb,UAAA2D,EAAQ,aACL,CACEA,EAAQ,eACN3D,EAAG,uCAAuC,eAAe,EACvD,MAAM,KAAK,IACT,GACA,KAAK,MAAM,OAAO2D,EAAQ,WAAW,IAAI,IAAI,CAC/C,EACF,CAAC,GACHA,EAAQ,eACN,UAAUA,EAAQ,YAAY,MAAM,GAAG,EAAE,EAAE,EAC/C,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,KAAK,IACb3D,EACE,uCACA,sFACF;OACA,CAAA;OACL8H,KACC,kBAAC,QAAD;QAAM,WAAU;QACb,UAAA9H,EACC,qCACA,4BACA,EACE,UAAU,KAAK,MAAM+H,EAAQ,EAC/B,CACF;OACI,CAAA;OAEPhD,KACC,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAA;OACG,CAAA;MAEL;KACF,CAAA,CAAA;IACJ,CAAA,GAAAuC,MAAYlE,KACX,kBAAAjE,IAAA,EAAA,UAAA,CACE,kBAAC,SAAD;KACE,KAAKkG;KACL,MAAK;KACL,QAAO;KACP,WAAU;KACV,eAAY;KACZ,UAAUe;IACX,CAAA,GACD,kBAAC,UAAD;KACE,MAAK;KACL,UAAU0B,KAAajC;KACvB,eAAeR,EAAY,SAAS,MAAM;KAC1C,WAAU;KAJZ,UAAA,CAMGyC,IACC,kBAACvH,GAAD;MAAS,MAAM;MAAI,WAAU;KAAgB,CAAA,IAE7C,kBAACsH,IAAD,EAAQ,MAAM,GAAK,CAAA,GAEpBlE,EAAQ,aACL3D,EAAG,sCAAsC,aAAa,IACtDA,EAAG,qCAAqC,YAAY,CAClD;IACR,CAAA,CAAA,EAAA,CAAA,CAEG;;GAET,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAACkB,IAAD;KAAwB;KAAe;IAAK,CAAA,GAC5C,kBAACkB,IAAD;KAAiB,UAAUuB,EAAQ;KAAc;IAAK,CAAA,CACnD;;GAEL,kBAAC,WAAD;IACE,WAAU;IACV,eAAY;IAFd,UAAA,CAIE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,kBAAC,QAAD;OAAM,WAAU;OACb,UAAA3D,EAAG,sCAAsC,YAAY;MAClD,CAAA;MACN,kBAAC,OAAD;OACE,MAAK;OACL,cAAYA,EAAG,sCAAsC,YAAY;OACjE,WAAU;OAGR,UAAA,CACE;QACE;QACA,kBAACiI,IAAD,EAAc,MAAM,GAAK,GAAf,GAAe;QACzBjI,EAAG,mCAAmC,mBAAmB;OAC3D,GACA;QACE;QACA,kBAACkI,IAAD,EAAe,MAAM,GAAK,GAAf,GAAe;QAC1BlI,EAAG,iCAAiC,iBAAiB;OACvD,CACF,CAAC,CACD,KAAK,CAAC6B,GAAOsG,GAAMC,OAAW;QAC9B,IAAMC,IAAWtE,MAAelC;QAChC,OACE,kBAAC,QAAD;SAEE,MAAK;SACL,gBAAcwG;SACd,iBAAe,CAACA;SAChB,mBAAiBxG;SACjB,WAAWzB,EACT,oDACAiI,IACI,+DACA,qBACN;SAXF,UAAA,CAaGF,GACAC,CACG;QAdC,GAAAvG,CAcD;OAEV,CAAC;MACE,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;OAAb,UAAA;QACGkC,MAAe,YACZ/D,EACE,uCACA,kIACF,IACAA,EACE,qCACA,kGACF;QAAG;QACP,kBAAC,UAAD;SACE,MAAK;SACL,WAAU;SACV,eAAe+F,EAAG,SAASzC,EAAM,MAAM;SAEtC,UAAAtD,EACC,4CACA,mBACF;QACM,CAAA;OACP;;KACA;IACL,CAAA,GAAA,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe+F,EAAG,SAASzC,EAAM,UAAU;QAC3C,WAAU;QAHZ,UAAA,CAKE,kBAACgF,IAAD,EAAU,MAAM,GAAK,CAAA,GACpBtI,EAAG,uCAAuC,cAAc,CACnD;OACP,CAAA,GAAAU,EAAU,MAAM,EAAE,CAAC,WAAW,cAC7B,kBAAC,UAAD;QACE,MAAK;QACL,SAASmG;QACT,UAAUW;QACV,iBAAeA;QACf,eAAY;QACZ,WAAU;QANZ,UAAA,CAQGD,KACC,kBAAChH,GAAD;SAAS,MAAM;SAAI,WAAU;QAAgB,CAAA,IAE7CuB,EADEiC,MAAe,YAChBwE,KAEAC,IAFD,EAAW,MAAM,GAAK,CAEH,GAEpBb,EACK;OAEP,CAAA,CAAA;;MACJhB,KAAWjG,EAAU,MAAM,EAAE,CAAC,WAAW,cACxC,kBAAC,KAAD;OACE,WAAU;OACV,eAAY;OACZ,gBAAciG;OAEb,UAAA3G,EAAGyH,IAAYC,EAAe;MAC9B,CAAA;MAEJhH,EAAU,MAAM,EAAE,CAAC,WAAW,cAC7B,kBAAC,KAAD;OAAG,WAAU;OAAb,UAAA,CACE,kBAACwB,GAAD,EAAc,MAAM,GAAK,CAAA,GACxBnC,GAAWC,GAAIU,EAAU,MAAM,EAAE,CACjC;;KAEF;IACE,CAAA,CAAA;;EACC;;AAEhB"}
|
|
@@ -100,9 +100,20 @@ export type CreateApplicationVersionInput = {
|
|
|
100
100
|
manifest?: Record<string, unknown> | null | undefined;
|
|
101
101
|
maxPlatformVersion?: string | null | undefined;
|
|
102
102
|
minPlatformVersion?: string | null | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* wspace-files-svc File id of the uploaded package, captured with packageUrl
|
|
105
|
+
* at upload time. Lets the service fetch fresh download URLs from the
|
|
106
|
+
* canonical file owner instead of re-signing S3 URLs itself (BOFF-5311).
|
|
107
|
+
*/
|
|
108
|
+
packageFileId?: string | null | undefined;
|
|
103
109
|
packageHash?: string | null | undefined;
|
|
104
110
|
packageSize?: string | null | undefined;
|
|
105
111
|
packageUrl?: string | null | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Workspace that owns the files-svc File referenced by packageFileId.
|
|
114
|
+
* Required together with packageFileId for the files-svc download-URL path.
|
|
115
|
+
*/
|
|
116
|
+
packageWorkspaceId?: string | null | undefined;
|
|
106
117
|
releaseNotes?: string | null | undefined;
|
|
107
118
|
requiredScopes?: Array<string> | null | undefined;
|
|
108
119
|
version: string;
|
|
@@ -296,12 +307,22 @@ export type UpdateApplicationVersionInput = {
|
|
|
296
307
|
manifest?: Record<string, unknown> | null | undefined;
|
|
297
308
|
maxPlatformVersion?: string | null | undefined;
|
|
298
309
|
minPlatformVersion?: string | null | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* Immutable once status is pending_review or published.
|
|
312
|
+
* Must match the packageUrl being replaced (same upload).
|
|
313
|
+
*/
|
|
314
|
+
packageFileId?: string | null | undefined;
|
|
299
315
|
/** Immutable once status is pending_review or published. */
|
|
300
316
|
packageHash?: string | null | undefined;
|
|
301
317
|
/** Immutable once status is pending_review or published. */
|
|
302
318
|
packageSize?: string | null | undefined;
|
|
303
319
|
/** Immutable once status is pending_review or published. */
|
|
304
320
|
packageUrl?: string | null | undefined;
|
|
321
|
+
/**
|
|
322
|
+
* Immutable once status is pending_review or published.
|
|
323
|
+
* Must match the packageUrl being replaced (same upload).
|
|
324
|
+
*/
|
|
325
|
+
packageWorkspaceId?: string | null | undefined;
|
|
305
326
|
releaseNotes?: string | null | undefined;
|
|
306
327
|
/** Immutable once status is pending_review or published. */
|
|
307
328
|
requiredScopes?: Array<string> | null | undefined;
|