@burdenoff/microfe-devportal 2026.916.8 → 2026.917.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationVersionsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationVersionsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useParams } from \"react-router\";\nimport {\n Plus,\n Package,\n CheckCircle,\n XCircle,\n Clock,\n Archive,\n Loader2,\n AlertCircle,\n Upload,\n Send,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { InputField, TextareaField } from \"../components/FormField\";\nimport { MarkdownEditor } from \"../components/MarkdownEditor\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { format } from \"date-fns\";\nimport {\n useGetApplicationQuery,\n useGetApplicationVersionsQuery,\n useCreateApplicationVersionMutation,\n useUpdateApplicationVersionMutation,\n usePublishApplicationVersionMutation,\n useDeprecateApplicationVersionMutation,\n useApproveApplicationVersionMutation,\n useRejectApplicationVersionMutation,\n type ApplicationVersionFieldsFragment,\n} from \"../hooks\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { usePackageUpload } from \"../hooks/usePackageUpload\";\n\nexport const ApplicationVersionsPage: FC = () => {\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 const { allowed: canCreate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_CREATE,\n );\n const { allowed: canPublish } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_PUBLISH,\n );\n const { allowed: canDeprecate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_DEPRECATE,\n );\n const { appId } = useParams<{ appId: string }>();\n const { workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken } =\n useDevportal();\n const {\n upload: uploadZip,\n uploading: zipUploading,\n progress: zipProgress,\n error: zipUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n );\n const zipInputRef = useRef<HTMLInputElement>(null);\n const manifestInputRef = useRef<HTMLInputElement>(null);\n const editZipInputRef = useRef<HTMLInputElement>(null);\n const editManifestInputRef = useRef<HTMLInputElement>(null);\n const [manifestFileName, setManifestFileName] = useState<string | null>(null);\n const [editManifestFileName, setEditManifestFileName] = useState<\n string | null\n >(null);\n const [showCreateDialog, setShowCreateDialog] = useState(false);\n const [editDialog, setEditDialog] = useState<{\n versionId: string;\n version: string;\n hasExistingZip: boolean;\n newPackageUrl: string;\n newPackageSize: string;\n manifestJson: string;\n originalManifestJson: string;\n releaseNotes: string;\n changelog: string;\n } | null>(null);\n const [newVersion, setNewVersion] = useState({\n version: \"\",\n releaseNotes: \"\",\n changelog: \"\",\n packageUrl: \"\",\n packageSize: \"\",\n manifestJson: \"\",\n requiredScopes: \"\",\n });\n const [actionError, setActionError] = useState<string | null>(null);\n const [actionSuccess, setActionSuccess] = useState<string | null>(null);\n const [createDialogError, setCreateDialogError] = useState<string | null>(\n null,\n );\n const [editDialogError, setEditDialogError] = useState<string | null>(null);\n const [selectedVersionIds, setSelectedVersionIds] = useState<Set<string>>(\n new Set(),\n );\n const [rejectDialog, setRejectDialog] = useState<{\n versionId: string;\n version: string;\n } | null>(null);\n const [rejectReason, setRejectReason] = useState(\"\");\n\n const handleManifestFileUpload = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (evt) => {\n const text = evt.target?.result;\n if (typeof text === \"string\") {\n setNewVersion((prev) => ({ ...prev, manifestJson: text }));\n setManifestFileName(file.name);\n }\n };\n reader.readAsText(file);\n // reset so re-uploading same file triggers onChange\n e.target.value = \"\";\n },\n [],\n );\n const [bulkAction, setBulkAction] = useState<\"publish\" | \"deprecate\" | null>(\n null,\n );\n\n const { data: appData } = useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-first\",\n });\n const isWorkflowApp = appData?.application?.appType === \"WORKFLOW\";\n const isNodeApp = appData?.application?.appType === \"NODE\";\n // Manifest-only types (no zip): Workflow plus its sibling types Parser/Widget/Dashboard.\n const isManifestOnlyType = [\n \"WORKFLOW\",\n \"PARSER\",\n \"WIDGET\",\n \"DASHBOARD\",\n ].includes(appData?.application?.appType ?? \"\");\n const isIntegrationApp = !isManifestOnlyType && !isNodeApp;\n\n // App-level readiness checks — version submission is blocked until the app is ready\n const app = appData?.application;\n const pricingDetailsRaw = (app?.pricingDetails ?? {}) as Record<\n string,\n unknown\n >;\n const pricingDone =\n app?.pricingType === \"FREE\" ||\n (app?.pricingType === \"PAID\" &&\n typeof pricingDetailsRaw.price === \"number\" &&\n (pricingDetailsRaw.price as number) > 0);\n const storeDone =\n !!app?.shortDescription?.trim() &&\n !!app?.privacyPolicyUrl?.trim() &&\n !!app?.termsOfServiceUrl?.trim();\n const appReadyForSubmission = pricingDone && storeDone;\n const appReadinessBlockers: string[] = [\n ...(!storeDone\n ? [\n \"Complete your store listing (short description, privacy policy, terms of service)\",\n ]\n : []),\n ...(!pricingDone ? [\"Set pricing in the Pricing tab\"] : []),\n ];\n\n useEffect(() => {\n const name = appData?.application?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, appData?.application?.name]);\n\n // Query\n const {\n data: versionsData,\n loading: versionsLoading,\n error: versionsError,\n } = useGetApplicationVersionsQuery({\n variables: { applicationId: appId! },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n // Mutations\n const [createVersion, { loading: creating }] =\n useCreateApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [updateVersion, { loading: updating }] =\n useUpdateApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [publishVersion] = usePublishApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [deprecateVersion] = useDeprecateApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [approveVersion] = useApproveApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [rejectVersion] = useRejectApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const versions: ApplicationVersionFieldsFragment[] = useMemo(\n () =>\n versionsData?.application?.versions?.edges?.map(\n (edge: { node: ApplicationVersionFieldsFragment }) => edge.node,\n ) ?? [],\n [versionsData?.application?.versions],\n );\n\n const selectedVersions = useMemo(\n () => versions.filter((version) => selectedVersionIds.has(version.id)),\n [versions, selectedVersionIds],\n );\n const publishableVersions = useMemo(\n () =>\n selectedVersions.filter(\n (version) =>\n version.status === \"draft\" || version.status === \"rejected\",\n ),\n [selectedVersions],\n );\n // Only one version should be in the admin review queue at a time — otherwise\n // an admin can't tell which pending version a developer actually wants\n // reviewed. This is a UI-only guard (no backend change): once a version is\n // pending_review, block submitting another until it's approved or rejected.\n const hasPendingVersion = useMemo(\n () => versions.some((version) => version.status === \"pending_review\"),\n [versions],\n );\n const deprecatableVersions = useMemo(\n () =>\n selectedVersions.filter(\n (version) =>\n version.status?.toUpperCase() === \"PUBLISHED\" && !version.isLatest,\n ),\n [selectedVersions],\n );\n const allVisibleSelected =\n versions.length > 0 &&\n versions.every((version) => selectedVersionIds.has(version.id));\n const partiallySelected =\n versions.some((version) => selectedVersionIds.has(version.id)) &&\n !allVisibleSelected;\n\n const handleCreate = async () => {\n if (!appId || !newVersion.version.trim()) return;\n setCreateDialogError(null);\n\n let parsedManifest: Record<string, unknown> | undefined;\n if (isManifestOnlyType) {\n if (!newVersion.manifestJson.trim()) {\n setCreateDialogError(\n isWorkflowApp\n ? \"Workflow Definition (JSON) is required — paste the {nodes, edges} object.\"\n : \"Manifest (JSON) is required.\",\n );\n return;\n }\n try {\n parsedManifest = JSON.parse(newVersion.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setCreateDialogError(\n isWorkflowApp\n ? \"Invalid JSON in Workflow Definition — please check your input.\"\n : \"Invalid JSON in Manifest — please check your input.\",\n );\n return;\n }\n } else if (isNodeApp) {\n if (!newVersion.packageUrl) {\n setCreateDialogError(\n \"Package zip is required for Node versions — upload a .zip file before creating.\",\n );\n return;\n }\n if (!newVersion.manifestJson.trim()) {\n setCreateDialogError(\n \"manifest.json is required for Node versions — upload or paste your manifest before creating.\",\n );\n return;\n }\n try {\n parsedManifest = JSON.parse(newVersion.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setCreateDialogError(\n \"Invalid JSON in manifest — please check your input.\",\n );\n return;\n }\n } else if (newVersion.manifestJson.trim()) {\n try {\n parsedManifest = JSON.parse(newVersion.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setCreateDialogError(\n \"Invalid JSON in manifest — please check your input.\",\n );\n return;\n }\n }\n\n const requiredScopes =\n isIntegrationApp && newVersion.requiredScopes.trim()\n ? newVersion.requiredScopes\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n try {\n await createVersion({\n variables: {\n applicationId: appId,\n input: {\n version: newVersion.version,\n releaseNotes: newVersion.releaseNotes || undefined,\n changelog: newVersion.changelog || undefined,\n packageUrl: newVersion.packageUrl || undefined,\n packageSize: newVersion.packageSize || undefined,\n manifest: parsedManifest,\n requiredScopes,\n },\n },\n });\n setShowCreateDialog(false);\n setManifestFileName(null);\n setNewVersion({\n version: \"\",\n releaseNotes: \"\",\n changelog: \"\",\n packageUrl: \"\",\n packageSize: \"\",\n manifestJson: \"\",\n requiredScopes: \"\",\n });\n setActionSuccess(\n tr(\"devportal.versionCreatedSuccess\", \"Version created successfully\"),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionCreateFailed\", \"Failed to create version\"),\n );\n }\n };\n\n const handleZipUpload = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n e.target.value = \"\";\n try {\n const result = await uploadZip(file);\n setNewVersion((prev) => ({\n ...prev,\n packageUrl: result.downloadUrl,\n packageSize: String(file.size),\n }));\n } catch {\n // error shown via zipUploadError prop\n }\n },\n [uploadZip],\n );\n\n const handleEditZipUpload = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n e.target.value = \"\";\n try {\n const result = await uploadZip(file);\n setEditDialog((prev) =>\n prev\n ? {\n ...prev,\n newPackageUrl: result.downloadUrl,\n newPackageSize: String(file.size),\n }\n : prev,\n );\n } catch {\n // error shown via zipUploadError prop\n }\n },\n [uploadZip],\n );\n\n const handleEditManifestUpload = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (evt) => {\n const text = evt.target?.result;\n if (typeof text === \"string\") {\n setEditDialog((prev) =>\n prev ? { ...prev, manifestJson: text } : prev,\n );\n setEditManifestFileName(file.name);\n }\n };\n reader.readAsText(file);\n e.target.value = \"\";\n },\n [],\n );\n\n const handleEditSave = async () => {\n if (!editDialog) return;\n setEditDialogError(null);\n\n const manifestChanged =\n editDialog.manifestJson.trim() !== editDialog.originalManifestJson.trim();\n\n let parsedManifest: Record<string, unknown> | undefined;\n if (manifestChanged && editDialog.manifestJson.trim()) {\n try {\n parsedManifest = JSON.parse(editDialog.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setEditDialogError(\n \"Invalid JSON in manifest — please check your input.\",\n );\n return;\n }\n }\n\n const input: {\n releaseNotes?: string;\n changelog?: string;\n packageUrl?: string;\n packageSize?: string;\n manifest?: Record<string, unknown>;\n } = {};\n\n if (editDialog.releaseNotes.trim())\n input.releaseNotes = editDialog.releaseNotes;\n if (editDialog.changelog.trim()) input.changelog = editDialog.changelog;\n if (editDialog.newPackageUrl) {\n input.packageUrl = editDialog.newPackageUrl;\n input.packageSize = editDialog.newPackageSize;\n }\n if (parsedManifest) input.manifest = parsedManifest;\n\n try {\n await updateVersion({\n variables: { id: editDialog.versionId, input },\n });\n setEditDialog(null);\n setEditManifestFileName(null);\n setActionSuccess(\n tr(\"devportal.versionUpdatedSuccess\", \"Version updated successfully\"),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionUpdateFailed\", \"Failed to update version\"),\n );\n }\n };\n\n const handlePublish = async (versionId: string) => {\n setActionError(null);\n setActionSuccess(null);\n try {\n await publishVersion({ variables: { id: versionId } });\n setActionSuccess(\n tr(\n \"devportal.versionSubmittedSuccess\",\n \"Version submitted for review — you'll be notified when approved\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.versionPublishFailed\",\n \"Failed to submit version for review\",\n ),\n );\n }\n };\n\n const handleDeprecate = async (versionId: string) => {\n setActionError(null);\n setActionSuccess(null);\n try {\n await deprecateVersion({ variables: { id: versionId } });\n setActionSuccess(\n tr(\n \"devportal.versionDeprecatedSuccess\",\n \"Version deprecated successfully\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.versionDeprecateFailed\",\n \"Failed to deprecate version\",\n ),\n );\n }\n };\n\n const handleApprove = async (versionId: string) => {\n setActionError(null);\n setActionSuccess(null);\n try {\n await approveVersion({ variables: { id: versionId } });\n setActionSuccess(\n tr(\n \"devportal.versionApprovedSuccess\",\n \"Version approved and published to store\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionApproveFailed\", \"Failed to approve version\"),\n );\n }\n };\n\n const handleRejectConfirm = async () => {\n if (!rejectDialog || !rejectReason.trim()) return;\n setActionError(null);\n setActionSuccess(null);\n try {\n await rejectVersion({\n variables: { id: rejectDialog.versionId, reason: rejectReason },\n });\n setActionSuccess(\n tr(\n \"devportal.versionRejectedSuccess\",\n \"Version rejected — developer has been notified\",\n ),\n );\n setRejectDialog(null);\n setRejectReason(\"\");\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionRejectFailed\", \"Failed to reject version\"),\n );\n }\n };\n\n const getStatusIcon = (version: ApplicationVersionFieldsFragment) => {\n if (version.status === \"published\" && version.isLatest) {\n return <CheckCircle size={16} className=\"text-status-success-text\" />;\n }\n if (version.status === \"pending_review\") {\n return <Send size={16} className=\"text-status-info-text\" />;\n }\n if (version.status === \"rejected\") {\n return <XCircle size={16} className=\"text-status-error-text\" />;\n }\n if (version.status === \"draft\") {\n return <Clock size={16} className=\"text-status-warning-text\" />;\n }\n if (version.status === \"deprecated\") {\n return <Archive size={16} className=\"text-text-secondary\" />;\n }\n return <Package size={16} className=\"text-accent-blue\" />;\n };\n\n const toggleVersionSelection = (versionId: string, checked: boolean) => {\n setSelectedVersionIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(versionId);\n } else {\n next.delete(versionId);\n }\n return next;\n });\n };\n\n const toggleAllVisibleVersions = (checked: boolean) => {\n setSelectedVersionIds((prev) => {\n const next = new Set(prev);\n versions.forEach((version) => {\n if (checked) {\n next.add(version.id);\n } else {\n next.delete(version.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedVersionIds(new Set());\n\n const handleBulkPublish = async () => {\n if (publishableVersions.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n publishableVersions.map((version) =>\n publishVersion({ variables: { id: version.id } }),\n ),\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `Published ${succeeded} version${succeeded === 1 ? \"\" : \"s\"}${failed > 0 ? ` • ${failed} failed` : \"\"}`,\n );\n clearSelection();\n setBulkAction(null);\n };\n\n const handleBulkDeprecate = async () => {\n if (deprecatableVersions.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n deprecatableVersions.map((version) =>\n deprecateVersion({ variables: { id: version.id } }),\n ),\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `Deprecated ${succeeded} version${succeeded === 1 ? \"\" : \"s\"}${failed > 0 ? ` • ${failed} failed` : \"\"}`,\n );\n clearSelection();\n setBulkAction(null);\n };\n\n // Loading state\n if (versionsLoading && !versionsData) {\n return (\n <PageLayout\n title={tr(\"devportal.versionManagement\", \"Version Management\")}\n description={tr(\n \"devportal.versionManagementDescription\",\n \"Manage your application versions\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <div className=\"flex items-center justify-center py-16\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (versionsError && !versionsData) {\n return (\n <PageLayout\n title={tr(\"devportal.versionManagement\", \"Version Management\")}\n description={tr(\n \"devportal.versionManagementDescription\",\n \"Manage your application versions\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.failedToLoadVersions\",\n \"Failed to load versions\",\n )}\n description={\n versionsError.message ||\n tr(\n \"devportal.versionsLoadError\",\n \"An error occurred while loading versions\",\n )\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={tr(\"devportal.versionManagement\", \"Version Management\")}\n description={tr(\n \"devportal.versionManagementDescription\",\n \"Manage your application versions\",\n )}\n purpose={\n isWorkflowApp\n ? tr(\n \"devportal.versionManagementPurposeWorkflow\",\n \"Versions track releases of your workflow. Create a version for each significant change and paste the workflow definition JSON. No zip is needed — the manifest is the workflow.\",\n )\n : isNodeApp\n ? tr(\n \"devportal.versionManagementPurposeNode\",\n \"Versions are the releases of your node that users install. Upload a new zip whenever the node implementation changes, and update the manifest if the node's inputs, outputs, or operations change. Bump the version for any change users will see.\",\n )\n : isManifestOnlyType\n ? tr(\n \"devportal.versionManagementPurposeManifestOnly\",\n \"Versions track releases of this item. Create a version for each significant change and paste the manifest JSON. No zip is needed.\",\n )\n : tr(\n \"devportal.versionManagementPurposeIntegration\",\n \"Versions track permission and webhook changes for your integration. No zip or manifest is needed — create a new version whenever you add or change required scopes so users can review and accept the updated permissions.\",\n )\n }\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n actions={\n <button\n onClick={() => {\n setCreateDialogError(null);\n setShowCreateDialog(true);\n }}\n disabled={!canCreate}\n aria-disabled={!canCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n <Plus size={16} />\n {tr(\"devportal.newVersion\", \"New Version\")}\n </button>\n }\n >\n {/* Action Error Banner */}\n {actionError && (\n <div className=\"rounded-lg border border-border-subtle bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={16} className=\"flex-shrink-0\" />\n {actionError}\n <button\n onClick={() => setActionError(null)}\n className=\"ml-auto text-status-error-text hover:text-status-error-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {actionSuccess && (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-3 flex items-center gap-2 text-sm text-status-success-text\">\n <CheckCircle size={16} className=\"flex-shrink-0\" />\n {actionSuccess}\n <button\n onClick={() => setActionSuccess(null)}\n className=\"ml-auto text-status-success-text hover:text-status-success-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* App setup incomplete — block version submission with a clear warning */}\n {app && !appReadyForSubmission && (\n <div className=\"flex items-start gap-3 rounded-lg border border-status-warning-bg bg-status-warning-bg-subtle px-4 py-3 text-sm text-status-warning-text\">\n <AlertCircle size={16} className=\"mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium\">\n Complete your app setup before submitting for review\n </p>\n <ul className=\"mt-1 list-disc pl-4 text-xs opacity-80\">\n {appReadinessBlockers.map((b) => (\n <li key={b}>{b}</li>\n ))}\n </ul>\n </div>\n </div>\n )}\n\n {/* First-time submission explainer — shown when app is not yet published and there are draft versions */}\n {app &&\n app.status !== \"PUBLISHED\" &&\n versions.some((v) => v.status === \"draft\") && (\n <div className=\"flex items-start gap-3 rounded-lg border border-status-info-bg bg-status-info-bg-subtle px-4 py-3 text-sm text-status-info-text\">\n <Send size={16} className=\"mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium\">\n Ready to submit? Go to the Submit tab\n </p>\n <p className=\"mt-1 text-xs opacity-80\">\n For your first submission the app and its version are reviewed\n together. Head to the <strong>Submit</strong> tab — your draft\n version will be included automatically. The per-version\n &quot;Submit for Review&quot; button is only for new versions\n after the app is already live in the marketplace.\n </p>\n </div>\n </div>\n )}\n\n {/* A version is already awaiting admin review — block submitting another\n so admins never have more than one pending version per app to sort out. */}\n {app && hasPendingVersion && (\n <div className=\"flex items-start gap-3 rounded-lg border border-status-warning-bg bg-status-warning-bg-subtle px-4 py-3 text-sm text-status-warning-text\">\n <Send size={16} className=\"mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium\">\n {tr(\n \"devportal.versionAlreadyPending\",\n \"A version is already pending review\",\n )}\n </p>\n <p className=\"mt-1 text-xs opacity-80\">\n {tr(\n \"devportal.versionAlreadyPendingDetail\",\n \"Submitting another version is disabled until it's approved or rejected.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {versions.length > 0 && (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleVersions}\n ariaLabel=\"Select all visible versions\"\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllVisible\", \"Select all visible\")}\n </span>\n </div>\n {selectedVersionIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr(\"devportal.clearSelection\", \"Clear selection\")}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedVersionIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"publish\")}\n disabled={\n publishableVersions.length === 0 ||\n !canPublish ||\n !appReadyForSubmission ||\n hasPendingVersion\n }\n aria-disabled={\n !canPublish || !appReadyForSubmission || hasPendingVersion\n }\n title={\n hasPendingVersion\n ? tr(\n \"devportal.versionAlreadyPending\",\n \"A version is already pending review\",\n )\n : !appReadyForSubmission\n ? appReadinessBlockers.join(\" · \")\n : undefined\n }\n className=\"rounded-md border border-status-success-bg px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n {publishableVersions.length > 0\n ? ` (${publishableVersions.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"deprecate\")}\n disabled={deprecatableVersions.length === 0 || !canDeprecate}\n aria-disabled={!canDeprecate}\n className=\"rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.deprecateSelected\", \"Deprecate Selected\")}\n {deprecatableVersions.length > 0\n ? ` (${deprecatableVersions.length})`\n : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {versions.length > 0 ? (\n <DataTable\n data={versions}\n keyField=\"id\"\n columns={[\n {\n key: \"select\",\n header: (\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleVersions}\n ariaLabel=\"Select all visible versions\"\n />\n ),\n className: \"w-12\",\n render: (v) => (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedVersionIds.has(v.id)}\n onChange={(checked) =>\n toggleVersionSelection(v.id, checked)\n }\n ariaLabel={`Select version ${v.version}`}\n />\n </div>\n ),\n },\n {\n key: \"version\",\n header: tr(\"devportal.version\", \"Version\"),\n render: (v) => (\n <div className=\"flex items-center gap-2\">\n {getStatusIcon(v)}\n <span className=\"font-mono font-medium\">{v.version}</span>\n {v.isLatest && (\n <span className=\"rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs text-status-success-text\">\n {tr(\"devportal.latest\", \"Latest\")}\n </span>\n )}\n {!v.isStable && (\n <span className=\"rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs text-status-warning-text\">\n {tr(\"devportal.beta\", \"Beta\")}\n </span>\n )}\n </div>\n ),\n },\n {\n key: \"releaseNotes\",\n header: tr(\"devportal.releaseNotes\", \"Release Notes\"),\n render: (v) => (\n <p className=\"max-w-md truncate text-sm text-text-secondary\">\n {v.releaseNotes ||\n tr(\"devportal.noReleaseNotes\", \"No release notes\")}\n </p>\n ),\n },\n {\n key: \"status\",\n header: tr(\"devportal.status\", \"Status\"),\n render: (v) => (\n <div className=\"space-y-1\">\n <StatusBadge\n status={\n v.status === \"pending_review\" ? \"In Review\" : v.status\n }\n />\n {v.status === \"pending_review\" && (\n <p className=\"text-xs text-status-info-text\">\n Awaiting platform review\n </p>\n )}\n {v.status === \"rejected\" && v.reviewNotes && (\n <p className=\"text-xs text-status-error-text max-w-xs\">\n {v.reviewNotes}\n </p>\n )}\n </div>\n ),\n },\n {\n key: \"publishedAt\",\n header: tr(\"devportal.published\", \"Published\"),\n render: (v) =>\n v.publishedAt\n ? format(new Date(v.publishedAt), \"MMM d, yyyy\")\n : \"-\",\n },\n {\n key: \"actions\",\n header: \"\",\n className: \"w-48\",\n render: (v) => (\n <div className=\"flex flex-wrap gap-2\">\n {/* Edit draft/rejected versions before submission */}\n {(v.status === \"draft\" || v.status === \"rejected\") &&\n canCreate && (\n <button\n className=\"inline-flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary hover:underline\"\n onClick={() => {\n const existingManifest = v.manifest\n ? JSON.stringify(v.manifest, null, 2)\n : \"\";\n setEditDialog({\n versionId: v.id,\n version: v.version,\n hasExistingZip: !!v.packageUrl,\n newPackageUrl: \"\",\n newPackageSize: \"\",\n manifestJson: existingManifest,\n originalManifestJson: existingManifest,\n releaseNotes: v.releaseNotes ?? \"\",\n changelog: v.changelog ?? \"\",\n });\n setEditManifestFileName(null);\n setEditDialogError(null);\n }}\n >\n Edit\n </button>\n )}\n {/* Only show \"Submit for Review\" on a version when the app is already\n published — for a first-time app the whole submission goes through\n the app-level \"Submit for Review\" (store listing + pricing + version). */}\n {(v.status === \"draft\" || v.status === \"rejected\") &&\n app?.status === \"PUBLISHED\" && (\n <button\n className=\"inline-flex items-center gap-1 text-xs text-primary hover:underline disabled:opacity-50 disabled:cursor-not-allowed\"\n disabled={\n !canPublish ||\n !appReadyForSubmission ||\n hasPendingVersion\n }\n aria-disabled={\n !canPublish ||\n !appReadyForSubmission ||\n hasPendingVersion\n }\n title={\n hasPendingVersion\n ? tr(\n \"devportal.versionAlreadyPending\",\n \"A version is already pending review\",\n )\n : !appReadyForSubmission\n ? appReadinessBlockers.join(\" · \")\n : undefined\n }\n onClick={() => handlePublish(v.id)}\n >\n <Send size={11} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </button>\n )}\n {v.status === \"published\" && !v.isLatest && (\n <button\n className=\"text-xs text-status-warning-text hover:underline disabled:opacity-50\"\n disabled={!canDeprecate}\n aria-disabled={!canDeprecate}\n onClick={() => handleDeprecate(v.id)}\n >\n {tr(\"devportal.deprecate\", \"Deprecate\")}\n </button>\n )}\n </div>\n ),\n },\n ]}\n />\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title={tr(\"devportal.noVersionsYet\", \"No versions yet\")}\n description={tr(\n \"devportal.noVersionsYetDescription\",\n \"Create your first version to start distributing your app\",\n )}\n action={\n <button\n onClick={() => {\n setCreateDialogError(null);\n setShowCreateDialog(true);\n }}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createVersion\", \"Create Version\")}\n </button>\n }\n />\n )}\n\n {/* Create Version Dialog */}\n {showCreateDialog && (\n <ConfirmDialog\n open={showCreateDialog}\n onOpenChange={(open) => {\n setShowCreateDialog(open);\n if (!open) setCreateDialogError(null);\n }}\n onConfirm={handleCreate}\n title={tr(\"devportal.createNewVersion\", \"Create New Version\")}\n confirmLabel={\n creating\n ? tr(\"devportal.creating\", \"Creating...\")\n : tr(\"devportal.createVersion\", \"Create Version\")\n }\n >\n <div className=\"space-y-4\">\n {createDialogError && (\n <div className=\"rounded-lg border border-status-error-bg bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n {createDialogError}\n </div>\n )}\n <InputField\n label={tr(\"devportal.versionNumber\", \"Version Number\")}\n value={newVersion.version}\n onChange={(e) =>\n setNewVersion({ ...newVersion, version: e.target.value })\n }\n placeholder=\"e.g., 2.2.0\"\n hint={tr(\n \"devportal.versionHint\",\n \"Use semantic versioning (major.minor.patch)\",\n )}\n required\n />\n {isManifestOnlyType && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {isWorkflowApp\n ? \"Workflow Definition (JSON)\"\n : \"Manifest (JSON)\"}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n rows={10}\n required\n placeholder={\n isWorkflowApp\n ? `{\\n \"nodes\": [],\\n \"edges\": []\\n}`\n : `{\\n \"manifestVersion\": \"1.0\",\\n \"identity\": { \"name\": \"My Item\", \"version\": \"1.0.0\" }\\n}`\n }\n value={newVersion.manifestJson}\n onChange={(e) =>\n setNewVersion({\n ...newVersion,\n manifestJson: e.target.value,\n })\n }\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-secondary\">\n {isWorkflowApp ? (\n <>\n Paste the full <code>{`{nodes, edges}`}</code> JSON.\n Saved as this version&apos;s manifest — no zip needed.\n </>\n ) : (\n \"Paste the manifest JSON for this version. No zip needed.\"\n )}\n </p>\n </div>\n )}\n {/* Zip upload — node apps only */}\n {isNodeApp && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n Package (.zip){\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"flex gap-2 items-center\">\n <input\n ref={zipInputRef}\n type=\"file\"\n accept=\".zip\"\n className=\"hidden\"\n onChange={handleZipUpload}\n />\n <button\n type=\"button\"\n disabled={zipUploading}\n onClick={() => zipInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-bg-sunken transition-colors disabled:opacity-50\"\n >\n {zipUploading ? (\n <>\n <Loader2 size={14} className=\"animate-spin\" />{\" \"}\n Uploading… {zipProgress}%\n </>\n ) : (\n <>\n <Upload size={14} />{\" \"}\n {newVersion.packageUrl ? \"Replace zip\" : \"Upload zip\"}\n </>\n )}\n </button>\n {newVersion.packageUrl && !zipUploading && (\n <span className=\"text-xs text-status-success-text\">\n ✓ Uploaded\n </span>\n )}\n </div>\n {zipUploadError && (\n <p className=\"text-xs text-status-error-text\">\n {zipUploadError}\n </p>\n )}\n <p className=\"text-xs text-text-tertiary\">\n The zip is the node executable. Upload it before publishing\n — users install exactly this artifact.\n </p>\n </div>\n )}\n\n {/* Manifest JSON — node apps only (required) */}\n {isNodeApp && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2 flex-wrap\">\n <label className=\"text-sm font-medium\">\n manifest.json{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"flex items-center gap-2\">\n {manifestFileName && (\n <span className=\"text-xs text-status-success-text\">\n ✓ {manifestFileName}\n </span>\n )}\n <input\n ref={manifestInputRef}\n type=\"file\"\n accept=\".json,application/json\"\n className=\"hidden\"\n onChange={handleManifestFileUpload}\n />\n <button\n type=\"button\"\n onClick={() => manifestInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium hover:bg-bg-sunken transition-colors\"\n >\n <Upload size={12} />\n Upload manifest.json\n </button>\n </div>\n </div>\n <textarea\n rows={5}\n placeholder={`{\\n \"manifestVersion\": \"1.0\",\\n \"itemType\": \"node\",\\n \"identity\": { \"version\": \"1.0.0\", \"displayName\": \"My Node\" }\\n}`}\n value={newVersion.manifestJson}\n onChange={(e) => {\n setManifestFileName(null);\n setNewVersion({\n ...newVersion,\n manifestJson: e.target.value,\n });\n }}\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-tertiary\">\n Upload or paste your <code>manifest.json</code> — required\n so the platform knows your node&apos;s inputs, outputs, and\n operations. Not extracted from the zip automatically.\n </p>\n </div>\n )}\n\n {/* Required scopes — integration/app types only */}\n {isIntegrationApp && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n Required scopes{\" \"}\n <span className=\"text-xs font-normal text-text-secondary\">\n (optional)\n </span>\n </label>\n <input\n type=\"text\"\n value={newVersion.requiredScopes}\n onChange={(e) =>\n setNewVersion({\n ...newVersion,\n requiredScopes: e.target.value,\n })\n }\n placeholder=\"e.g. read:contacts, write:messages\"\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-sm placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-tertiary\">\n Comma-separated. List every permission this version needs —\n users will be prompted to accept any new or changed scopes\n on update.\n </p>\n </div>\n )}\n <MarkdownEditor\n label={tr(\"devportal.releaseNotes\", \"Release Notes\")}\n value={newVersion.releaseNotes}\n onChange={(value) =>\n setNewVersion({ ...newVersion, releaseNotes: value })\n }\n placeholder={tr(\n \"devportal.releaseNotesPlaceholder\",\n \"What changed in this release?\",\n )}\n rows={3}\n />\n <MarkdownEditor\n label={tr(\"devportal.changelog\", \"Changelog\")}\n value={newVersion.changelog}\n onChange={(value) =>\n setNewVersion({ ...newVersion, changelog: value })\n }\n placeholder={tr(\n \"devportal.changelogPlaceholder\",\n \"Detailed changelog for this version...\",\n )}\n rows={3}\n />\n </div>\n </ConfirmDialog>\n )}\n\n {/* Reject version dialog */}\n {rejectDialog && (\n <ConfirmDialog\n open={!!rejectDialog}\n onOpenChange={(open) => {\n if (!open) {\n setRejectDialog(null);\n setRejectReason(\"\");\n }\n }}\n onConfirm={handleRejectConfirm}\n title={`Reject version ${rejectDialog.version}`}\n confirmLabel=\"Reject Version\"\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"danger\"\n >\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n The developer will be notified and can fix and resubmit. Please\n provide a clear reason.\n </p>\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n Rejection reason{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n rows={3}\n value={rejectReason}\n onChange={(e) => setRejectReason(e.target.value)}\n placeholder=\"e.g. Manifest contains disallowed network calls to external domains...\"\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-sm placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n </ConfirmDialog>\n )}\n\n {/* Edit Version Dialog */}\n {editDialog && (\n <ConfirmDialog\n open={!!editDialog}\n onOpenChange={(open) => {\n if (!open) {\n setEditDialog(null);\n setEditManifestFileName(null);\n setEditDialogError(null);\n }\n }}\n onConfirm={handleEditSave}\n title={`Edit Version ${editDialog.version}`}\n confirmLabel={updating ? \"Saving…\" : \"Save Changes\"}\n >\n <div className=\"space-y-4\">\n {editDialogError && (\n <div className=\"rounded-lg border border-status-error-bg bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n {editDialogError}\n </div>\n )}\n <div className=\"rounded-lg border border-status-info-bg bg-status-info-bg-subtle px-3 py-2 text-xs text-status-info-text\">\n You can fix the zip, manifest, or release notes before\n submitting for review. Once submitted for review these fields\n are locked.\n </div>\n\n {/* ZIP replacement — node apps */}\n {isNodeApp && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">Package (.zip)</label>\n <div className=\"flex gap-2 items-center\">\n <input\n ref={editZipInputRef}\n type=\"file\"\n accept=\".zip\"\n className=\"hidden\"\n onChange={handleEditZipUpload}\n />\n <button\n type=\"button\"\n disabled={zipUploading}\n onClick={() => editZipInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-bg-sunken transition-colors disabled:opacity-50\"\n >\n {zipUploading ? (\n <>\n <Loader2 size={14} className=\"animate-spin\" />{\" \"}\n Uploading… {zipProgress}%\n </>\n ) : (\n <>\n <Upload size={14} />\n {editDialog.newPackageUrl\n ? \"Replace zip again\"\n : editDialog.hasExistingZip\n ? \"Replace zip\"\n : \"Upload zip\"}\n </>\n )}\n </button>\n {editDialog.newPackageUrl && !zipUploading && (\n <span className=\"text-xs text-status-success-text\">\n ✓ New zip ready\n </span>\n )}\n {!editDialog.newPackageUrl && editDialog.hasExistingZip && (\n <span className=\"text-xs text-text-secondary\">\n Current zip kept\n </span>\n )}\n </div>\n {zipUploadError && (\n <p className=\"text-xs text-status-error-text\">\n {zipUploadError}\n </p>\n )}\n </div>\n )}\n\n {/* Manifest replacement — node apps */}\n {isNodeApp && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2 flex-wrap\">\n <label className=\"text-sm font-medium\">\n manifest.json{\" \"}\n <span className=\"text-xs font-normal text-text-secondary\">\n (edit below or upload a new file)\n </span>\n </label>\n <div className=\"flex items-center gap-2\">\n {editManifestFileName && (\n <span className=\"text-xs text-status-success-text\">\n ✓ {editManifestFileName}\n </span>\n )}\n <input\n ref={editManifestInputRef}\n type=\"file\"\n accept=\".json,application/json\"\n className=\"hidden\"\n onChange={handleEditManifestUpload}\n />\n <button\n type=\"button\"\n onClick={() => editManifestInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium hover:bg-bg-sunken transition-colors\"\n >\n <Upload size={12} /> Upload manifest.json\n </button>\n </div>\n </div>\n <textarea\n rows={5}\n placeholder={`{\\n \"manifestVersion\": \"1.0\",\\n \"itemType\": \"node\",\\n \"identity\": { \"version\": \"1.0.0\", \"displayName\": \"My Node\" }\\n}`}\n value={editDialog.manifestJson}\n onChange={(e) => {\n setEditManifestFileName(null);\n setEditDialog((prev) =>\n prev ? { ...prev, manifestJson: e.target.value } : prev,\n );\n }}\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n )}\n\n {/* Workflow definition replacement */}\n {isManifestOnlyType && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {isWorkflowApp\n ? \"Workflow Definition (JSON)\"\n : \"Manifest (JSON)\"}{\" \"}\n <span className=\"text-xs font-normal text-text-secondary\">\n (leave empty to keep existing)\n </span>\n </label>\n <textarea\n rows={10}\n placeholder={\n isWorkflowApp\n ? `{\\n \"nodes\": [],\\n \"edges\": []\\n}`\n : `{\\n \"manifestVersion\": \"1.0\",\\n \"identity\": { \"name\": \"My Item\", \"version\": \"1.0.0\" }\\n}`\n }\n value={editDialog.manifestJson}\n onChange={(e) =>\n setEditDialog((prev) =>\n prev ? { ...prev, manifestJson: e.target.value } : prev,\n )\n }\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n )}\n\n <MarkdownEditor\n label={tr(\"devportal.releaseNotes\", \"Release Notes\")}\n value={editDialog.releaseNotes}\n onChange={(value) =>\n setEditDialog((prev) =>\n prev ? { ...prev, releaseNotes: value } : prev,\n )\n }\n placeholder={tr(\n \"devportal.releaseNotesPlaceholder\",\n \"What changed in this release?\",\n )}\n rows={3}\n />\n <MarkdownEditor\n label={tr(\"devportal.changelog\", \"Changelog\")}\n value={editDialog.changelog}\n onChange={(value) =>\n setEditDialog((prev) =>\n prev ? { ...prev, changelog: value } : prev,\n )\n }\n placeholder={tr(\n \"devportal.changelogPlaceholder\",\n \"Detailed changelog for this version...\",\n )}\n rows={3}\n />\n </div>\n </ConfirmDialog>\n )}\n\n <ConfirmDialog\n open={bulkAction === \"publish\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={handleBulkPublish}\n title={tr(\n \"devportal.submitSelectedVersions\",\n \"Submit selected versions for review\",\n )}\n description={`Submit ${publishableVersions.length} selected version${publishableVersions.length === 1 ? \"\" : \"s\"} for platform review?`}\n confirmLabel={tr(\"devportal.submitForReview\", \"Submit for Review\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"success\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"deprecate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={handleBulkDeprecate}\n title={tr(\n \"devportal.deprecateSelectedVersions\",\n \"Deprecate selected versions\",\n )}\n description={`${tr(\"devportal.deprecate\", \"Deprecate\")} ${deprecatableVersions.length} selected version${deprecatableVersions.length === 1 ? \"\" : \"s\"}? ${tr(\"devportal.deprecateVersionsWarning\", \"Deprecated versions remain visible but should no longer be promoted.\")}`}\n confirmLabel={tr(\"devportal.deprecate\", \"Deprecate\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ApplicationVersionsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationVersionsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useParams } from \"react-router\";\nimport {\n Plus,\n Package,\n CheckCircle,\n XCircle,\n Clock,\n Archive,\n Loader2,\n AlertCircle,\n Upload,\n Send,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { InputField, TextareaField } from \"../components/FormField\";\nimport { MarkdownEditor } from \"../components/MarkdownEditor\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { ManifestViewer } from \"../components/ManifestViewer\";\nimport { format } from \"date-fns\";\nimport {\n useGetApplicationQuery,\n useGetApplicationVersionsQuery,\n useCreateApplicationVersionMutation,\n useUpdateApplicationVersionMutation,\n usePublishApplicationVersionMutation,\n useDeprecateApplicationVersionMutation,\n useApproveApplicationVersionMutation,\n useRejectApplicationVersionMutation,\n type ApplicationVersionFieldsFragment,\n} from \"../hooks\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { usePackageUpload } from \"../hooks/usePackageUpload\";\n\n/**\n * Pulls the version string out of an uploaded manifest so the developer\n * doesn't have to retype what's already declared in the file. Checks the\n * FluidGrids node manifest shape (`nodeVersion`, e.g.\n * fluidgrids-nodes/nodes/*\\/manifest.json) first, then the generic\n * `identity.version` / top-level `version` shapes used by other manifest types.\n */\nconst extractVersionFromManifest = (\n manifestJson: string,\n): string | undefined => {\n if (!manifestJson.trim()) return undefined;\n try {\n const parsed = JSON.parse(manifestJson) as Record<string, unknown>;\n if (typeof parsed.nodeVersion === \"string\" && parsed.nodeVersion.trim()) {\n return parsed.nodeVersion.trim();\n }\n const identity = parsed.identity as Record<string, unknown> | undefined;\n if (\n identity &&\n typeof identity.version === \"string\" &&\n identity.version.trim()\n ) {\n return identity.version.trim();\n }\n if (typeof parsed.version === \"string\" && parsed.version.trim()) {\n return parsed.version.trim();\n }\n } catch {\n // Manifest isn't valid JSON yet (still being typed/pasted) — ignore.\n }\n return undefined;\n};\n\nexport const ApplicationVersionsPage: FC = () => {\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 const { allowed: canCreate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_CREATE,\n );\n const { allowed: canPublish } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_PUBLISH,\n );\n const { allowed: canDeprecate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_VERSION_DEPRECATE,\n );\n const { appId } = useParams<{ appId: string }>();\n const { workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken } =\n useDevportal();\n const {\n upload: uploadZip,\n uploading: zipUploading,\n progress: zipProgress,\n error: zipUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n );\n const zipInputRef = useRef<HTMLInputElement>(null);\n const manifestInputRef = useRef<HTMLInputElement>(null);\n const editZipInputRef = useRef<HTMLInputElement>(null);\n const editManifestInputRef = useRef<HTMLInputElement>(null);\n const [manifestFileName, setManifestFileName] = useState<string | null>(null);\n const [editManifestFileName, setEditManifestFileName] = useState<\n string | null\n >(null);\n const [showCreateDialog, setShowCreateDialog] = useState(false);\n const [editDialog, setEditDialog] = useState<{\n versionId: string;\n version: string;\n hasExistingZip: boolean;\n newPackageUrl: string;\n newPackageSize: string;\n manifestJson: string;\n originalManifestJson: string;\n releaseNotes: string;\n changelog: string;\n } | null>(null);\n const [newVersion, setNewVersion] = useState({\n version: \"\",\n releaseNotes: \"\",\n changelog: \"\",\n packageUrl: \"\",\n packageSize: \"\",\n manifestJson: \"\",\n requiredScopes: \"\",\n });\n const [actionError, setActionError] = useState<string | null>(null);\n const [actionSuccess, setActionSuccess] = useState<string | null>(null);\n const [createDialogError, setCreateDialogError] = useState<string | null>(\n null,\n );\n const [editDialogError, setEditDialogError] = useState<string | null>(null);\n const [selectedVersionIds, setSelectedVersionIds] = useState<Set<string>>(\n new Set(),\n );\n const [rejectDialog, setRejectDialog] = useState<{\n versionId: string;\n version: string;\n } | null>(null);\n const [rejectReason, setRejectReason] = useState(\"\");\n\n const handleManifestFileUpload = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (evt) => {\n const text = evt.target?.result;\n if (typeof text === \"string\") {\n const extractedVersion = extractVersionFromManifest(text);\n setNewVersion((prev) => ({\n ...prev,\n manifestJson: text,\n ...(extractedVersion ? { version: extractedVersion } : {}),\n }));\n setManifestFileName(file.name);\n }\n };\n reader.readAsText(file);\n // reset so re-uploading same file triggers onChange\n e.target.value = \"\";\n },\n [],\n );\n const [bulkAction, setBulkAction] = useState<\"publish\" | \"deprecate\" | null>(\n null,\n );\n\n const { data: appData } = useGetApplicationQuery({\n variables: { id: appId ?? \"\" },\n skip: !appId,\n fetchPolicy: \"cache-first\",\n });\n const isWorkflowApp = appData?.application?.appType === \"WORKFLOW\";\n const isNodeApp = appData?.application?.appType === \"NODE\";\n // Manifest-only types (no zip): Workflow plus its sibling types Parser/Widget/Dashboard.\n const isManifestOnlyType = [\n \"WORKFLOW\",\n \"PARSER\",\n \"WIDGET\",\n \"DASHBOARD\",\n ].includes(appData?.application?.appType ?? \"\");\n const isIntegrationApp = !isManifestOnlyType && !isNodeApp;\n\n // App-level readiness checks — version submission is blocked until the app is ready\n const app = appData?.application;\n const pricingDetailsRaw = (app?.pricingDetails ?? {}) as Record<\n string,\n unknown\n >;\n const pricingDone =\n app?.pricingType === \"FREE\" ||\n (app?.pricingType === \"PAID\" &&\n typeof pricingDetailsRaw.price === \"number\" &&\n (pricingDetailsRaw.price as number) > 0);\n const storeDone =\n !!app?.shortDescription?.trim() &&\n !!app?.privacyPolicyUrl?.trim() &&\n !!app?.termsOfServiceUrl?.trim();\n const appReadyForSubmission = pricingDone && storeDone;\n const appReadinessBlockers: string[] = [\n ...(!storeDone\n ? [\n \"Complete your store listing (short description, privacy policy, terms of service)\",\n ]\n : []),\n ...(!pricingDone ? [\"Set pricing in the Pricing tab\"] : []),\n ];\n\n useEffect(() => {\n const name = appData?.application?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, appData?.application?.name]);\n\n // Query\n const {\n data: versionsData,\n loading: versionsLoading,\n error: versionsError,\n } = useGetApplicationVersionsQuery({\n variables: { applicationId: appId! },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n // Mutations\n const [createVersion, { loading: creating }] =\n useCreateApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [updateVersion, { loading: updating }] =\n useUpdateApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [publishVersion] = usePublishApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [deprecateVersion] = useDeprecateApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [approveVersion] = useApproveApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const [rejectVersion] = useRejectApplicationVersionMutation({\n refetchQueries: [\"GetApplicationVersions\"],\n });\n\n const versions: ApplicationVersionFieldsFragment[] = useMemo(\n () =>\n versionsData?.application?.versions?.edges?.map(\n (edge: { node: ApplicationVersionFieldsFragment }) => edge.node,\n ) ?? [],\n [versionsData?.application?.versions],\n );\n\n const selectedVersions = useMemo(\n () => versions.filter((version) => selectedVersionIds.has(version.id)),\n [versions, selectedVersionIds],\n );\n const publishableVersions = useMemo(\n () =>\n selectedVersions.filter(\n (version) =>\n version.status === \"draft\" || version.status === \"rejected\",\n ),\n [selectedVersions],\n );\n // Only one version should be in the admin review queue at a time — otherwise\n // an admin can't tell which pending version a developer actually wants\n // reviewed. This is a UI-only guard (no backend change): once a version is\n // pending_review, block submitting another until it's approved or rejected.\n const hasPendingVersion = useMemo(\n () => versions.some((version) => version.status === \"pending_review\"),\n [versions],\n );\n const deprecatableVersions = useMemo(\n () =>\n selectedVersions.filter(\n (version) =>\n version.status?.toUpperCase() === \"PUBLISHED\" && !version.isLatest,\n ),\n [selectedVersions],\n );\n const allVisibleSelected =\n versions.length > 0 &&\n versions.every((version) => selectedVersionIds.has(version.id));\n const partiallySelected =\n versions.some((version) => selectedVersionIds.has(version.id)) &&\n !allVisibleSelected;\n\n const handleCreate = async () => {\n if (!appId || !newVersion.version.trim()) return;\n setCreateDialogError(null);\n\n let parsedManifest: Record<string, unknown> | undefined;\n if (isManifestOnlyType) {\n if (!newVersion.manifestJson.trim()) {\n setCreateDialogError(\n isWorkflowApp\n ? \"Workflow Definition (JSON) is required — paste the {nodes, edges} object.\"\n : \"Manifest (JSON) is required.\",\n );\n return;\n }\n try {\n parsedManifest = JSON.parse(newVersion.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setCreateDialogError(\n isWorkflowApp\n ? \"Invalid JSON in Workflow Definition — please check your input.\"\n : \"Invalid JSON in Manifest — please check your input.\",\n );\n return;\n }\n } else if (isNodeApp) {\n if (!newVersion.packageUrl) {\n setCreateDialogError(\n \"Package zip is required for Node versions — upload a .zip file before creating.\",\n );\n return;\n }\n if (!newVersion.manifestJson.trim()) {\n setCreateDialogError(\n \"manifest.json is required for Node versions — upload or paste your manifest before creating.\",\n );\n return;\n }\n try {\n parsedManifest = JSON.parse(newVersion.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setCreateDialogError(\n \"Invalid JSON in manifest — please check your input.\",\n );\n return;\n }\n } else if (newVersion.manifestJson.trim()) {\n try {\n parsedManifest = JSON.parse(newVersion.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setCreateDialogError(\n \"Invalid JSON in manifest — please check your input.\",\n );\n return;\n }\n }\n\n const requiredScopes =\n isIntegrationApp && newVersion.requiredScopes.trim()\n ? newVersion.requiredScopes\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n try {\n await createVersion({\n variables: {\n applicationId: appId,\n input: {\n version: newVersion.version,\n releaseNotes: newVersion.releaseNotes || undefined,\n changelog: newVersion.changelog || undefined,\n packageUrl: newVersion.packageUrl || undefined,\n packageSize: newVersion.packageSize || undefined,\n manifest: parsedManifest,\n requiredScopes,\n },\n },\n });\n setShowCreateDialog(false);\n setManifestFileName(null);\n setNewVersion({\n version: \"\",\n releaseNotes: \"\",\n changelog: \"\",\n packageUrl: \"\",\n packageSize: \"\",\n manifestJson: \"\",\n requiredScopes: \"\",\n });\n setActionSuccess(\n tr(\"devportal.versionCreatedSuccess\", \"Version created successfully\"),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionCreateFailed\", \"Failed to create version\"),\n );\n }\n };\n\n const handleZipUpload = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n e.target.value = \"\";\n try {\n const result = await uploadZip(file);\n setNewVersion((prev) => ({\n ...prev,\n packageUrl: result.downloadUrl,\n packageSize: String(file.size),\n }));\n } catch {\n // error shown via zipUploadError prop\n }\n },\n [uploadZip],\n );\n\n const handleEditZipUpload = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n e.target.value = \"\";\n try {\n const result = await uploadZip(file);\n setEditDialog((prev) =>\n prev\n ? {\n ...prev,\n newPackageUrl: result.downloadUrl,\n newPackageSize: String(file.size),\n }\n : prev,\n );\n } catch {\n // error shown via zipUploadError prop\n }\n },\n [uploadZip],\n );\n\n const handleEditManifestUpload = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (evt) => {\n const text = evt.target?.result;\n if (typeof text === \"string\") {\n setEditDialog((prev) =>\n prev ? { ...prev, manifestJson: text } : prev,\n );\n setEditManifestFileName(file.name);\n }\n };\n reader.readAsText(file);\n e.target.value = \"\";\n },\n [],\n );\n\n const handleEditSave = async () => {\n if (!editDialog) return;\n setEditDialogError(null);\n\n const manifestChanged =\n editDialog.manifestJson.trim() !== editDialog.originalManifestJson.trim();\n\n let parsedManifest: Record<string, unknown> | undefined;\n if (manifestChanged && editDialog.manifestJson.trim()) {\n try {\n parsedManifest = JSON.parse(editDialog.manifestJson) as Record<\n string,\n unknown\n >;\n } catch {\n setEditDialogError(\n \"Invalid JSON in manifest — please check your input.\",\n );\n return;\n }\n }\n\n const input: {\n releaseNotes?: string;\n changelog?: string;\n packageUrl?: string;\n packageSize?: string;\n manifest?: Record<string, unknown>;\n } = {};\n\n if (editDialog.releaseNotes.trim())\n input.releaseNotes = editDialog.releaseNotes;\n if (editDialog.changelog.trim()) input.changelog = editDialog.changelog;\n if (editDialog.newPackageUrl) {\n input.packageUrl = editDialog.newPackageUrl;\n input.packageSize = editDialog.newPackageSize;\n }\n if (parsedManifest) input.manifest = parsedManifest;\n\n try {\n await updateVersion({\n variables: { id: editDialog.versionId, input },\n });\n setEditDialog(null);\n setEditManifestFileName(null);\n setActionSuccess(\n tr(\"devportal.versionUpdatedSuccess\", \"Version updated successfully\"),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionUpdateFailed\", \"Failed to update version\"),\n );\n }\n };\n\n const handlePublish = async (versionId: string) => {\n setActionError(null);\n setActionSuccess(null);\n try {\n await publishVersion({ variables: { id: versionId } });\n setActionSuccess(\n tr(\n \"devportal.versionSubmittedSuccess\",\n \"Version submitted for review — you'll be notified when approved\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.versionPublishFailed\",\n \"Failed to submit version for review\",\n ),\n );\n }\n };\n\n const handleDeprecate = async (versionId: string) => {\n setActionError(null);\n setActionSuccess(null);\n try {\n await deprecateVersion({ variables: { id: versionId } });\n setActionSuccess(\n tr(\n \"devportal.versionDeprecatedSuccess\",\n \"Version deprecated successfully\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.versionDeprecateFailed\",\n \"Failed to deprecate version\",\n ),\n );\n }\n };\n\n const handleApprove = async (versionId: string) => {\n setActionError(null);\n setActionSuccess(null);\n try {\n await approveVersion({ variables: { id: versionId } });\n setActionSuccess(\n tr(\n \"devportal.versionApprovedSuccess\",\n \"Version approved and published to store\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionApproveFailed\", \"Failed to approve version\"),\n );\n }\n };\n\n const handleRejectConfirm = async () => {\n if (!rejectDialog || !rejectReason.trim()) return;\n setActionError(null);\n setActionSuccess(null);\n try {\n await rejectVersion({\n variables: { id: rejectDialog.versionId, reason: rejectReason },\n });\n setActionSuccess(\n tr(\n \"devportal.versionRejectedSuccess\",\n \"Version rejected — developer has been notified\",\n ),\n );\n setRejectDialog(null);\n setRejectReason(\"\");\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.versionRejectFailed\", \"Failed to reject version\"),\n );\n }\n };\n\n const getStatusIcon = (version: ApplicationVersionFieldsFragment) => {\n if (version.status === \"published\" && version.isLatest) {\n return <CheckCircle size={16} className=\"text-status-success-text\" />;\n }\n if (version.status === \"pending_review\") {\n return <Send size={16} className=\"text-status-info-text\" />;\n }\n if (version.status === \"rejected\") {\n return <XCircle size={16} className=\"text-status-error-text\" />;\n }\n if (version.status === \"draft\") {\n return <Clock size={16} className=\"text-status-warning-text\" />;\n }\n if (version.status === \"deprecated\") {\n return <Archive size={16} className=\"text-text-secondary\" />;\n }\n return <Package size={16} className=\"text-accent-blue\" />;\n };\n\n const toggleVersionSelection = (versionId: string, checked: boolean) => {\n setSelectedVersionIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(versionId);\n } else {\n next.delete(versionId);\n }\n return next;\n });\n };\n\n const toggleAllVisibleVersions = (checked: boolean) => {\n setSelectedVersionIds((prev) => {\n const next = new Set(prev);\n versions.forEach((version) => {\n if (checked) {\n next.add(version.id);\n } else {\n next.delete(version.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedVersionIds(new Set());\n\n const handleBulkPublish = async () => {\n if (publishableVersions.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n publishableVersions.map((version) =>\n publishVersion({ variables: { id: version.id } }),\n ),\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `Published ${succeeded} version${succeeded === 1 ? \"\" : \"s\"}${failed > 0 ? ` • ${failed} failed` : \"\"}`,\n );\n clearSelection();\n setBulkAction(null);\n };\n\n const handleBulkDeprecate = async () => {\n if (deprecatableVersions.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n deprecatableVersions.map((version) =>\n deprecateVersion({ variables: { id: version.id } }),\n ),\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `Deprecated ${succeeded} version${succeeded === 1 ? \"\" : \"s\"}${failed > 0 ? ` • ${failed} failed` : \"\"}`,\n );\n clearSelection();\n setBulkAction(null);\n };\n\n // The version number is meant to come from the manifest itself, not be\n // retyped by hand — surface whatever we could parse out of it so the field\n // can be locked once the manifest supplies one.\n const manifestDerivedVersion = extractVersionFromManifest(\n newVersion.manifestJson,\n );\n\n // Loading state\n if (versionsLoading && !versionsData) {\n return (\n <PageLayout\n title={tr(\"devportal.versionManagement\", \"Version Management\")}\n description={tr(\n \"devportal.versionManagementDescription\",\n \"Manage your application versions\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <div className=\"flex items-center justify-center py-16\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (versionsError && !versionsData) {\n return (\n <PageLayout\n title={tr(\"devportal.versionManagement\", \"Version Management\")}\n description={tr(\n \"devportal.versionManagementDescription\",\n \"Manage your application versions\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.failedToLoadVersions\",\n \"Failed to load versions\",\n )}\n description={\n versionsError.message ||\n tr(\n \"devportal.versionsLoadError\",\n \"An error occurred while loading versions\",\n )\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={tr(\"devportal.versionManagement\", \"Version Management\")}\n description={tr(\n \"devportal.versionManagementDescription\",\n \"Manage your application versions\",\n )}\n purpose={\n isWorkflowApp\n ? tr(\n \"devportal.versionManagementPurposeWorkflow\",\n \"Versions track releases of your workflow. Create a version for each significant change and paste the workflow definition JSON. No zip is needed — the manifest is the workflow.\",\n )\n : isNodeApp\n ? tr(\n \"devportal.versionManagementPurposeNode\",\n \"Versions are the releases of your node that users install. Upload a new zip whenever the node implementation changes, and update the manifest if the node's inputs, outputs, or operations change. Bump the version for any change users will see.\",\n )\n : isManifestOnlyType\n ? tr(\n \"devportal.versionManagementPurposeManifestOnly\",\n \"Versions track releases of this item. Create a version for each significant change and paste the manifest JSON. No zip is needed.\",\n )\n : tr(\n \"devportal.versionManagementPurposeIntegration\",\n \"Versions track permission and webhook changes for your integration. No zip or manifest is needed — create a new version whenever you add or change required scopes so users can review and accept the updated permissions.\",\n )\n }\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n actions={\n <button\n onClick={() => {\n setCreateDialogError(null);\n setShowCreateDialog(true);\n }}\n disabled={!canCreate}\n aria-disabled={!canCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n <Plus size={16} />\n {tr(\"devportal.newVersion\", \"New Version\")}\n </button>\n }\n >\n {/* Action Error Banner */}\n {actionError && (\n <div className=\"rounded-lg border border-border-subtle bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={16} className=\"flex-shrink-0\" />\n {actionError}\n <button\n onClick={() => setActionError(null)}\n className=\"ml-auto text-status-error-text hover:text-status-error-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {actionSuccess && (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-3 flex items-center gap-2 text-sm text-status-success-text\">\n <CheckCircle size={16} className=\"flex-shrink-0\" />\n {actionSuccess}\n <button\n onClick={() => setActionSuccess(null)}\n className=\"ml-auto text-status-success-text hover:text-status-success-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* App setup incomplete — block version submission with a clear warning */}\n {app && !appReadyForSubmission && (\n <div className=\"flex items-start gap-3 rounded-lg border border-status-warning-bg bg-status-warning-bg-subtle px-4 py-3 text-sm text-status-warning-text\">\n <AlertCircle size={16} className=\"mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium\">\n Complete your app setup before submitting for review\n </p>\n <ul className=\"mt-1 list-disc pl-4 text-xs opacity-80\">\n {appReadinessBlockers.map((b) => (\n <li key={b}>{b}</li>\n ))}\n </ul>\n </div>\n </div>\n )}\n\n {/* First-time submission explainer — shown when app is not yet published and there are draft versions */}\n {app &&\n app.status !== \"PUBLISHED\" &&\n versions.some((v) => v.status === \"draft\") && (\n <div className=\"flex items-start gap-3 rounded-lg border border-status-info-bg bg-status-info-bg-subtle px-4 py-3 text-sm text-status-info-text\">\n <Send size={16} className=\"mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium\">\n Ready to submit? Go to the Submit tab\n </p>\n <p className=\"mt-1 text-xs opacity-80\">\n For your first submission the app and its version are reviewed\n together. Head to the <strong>Submit</strong> tab — your draft\n version will be included automatically. The per-version\n &quot;Submit for Review&quot; button is only for new versions\n after the app is already live in the marketplace.\n </p>\n </div>\n </div>\n )}\n\n {/* A version is already awaiting admin review — block submitting another\n so admins never have more than one pending version per app to sort out. */}\n {app && hasPendingVersion && (\n <div className=\"flex items-start gap-3 rounded-lg border border-status-warning-bg bg-status-warning-bg-subtle px-4 py-3 text-sm text-status-warning-text\">\n <Send size={16} className=\"mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium\">\n {tr(\n \"devportal.versionAlreadyPending\",\n \"A version is already pending review\",\n )}\n </p>\n <p className=\"mt-1 text-xs opacity-80\">\n {tr(\n \"devportal.versionAlreadyPendingDetail\",\n \"Submitting another version is disabled until it's approved or rejected.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {versions.length > 0 && (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleVersions}\n ariaLabel=\"Select all visible versions\"\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllVisible\", \"Select all visible\")}\n </span>\n </div>\n {selectedVersionIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr(\"devportal.clearSelection\", \"Clear selection\")}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedVersionIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"publish\")}\n disabled={\n publishableVersions.length === 0 ||\n !canPublish ||\n !appReadyForSubmission ||\n hasPendingVersion\n }\n aria-disabled={\n !canPublish || !appReadyForSubmission || hasPendingVersion\n }\n title={\n hasPendingVersion\n ? tr(\n \"devportal.versionAlreadyPending\",\n \"A version is already pending review\",\n )\n : !appReadyForSubmission\n ? appReadinessBlockers.join(\" · \")\n : undefined\n }\n className=\"rounded-md border border-status-success-bg px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n {publishableVersions.length > 0\n ? ` (${publishableVersions.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"deprecate\")}\n disabled={deprecatableVersions.length === 0 || !canDeprecate}\n aria-disabled={!canDeprecate}\n className=\"rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.deprecateSelected\", \"Deprecate Selected\")}\n {deprecatableVersions.length > 0\n ? ` (${deprecatableVersions.length})`\n : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {versions.length > 0 ? (\n <DataTable\n data={versions}\n keyField=\"id\"\n columns={[\n {\n key: \"select\",\n header: (\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleVersions}\n ariaLabel=\"Select all visible versions\"\n />\n ),\n className: \"w-12\",\n render: (v) => (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedVersionIds.has(v.id)}\n onChange={(checked) =>\n toggleVersionSelection(v.id, checked)\n }\n ariaLabel={`Select version ${v.version}`}\n />\n </div>\n ),\n },\n {\n key: \"version\",\n header: tr(\"devportal.version\", \"Version\"),\n render: (v) => (\n <div className=\"flex items-center gap-2\">\n {getStatusIcon(v)}\n <span className=\"font-mono font-medium\">{v.version}</span>\n {v.isLatest && (\n <span className=\"rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs text-status-success-text\">\n {tr(\"devportal.latest\", \"Latest\")}\n </span>\n )}\n {!v.isStable && (\n <span className=\"rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-xs text-status-warning-text\">\n {tr(\"devportal.beta\", \"Beta\")}\n </span>\n )}\n </div>\n ),\n },\n {\n key: \"releaseNotes\",\n header: tr(\"devportal.releaseNotes\", \"Release Notes\"),\n render: (v) => (\n <p className=\"max-w-md truncate text-sm text-text-secondary\">\n {v.releaseNotes ||\n tr(\"devportal.noReleaseNotes\", \"No release notes\")}\n </p>\n ),\n },\n {\n key: \"status\",\n header: tr(\"devportal.status\", \"Status\"),\n render: (v) => (\n <div className=\"space-y-1\">\n <StatusBadge\n status={\n v.status === \"pending_review\" ? \"In Review\" : v.status\n }\n />\n {v.status === \"pending_review\" && (\n <p className=\"text-xs text-status-info-text\">\n Awaiting platform review\n </p>\n )}\n {v.status === \"rejected\" && v.reviewNotes && (\n <p className=\"text-xs text-status-error-text max-w-xs\">\n {v.reviewNotes}\n </p>\n )}\n </div>\n ),\n },\n {\n key: \"publishedAt\",\n header: tr(\"devportal.published\", \"Published\"),\n render: (v) =>\n v.publishedAt\n ? format(new Date(v.publishedAt), \"MMM d, yyyy\")\n : \"-\",\n },\n {\n key: \"manifest\",\n header: tr(\"devportal.manifest\", \"Manifest\"),\n render: (v) =>\n v.manifest ? (\n <ManifestViewer\n manifest={v.manifest as Record<string, unknown>}\n tr={tr}\n />\n ) : (\n <span className=\"text-xs text-text-secondary\">\n {tr(\"devportal.noManifest\", \"No manifest\")}\n </span>\n ),\n },\n {\n key: \"actions\",\n header: \"\",\n className: \"w-48\",\n render: (v) => (\n <div className=\"flex flex-wrap gap-2\">\n {/* Edit draft/rejected versions before submission */}\n {(v.status === \"draft\" || v.status === \"rejected\") &&\n canCreate && (\n <button\n className=\"inline-flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary hover:underline\"\n onClick={() => {\n const existingManifest = v.manifest\n ? JSON.stringify(v.manifest, null, 2)\n : \"\";\n setEditDialog({\n versionId: v.id,\n version: v.version,\n hasExistingZip: !!v.packageUrl,\n newPackageUrl: \"\",\n newPackageSize: \"\",\n manifestJson: existingManifest,\n originalManifestJson: existingManifest,\n releaseNotes: v.releaseNotes ?? \"\",\n changelog: v.changelog ?? \"\",\n });\n setEditManifestFileName(null);\n setEditDialogError(null);\n }}\n >\n Edit\n </button>\n )}\n {/* Only show \"Submit for Review\" on a version when the app is already\n published — for a first-time app the whole submission goes through\n the app-level \"Submit for Review\" (store listing + pricing + version). */}\n {(v.status === \"draft\" || v.status === \"rejected\") &&\n app?.status === \"PUBLISHED\" && (\n <button\n className=\"inline-flex items-center gap-1 text-xs text-primary hover:underline disabled:opacity-50 disabled:cursor-not-allowed\"\n disabled={\n !canPublish ||\n !appReadyForSubmission ||\n hasPendingVersion\n }\n aria-disabled={\n !canPublish ||\n !appReadyForSubmission ||\n hasPendingVersion\n }\n title={\n hasPendingVersion\n ? tr(\n \"devportal.versionAlreadyPending\",\n \"A version is already pending review\",\n )\n : !appReadyForSubmission\n ? appReadinessBlockers.join(\" · \")\n : undefined\n }\n onClick={() => handlePublish(v.id)}\n >\n <Send size={11} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </button>\n )}\n {v.status === \"published\" && !v.isLatest && (\n <button\n className=\"text-xs text-status-warning-text hover:underline disabled:opacity-50\"\n disabled={!canDeprecate}\n aria-disabled={!canDeprecate}\n onClick={() => handleDeprecate(v.id)}\n >\n {tr(\"devportal.deprecate\", \"Deprecate\")}\n </button>\n )}\n </div>\n ),\n },\n ]}\n />\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title={tr(\"devportal.noVersionsYet\", \"No versions yet\")}\n description={tr(\n \"devportal.noVersionsYetDescription\",\n \"Create your first version to start distributing your app\",\n )}\n action={\n <button\n onClick={() => {\n setCreateDialogError(null);\n setShowCreateDialog(true);\n }}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createVersion\", \"Create Version\")}\n </button>\n }\n />\n )}\n\n {/* Create Version Dialog */}\n {showCreateDialog && (\n <ConfirmDialog\n open={showCreateDialog}\n onOpenChange={(open) => {\n setShowCreateDialog(open);\n if (!open) setCreateDialogError(null);\n }}\n onConfirm={handleCreate}\n title={tr(\"devportal.createNewVersion\", \"Create New Version\")}\n confirmLabel={\n creating\n ? tr(\"devportal.creating\", \"Creating...\")\n : tr(\"devportal.createVersion\", \"Create Version\")\n }\n >\n <div className=\"space-y-4\">\n {createDialogError && (\n <div className=\"rounded-lg border border-status-error-bg bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n {createDialogError}\n </div>\n )}\n <InputField\n label={tr(\"devportal.versionNumber\", \"Version Number\")}\n value={newVersion.version}\n onChange={(e) =>\n setNewVersion({ ...newVersion, version: e.target.value })\n }\n placeholder=\"e.g., 2.2.0\"\n hint={\n manifestDerivedVersion\n ? tr(\n \"devportal.versionHintAutoFilled\",\n \"Filled in from the manifest's version — edit it there if this is wrong.\",\n )\n : tr(\n \"devportal.versionHint\",\n \"Use semantic versioning (major.minor.patch). Upload a manifest.json/manifest with a version to fill this in automatically.\",\n )\n }\n readOnly={!!manifestDerivedVersion}\n required\n />\n {isManifestOnlyType && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {isWorkflowApp\n ? \"Workflow Definition (JSON)\"\n : \"Manifest (JSON)\"}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n rows={10}\n required\n placeholder={\n isWorkflowApp\n ? `{\\n \"nodes\": [],\\n \"edges\": []\\n}`\n : `{\\n \"manifestVersion\": \"1.0\",\\n \"identity\": { \"name\": \"My Item\", \"version\": \"1.0.0\" }\\n}`\n }\n value={newVersion.manifestJson}\n onChange={(e) => {\n const extractedVersion = extractVersionFromManifest(\n e.target.value,\n );\n setNewVersion({\n ...newVersion,\n manifestJson: e.target.value,\n ...(extractedVersion\n ? { version: extractedVersion }\n : {}),\n });\n }}\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-secondary\">\n {isWorkflowApp ? (\n <>\n Paste the full <code>{`{nodes, edges}`}</code> JSON.\n Saved as this version&apos;s manifest — no zip needed.\n </>\n ) : (\n \"Paste the manifest JSON for this version. No zip needed.\"\n )}\n </p>\n </div>\n )}\n {/* Zip upload — node apps only */}\n {isNodeApp && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n Package (.zip){\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"flex gap-2 items-center\">\n <input\n ref={zipInputRef}\n type=\"file\"\n accept=\".zip\"\n className=\"hidden\"\n onChange={handleZipUpload}\n />\n <button\n type=\"button\"\n disabled={zipUploading}\n onClick={() => zipInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-bg-sunken transition-colors disabled:opacity-50\"\n >\n {zipUploading ? (\n <>\n <Loader2 size={14} className=\"animate-spin\" />{\" \"}\n Uploading… {zipProgress}%\n </>\n ) : (\n <>\n <Upload size={14} />{\" \"}\n {newVersion.packageUrl ? \"Replace zip\" : \"Upload zip\"}\n </>\n )}\n </button>\n {newVersion.packageUrl && !zipUploading && (\n <span className=\"text-xs text-status-success-text\">\n ✓ Uploaded\n </span>\n )}\n </div>\n {zipUploadError && (\n <p className=\"text-xs text-status-error-text\">\n {zipUploadError}\n </p>\n )}\n <p className=\"text-xs text-text-tertiary\">\n The zip is the node executable. Upload it before publishing\n — users install exactly this artifact.\n </p>\n </div>\n )}\n\n {/* Manifest JSON — node apps only (required) */}\n {isNodeApp && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2 flex-wrap\">\n <label className=\"text-sm font-medium\">\n manifest.json{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"flex items-center gap-2\">\n {manifestFileName && (\n <span className=\"text-xs text-status-success-text\">\n ✓ {manifestFileName}\n </span>\n )}\n <input\n ref={manifestInputRef}\n type=\"file\"\n accept=\".json,application/json\"\n className=\"hidden\"\n onChange={handleManifestFileUpload}\n />\n <button\n type=\"button\"\n onClick={() => manifestInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium hover:bg-bg-sunken transition-colors\"\n >\n <Upload size={12} />\n Upload manifest.json\n </button>\n </div>\n </div>\n <textarea\n rows={5}\n placeholder={`{\\n \"manifestVersion\": \"1.0\",\\n \"itemType\": \"node\",\\n \"identity\": { \"version\": \"1.0.0\", \"displayName\": \"My Node\" }\\n}`}\n value={newVersion.manifestJson}\n onChange={(e) => {\n setManifestFileName(null);\n const extractedVersion = extractVersionFromManifest(\n e.target.value,\n );\n setNewVersion({\n ...newVersion,\n manifestJson: e.target.value,\n ...(extractedVersion\n ? { version: extractedVersion }\n : {}),\n });\n }}\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-tertiary\">\n Upload or paste your <code>manifest.json</code> — required\n so the platform knows your node&apos;s inputs, outputs, and\n operations. Not extracted from the zip automatically.\n </p>\n </div>\n )}\n\n {/* Required scopes — integration/app types only */}\n {isIntegrationApp && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n Required scopes{\" \"}\n <span className=\"text-xs font-normal text-text-secondary\">\n (optional)\n </span>\n </label>\n <input\n type=\"text\"\n value={newVersion.requiredScopes}\n onChange={(e) =>\n setNewVersion({\n ...newVersion,\n requiredScopes: e.target.value,\n })\n }\n placeholder=\"e.g. read:contacts, write:messages\"\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-sm placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-tertiary\">\n Comma-separated. List every permission this version needs —\n users will be prompted to accept any new or changed scopes\n on update.\n </p>\n </div>\n )}\n <MarkdownEditor\n label={tr(\"devportal.releaseNotes\", \"Release Notes\")}\n value={newVersion.releaseNotes}\n onChange={(value) =>\n setNewVersion({ ...newVersion, releaseNotes: value })\n }\n placeholder={tr(\n \"devportal.releaseNotesPlaceholder\",\n \"What changed in this release?\",\n )}\n rows={3}\n />\n <MarkdownEditor\n label={tr(\"devportal.changelog\", \"Changelog\")}\n value={newVersion.changelog}\n onChange={(value) =>\n setNewVersion({ ...newVersion, changelog: value })\n }\n placeholder={tr(\n \"devportal.changelogPlaceholder\",\n \"Detailed changelog for this version...\",\n )}\n rows={3}\n />\n </div>\n </ConfirmDialog>\n )}\n\n {/* Reject version dialog */}\n {rejectDialog && (\n <ConfirmDialog\n open={!!rejectDialog}\n onOpenChange={(open) => {\n if (!open) {\n setRejectDialog(null);\n setRejectReason(\"\");\n }\n }}\n onConfirm={handleRejectConfirm}\n title={`Reject version ${rejectDialog.version}`}\n confirmLabel=\"Reject Version\"\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"danger\"\n >\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n The developer will be notified and can fix and resubmit. Please\n provide a clear reason.\n </p>\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n Rejection reason{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n rows={3}\n value={rejectReason}\n onChange={(e) => setRejectReason(e.target.value)}\n placeholder=\"e.g. Manifest contains disallowed network calls to external domains...\"\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-sm placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n </ConfirmDialog>\n )}\n\n {/* Edit Version Dialog */}\n {editDialog && (\n <ConfirmDialog\n open={!!editDialog}\n onOpenChange={(open) => {\n if (!open) {\n setEditDialog(null);\n setEditManifestFileName(null);\n setEditDialogError(null);\n }\n }}\n onConfirm={handleEditSave}\n title={`Edit Version ${editDialog.version}`}\n confirmLabel={updating ? \"Saving…\" : \"Save Changes\"}\n >\n <div className=\"space-y-4\">\n {editDialogError && (\n <div className=\"rounded-lg border border-status-error-bg bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n {editDialogError}\n </div>\n )}\n <div className=\"rounded-lg border border-status-info-bg bg-status-info-bg-subtle px-3 py-2 text-xs text-status-info-text\">\n You can fix the zip, manifest, or release notes before\n submitting for review. Once submitted for review these fields\n are locked.\n </div>\n\n {/* ZIP replacement — node apps */}\n {isNodeApp && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">Package (.zip)</label>\n <div className=\"flex gap-2 items-center\">\n <input\n ref={editZipInputRef}\n type=\"file\"\n accept=\".zip\"\n className=\"hidden\"\n onChange={handleEditZipUpload}\n />\n <button\n type=\"button\"\n disabled={zipUploading}\n onClick={() => editZipInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-bg-sunken transition-colors disabled:opacity-50\"\n >\n {zipUploading ? (\n <>\n <Loader2 size={14} className=\"animate-spin\" />{\" \"}\n Uploading… {zipProgress}%\n </>\n ) : (\n <>\n <Upload size={14} />\n {editDialog.newPackageUrl\n ? \"Replace zip again\"\n : editDialog.hasExistingZip\n ? \"Replace zip\"\n : \"Upload zip\"}\n </>\n )}\n </button>\n {editDialog.newPackageUrl && !zipUploading && (\n <span className=\"text-xs text-status-success-text\">\n ✓ New zip ready\n </span>\n )}\n {!editDialog.newPackageUrl && editDialog.hasExistingZip && (\n <span className=\"text-xs text-text-secondary\">\n Current zip kept\n </span>\n )}\n </div>\n {zipUploadError && (\n <p className=\"text-xs text-status-error-text\">\n {zipUploadError}\n </p>\n )}\n </div>\n )}\n\n {/* Manifest replacement — node apps */}\n {isNodeApp && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2 flex-wrap\">\n <label className=\"text-sm font-medium\">\n manifest.json{\" \"}\n <span className=\"text-xs font-normal text-text-secondary\">\n (edit below or upload a new file)\n </span>\n </label>\n <div className=\"flex items-center gap-2\">\n {editManifestFileName && (\n <span className=\"text-xs text-status-success-text\">\n ✓ {editManifestFileName}\n </span>\n )}\n <input\n ref={editManifestInputRef}\n type=\"file\"\n accept=\".json,application/json\"\n className=\"hidden\"\n onChange={handleEditManifestUpload}\n />\n <button\n type=\"button\"\n onClick={() => editManifestInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium hover:bg-bg-sunken transition-colors\"\n >\n <Upload size={12} /> Upload manifest.json\n </button>\n </div>\n </div>\n <textarea\n rows={5}\n placeholder={`{\\n \"manifestVersion\": \"1.0\",\\n \"itemType\": \"node\",\\n \"identity\": { \"version\": \"1.0.0\", \"displayName\": \"My Node\" }\\n}`}\n value={editDialog.manifestJson}\n onChange={(e) => {\n setEditManifestFileName(null);\n setEditDialog((prev) =>\n prev ? { ...prev, manifestJson: e.target.value } : prev,\n );\n }}\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n )}\n\n {/* Workflow definition replacement */}\n {isManifestOnlyType && (\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {isWorkflowApp\n ? \"Workflow Definition (JSON)\"\n : \"Manifest (JSON)\"}{\" \"}\n <span className=\"text-xs font-normal text-text-secondary\">\n (leave empty to keep existing)\n </span>\n </label>\n <textarea\n rows={10}\n placeholder={\n isWorkflowApp\n ? `{\\n \"nodes\": [],\\n \"edges\": []\\n}`\n : `{\\n \"manifestVersion\": \"1.0\",\\n \"identity\": { \"name\": \"My Item\", \"version\": \"1.0.0\" }\\n}`\n }\n value={editDialog.manifestJson}\n onChange={(e) =>\n setEditDialog((prev) =>\n prev ? { ...prev, manifestJson: e.target.value } : prev,\n )\n }\n className=\"w-full rounded-md border bg-transparent px-3 py-2 text-xs font-mono resize-y placeholder:text-text-secondary focus:outline-none focus:ring-1 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n )}\n\n <MarkdownEditor\n label={tr(\"devportal.releaseNotes\", \"Release Notes\")}\n value={editDialog.releaseNotes}\n onChange={(value) =>\n setEditDialog((prev) =>\n prev ? { ...prev, releaseNotes: value } : prev,\n )\n }\n placeholder={tr(\n \"devportal.releaseNotesPlaceholder\",\n \"What changed in this release?\",\n )}\n rows={3}\n />\n <MarkdownEditor\n label={tr(\"devportal.changelog\", \"Changelog\")}\n value={editDialog.changelog}\n onChange={(value) =>\n setEditDialog((prev) =>\n prev ? { ...prev, changelog: value } : prev,\n )\n }\n placeholder={tr(\n \"devportal.changelogPlaceholder\",\n \"Detailed changelog for this version...\",\n )}\n rows={3}\n />\n </div>\n </ConfirmDialog>\n )}\n\n <ConfirmDialog\n open={bulkAction === \"publish\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={handleBulkPublish}\n title={tr(\n \"devportal.submitSelectedVersions\",\n \"Submit selected versions for review\",\n )}\n description={`Submit ${publishableVersions.length} selected version${publishableVersions.length === 1 ? \"\" : \"s\"} for platform review?`}\n confirmLabel={tr(\"devportal.submitForReview\", \"Submit for Review\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"success\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"deprecate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={handleBulkDeprecate}\n title={tr(\n \"devportal.deprecateSelectedVersions\",\n \"Deprecate selected versions\",\n )}\n description={`${tr(\"devportal.deprecate\", \"Deprecate\")} ${deprecatableVersions.length} selected version${deprecatableVersions.length === 1 ? \"\" : \"s\"}? ${tr(\"devportal.deprecateVersionsWarning\", \"Deprecated versions remain visible but should no longer be promoted.\")}`}\n confirmLabel={tr(\"devportal.deprecate\", \"Deprecate\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
@@ -461,7 +461,6 @@ export declare const enTranslations: {
461
461
  gridView: string;
462
462
  guides: string;
463
463
  hide: string;
464
- hideManifest: string;
465
464
  hintMissingBilling: string;
466
465
  hintMissingCategory: string;
467
466
  hintMissingDescription: string;
@@ -552,7 +551,9 @@ export declare const enTranslations: {
552
551
  manageYourDevTeams: string;
553
552
  manageYourOrganizationsTeam: string;
554
553
  manageYourPhysicalProductListings: string;
554
+ manifest: string;
555
555
  manifestDisplayName: string;
556
+ manifestJson: string;
556
557
  manualVerification: string;
557
558
  markdownSupported: string;
558
559
  marketplacePreview: string;
@@ -615,6 +616,7 @@ export declare const enTranslations: {
615
616
  noGrantedDelegationsDescription: string;
616
617
  noItemsMatchYourSearch: string;
617
618
  noItemsYet: string;
619
+ noManifest: string;
618
620
  noMatchingWorkspaces: string;
619
621
  noMembers: string;
620
622
  noOAuthAppsFound: string;
@@ -1180,6 +1182,7 @@ export declare const enTranslations: {
1180
1182
  versionDeprecateFailed: string;
1181
1183
  versionDeprecatedSuccess: string;
1182
1184
  versionHint: string;
1185
+ versionHintAutoFilled: string;
1183
1186
  versionManagement: string;
1184
1187
  versionManagementDescription: string;
1185
1188
  versionManagementPurposeIntegration: string;
@@ -1 +1 @@
1
- {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/translations/en.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA44C1B,CAAC"}
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/translations/en.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAi5C1B,CAAC"}
@@ -449,7 +449,6 @@ var e = { devportal: {
449
449
  gridView: "Grid view",
450
450
  guides: "Guides",
451
451
  hide: "Hide",
452
- hideManifest: "Hide manifest",
453
452
  hintMissingBilling: "Link a billing account in the Pricing tab to receive payouts",
454
453
  hintMissingCategory: "Select a category on the Store Listing tab",
455
454
  hintMissingDescription: "Add a full description on the Store Listing tab",
@@ -540,7 +539,9 @@ var e = { devportal: {
540
539
  manageYourDevTeams: "Manage your development teams",
541
540
  manageYourOrganizationsTeam: "Manage your organization's team",
542
541
  manageYourPhysicalProductListings: "Manage your physical product listings.",
542
+ manifest: "Manifest",
543
543
  manifestDisplayName: "Display Name",
544
+ manifestJson: "manifest.json",
544
545
  manualVerification: "Manual review",
545
546
  markdownSupported: "Markdown formatting is supported",
546
547
  marketplacePreview: "Marketplace Preview",
@@ -603,6 +604,7 @@ var e = { devportal: {
603
604
  noGrantedDelegationsDescription: "You haven't granted any app delegations to other users.",
604
605
  noItemsMatchYourSearch: "No items match your search",
605
606
  noItemsYet: "No items yet",
607
+ noManifest: "No manifest",
606
608
  noMatchingWorkspaces: "No matching workspaces",
607
609
  noMembers: "No members",
608
610
  noOAuthAppsFound: "No OAuth apps found",
@@ -1161,7 +1163,8 @@ var e = { devportal: {
1161
1163
  versionCreatedSuccess: "Version created successfully",
1162
1164
  versionDeprecateFailed: "Failed to deprecate version",
1163
1165
  versionDeprecatedSuccess: "Version deprecated successfully",
1164
- versionHint: "Use semantic versioning (major.minor.patch)",
1166
+ versionHint: "Use semantic versioning (major.minor.patch). Upload a manifest.json/manifest with a version to fill this in automatically.",
1167
+ versionHintAutoFilled: "Filled in from the manifest's version — edit it there if this is wrong.",
1165
1168
  versionManagement: "Version Management",
1166
1169
  versionManagementDescription: "Manage your application versions",
1167
1170
  versionManagementPurposeIntegration: "Versions track permission and webhook changes for your integration. No zip or manifest is needed — create a new version whenever you add or change required scopes so users can review and accept the updated permissions.",