From 0a71bca7b86238b4dbb2ee0fa2e6db5fe1fcc393 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 23 Apr 2026 00:06:00 +0200 Subject: [PATCH] fix(deploy): redeploy button after save, disable save when clean, success toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bug 1: default serverDirtyAgainstDeploy to true (not false) while dirtyState query is loading — prevents the button showing 'Save' instead of 'Redeploy' on apps with no successful deployment yet. - Bug 2: normalize samplingRate from server as '.0' when the value is a whole-number float so serverState matches form after save, eliminating spurious dirty detection that kept Save enabled. - Bug 3: add success toast after handleSave completes. Co-Authored-By: Claude Sonnet 4.6 --- .../AppsTab/AppDeploymentPage/hooks/useDeploymentPageState.ts | 4 +++- ui/src/pages/AppsTab/AppDeploymentPage/index.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/hooks/useDeploymentPageState.ts b/ui/src/pages/AppsTab/AppDeploymentPage/hooks/useDeploymentPageState.ts index 1e8b7dcb..a570de1a 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/hooks/useDeploymentPageState.ts +++ b/ui/src/pages/AppsTab/AppDeploymentPage/hooks/useDeploymentPageState.ts @@ -96,7 +96,9 @@ export function useDeploymentPageState( agentLogLevel: (agentConfig?.agentLogLevel as string) ?? defaultForm.monitoring.agentLogLevel, metricsEnabled: agentConfig?.metricsEnabled ?? defaultForm.monitoring.metricsEnabled, metricsInterval: defaultForm.monitoring.metricsInterval, - samplingRate: agentConfig?.samplingRate !== undefined ? String(agentConfig.samplingRate) : defaultForm.monitoring.samplingRate, + samplingRate: agentConfig?.samplingRate !== undefined + ? (Number.isInteger(agentConfig.samplingRate) ? `${agentConfig.samplingRate}.0` : String(agentConfig.samplingRate)) + : defaultForm.monitoring.samplingRate, compressSuccess: agentConfig?.compressSuccess ?? defaultForm.monitoring.compressSuccess, replayEnabled: defaultForm.monitoring.replayEnabled, routeControlEnabled: defaultForm.monitoring.routeControlEnabled, diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx index 3ae36f6d..9325042e 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx +++ b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx @@ -113,7 +113,7 @@ export default function AppDeploymentPage() { const dirty = useFormDirty(form, serverState, stagedJar); const { dialogOpen: blockerOpen, confirm: blockerConfirm, cancel: blockerCancel } = useUnsavedChangesBlocker(dirty.anyLocalEdit); - const serverDirtyAgainstDeploy = dirtyState?.dirty ?? false; + const serverDirtyAgainstDeploy = dirtyState?.dirty ?? true; const deploymentInProgress = !!activeDeployment; const primaryMode = computeMode({ deploymentInProgress, @@ -220,6 +220,8 @@ export default function AppDeploymentPage() { setStagedJar(null); + toast({ title: 'Configuration saved', variant: 'success' }); + // Invalidate dirty-state so the button reflects the new saved state await queryClient.invalidateQueries({ queryKey: ['apps', envSlug, targetApp.slug, 'dirty-state'] });