diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx index 702ce4ee..af2229be 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx +++ b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx @@ -88,6 +88,7 @@ export default function AppDeploymentPage() { // Local UI state const [name, setName] = useState(''); const [stagedJar, setStagedJar] = useState(null); + const [uploadPct, setUploadPct] = useState(null); const [tab, setTab] = useState('monitoring'); const [deleteConfirm, setDeleteConfirm] = useState(false); const [stopTarget, setStopTarget] = useState(null); @@ -125,8 +126,10 @@ export default function AppDeploymentPage() { // redeploy path). const serverDirtyAgainstDeploy = app && dirtyLoading ? false : (dirtyState?.dirty ?? true); const deploymentInProgress = !!activeDeployment; + const uploading = uploadPct !== null; const primaryMode = computeMode({ deploymentInProgress, + uploading, hasLocalEdits: dirty.anyLocalEdit, serverDirtyAgainstDeploy, }); @@ -177,7 +180,17 @@ export default function AppDeploymentPage() { // 2. Upload JAR if staged if (stagedJar) { - await uploadJar.mutateAsync({ envSlug, appSlug: targetApp.slug, file: stagedJar }); + setUploadPct(0); + try { + await uploadJar.mutateAsync({ + envSlug, + appSlug: targetApp.slug, + file: stagedJar, + onProgress: setUploadPct, + }); + } finally { + setUploadPct(null); + } } // 3. Save container config @@ -260,8 +273,18 @@ export default function AppDeploymentPage() { let versionId: string; if (stagedJar) { - const newVersion = await uploadJar.mutateAsync({ envSlug, appSlug: app.slug, file: stagedJar }); - versionId = newVersion.id; + setUploadPct(0); + try { + const newVersion = await uploadJar.mutateAsync({ + envSlug, + appSlug: app.slug, + file: stagedJar, + onProgress: setUploadPct, + }); + versionId = newVersion.id; + } finally { + setUploadPct(null); + } } else { if (!currentVersion) { toast({ @@ -346,6 +369,7 @@ export default function AppDeploymentPage() { // ── Primary button enabled logic ─────────────────────────────────── const primaryEnabled = (() => { if (primaryMode === 'deploying') return false; + if (primaryMode === 'uploading') return false; if (primaryMode === 'save') return !!name.trim() && (isNetNew || dirty.anyLocalEdit); return true; // redeploy always enabled })(); @@ -389,6 +413,7 @@ export default function AppDeploymentPage() { {app && latestDeployment && (