From 4e19f925c63b66c7e14aba494be32a1f904bed0e Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 23 Apr 2026 00:42:48 +0200 Subject: [PATCH] ui(deploy): loading-aware default for dirty-state baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously `dirtyState?.dirty ?? true` caused a stale `Redeploy` label to flash briefly while the first fetch was in flight. Gate the default on isLoading so the button starts as `Save (disabled)` until the endpoint resolves — spurious Redeploy clicks were harmless but the loading-state UX was wrong. Co-Authored-By: Claude Opus 4.7 (1M context) --- ui/src/pages/AppsTab/AppDeploymentPage/index.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx index 127a4476..e12db860 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx +++ b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx @@ -62,7 +62,7 @@ export default function AppDeploymentPage() { const activeDeployment = deployments.find((d) => d.status === 'STARTING') ?? null; const { data: agentConfig = null } = useApplicationConfig(app?.slug, selectedEnv); - const { data: dirtyState } = useDirtyState(selectedEnv, app?.slug); + const { data: dirtyState, isLoading: dirtyLoading } = useDirtyState(selectedEnv, app?.slug); // Mutations const createApp = useCreateApp(); @@ -113,7 +113,11 @@ export default function AppDeploymentPage() { const dirty = useFormDirty(form, serverState, stagedJar); const { dialogOpen: blockerOpen, confirm: blockerConfirm, cancel: blockerCancel } = useUnsavedChangesBlocker(dirty.anyLocalEdit); - const serverDirtyAgainstDeploy = dirtyState?.dirty ?? true; + // Before the first dirty-state fetch resolves, default to "not dirty" so the + // primary button shows `Save (disabled)` — not a stale `Redeploy`. Once loaded, + // fall back to `true` if the endpoint failed entirely (fail-safe for the + // redeploy path). + const serverDirtyAgainstDeploy = app && dirtyLoading ? false : (dirtyState?.dirty ?? true); const deploymentInProgress = !!activeDeployment; const primaryMode = computeMode({ deploymentInProgress,