Skip no-op saves in the edit dialogs; clear a stale model-spec error
Build image / build-and-push (push) Successful in 26s

A Save that changed nothing still sent a PATCH, which bumped the row's
version and landed an "Edited garden settings" step in History that undid
nothing — the drift is gone since the last commit, but the write was still
there. Both dialogs now close without a request when every field matches
the loaded row.

In Settings, a rejected model spec's reason stayed under the field after
the field was blanked back to the saved value; committing an unchanged
value now clears it.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-08-22 22:22:22 -04:00
co-authored by Claude Fable 5
parent 27f658c1f7
commit 157e04ed24
3 changed files with 16 additions and 0 deletions
@@ -98,6 +98,13 @@ export function GardenDialog({ garden, onClose }: { garden?: Garden; onClose: ()
return return
} }
const input = { name: name.trim(), widthCm, heightCm, unitPref: unit, notes: notes.trim(), gridSizeCm, snapToGrid } const input = { name: name.trim(), widthCm, heightCm, unitPref: unit, notes: notes.trim(), gridSizeCm, snapToGrid }
// Nothing changed: close without a request. A PATCH that writes the same
// row still bumps the version and lands an "Edited garden settings" step
// in History that undoes nothing.
if (isEdit && (Object.keys(input) as (keyof typeof input)[]).every((k) => input[k] === garden[k])) {
onClose()
return
}
try { try {
if (isEdit) await update.mutateAsync({ id: garden.id, ...input, version }) if (isEdit) await update.mutateAsync({ id: garden.id, ...input, version })
else await create.mutateAsync(input) else await create.mutateAsync(input)
@@ -99,6 +99,12 @@ export function PlantDialog({
vendor: vendor.trim(), vendor: vendor.trim(),
notes: notes.trim(), notes: notes.trim(),
} }
// Nothing changed: close without a request, so a look-and-Save doesn't bump
// the version for every garden that shares the plant.
if (isEdit && (Object.keys(input) as (keyof PlantInput)[]).every((k) => input[k] === (k === 'color' ? expandHex(plant.color) : plant[k]))) {
onClose()
return
}
try { try {
if (isEdit) await update.mutateAsync({ id: plant.id, ...input, version }) if (isEdit) await update.mutateAsync({ id: plant.id, ...input, version })
else await create.mutateAsync(input) else await create.mutateAsync(input)
+3
View File
@@ -171,6 +171,9 @@ function AssistantCard({ data }: { data: SettingsResponse }) {
const commit = (field: ModelField, value: string) => { const commit = (field: ModelField, value: string) => {
const v = value.trim() const v = value.trim()
if (v !== settings[field]) save({ [field]: v }) if (v !== settings[field]) save({ [field]: v })
// Back to what's saved (the typo was cleared): nothing to send, and the
// old reason would be about a value no longer in the field.
else setFieldError((e) => (e?.field === field ? null : e))
} }
const errorFor = (field: ModelField) => const errorFor = (field: ModelField) =>
fieldError?.field === field ? <span className="text-accent-700">{fieldError.message}</span> : null fieldError?.field === field ? <span className="text-accent-700">{fieldError.message}</span> : null