From 36cb22ee2a42b480fdcff011fdb0d7e79586f3b2 Mon Sep 17 00:00:00 2001 From: Ivan Bochkarev Date: Tue, 18 Aug 2026 00:59:45 +0600 Subject: [PATCH 1/5] fix(manager): stop settings grid remove from poisoning autosave Cloning saveParams on remove prevents the deleted key/action from leaking into later UpdateFromGrid calls. Settings grids also skip the extra store.remove after refreshFilterOptions already reloads. --- manager/assets/modext/widgets/core/modx.grid.js | 11 ++++++++--- .../assets/modext/widgets/core/modx.grid.settings.js | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/manager/assets/modext/widgets/core/modx.grid.js b/manager/assets/modext/widgets/core/modx.grid.js index d58e11bec30..8bf08320932 100644 --- a/manager/assets/modext/widgets/core/modx.grid.js +++ b/manager/assets/modext/widgets/core/modx.grid.js @@ -1554,7 +1554,9 @@ Ext.extend(MODx.grid.GridBase, Ext.grid.EditorGridPanel, { } const { record } = this.menu, - saveParams = this.config.saveParams || {}, + // Clone — mutating config.saveParams leaks remove action/key into later + // autosave UpdateFromGrid payloads (#14280). + saveParams = Ext.apply({}, this.config.saveParams || {}), primaryKey = this.config.primaryKey || 'id' ; text = text || 'confirm_remove'; @@ -1580,8 +1582,11 @@ Ext.extend(MODx.grid.GridBase, Ext.grid.EditorGridPanel, { }, removeActiveRow: function(record) { - if (this.fireEvent('afterRemoveRow', record)) { - const selection = this.getSelectionModel().getSelected(); + if (!this.fireEvent('afterRemoveRow', record)) { + return; + } + const selection = this.getSelectionModel().getSelected(); + if (selection) { this.getStore().remove(selection); } }, diff --git a/manager/assets/modext/widgets/core/modx.grid.settings.js b/manager/assets/modext/widgets/core/modx.grid.settings.js index ba4ebeef9ff..6ffbf56c99a 100644 --- a/manager/assets/modext/widgets/core/modx.grid.settings.js +++ b/manager/assets/modext/widgets/core/modx.grid.settings.js @@ -300,7 +300,11 @@ MODx.grid.SettingsGrid = function(config = {}) { } }, afterRemoveRow: function() { + // Reload filters + grid. Return false so removeActiveRow does not also + // store.remove(selection) — that races the refresh and can drop another + // row, so later edit/delete hits setting_err_nf (#14280). this.refreshFilterOptions(gridFilterData); + return false; } }); From ba6d5497e0d18dc1e4fddc2a13fea8d0b7b5c899 Mon Sep 17 00:00:00 2001 From: Bochkarev Ivan Date: Tue, 18 Aug 2026 21:38:58 +0600 Subject: [PATCH 2/5] Update manager/assets/modext/widgets/core/modx.grid.js Co-authored-by: Jim Graham --- manager/assets/modext/widgets/core/modx.grid.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/assets/modext/widgets/core/modx.grid.js b/manager/assets/modext/widgets/core/modx.grid.js index 8bf08320932..b77e05b1ded 100644 --- a/manager/assets/modext/widgets/core/modx.grid.js +++ b/manager/assets/modext/widgets/core/modx.grid.js @@ -1554,8 +1554,7 @@ Ext.extend(MODx.grid.GridBase, Ext.grid.EditorGridPanel, { } const { record } = this.menu, - // Clone — mutating config.saveParams leaks remove action/key into later - // autosave UpdateFromGrid payloads (#14280). + // Clone config.saveParams here to avoid modification of the original config object, which would break subsequent calls to updateFromGrid saveParams = Ext.apply({}, this.config.saveParams || {}), primaryKey = this.config.primaryKey || 'id' ; From b9afcb22c6e41bfa78a4324e49a60fb346feb042 Mon Sep 17 00:00:00 2001 From: Bochkarev Ivan Date: Tue, 18 Aug 2026 21:39:09 +0600 Subject: [PATCH 3/5] Update manager/assets/modext/widgets/core/modx.grid.js Co-authored-by: Jim Graham --- manager/assets/modext/widgets/core/modx.grid.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/manager/assets/modext/widgets/core/modx.grid.js b/manager/assets/modext/widgets/core/modx.grid.js index b77e05b1ded..56d71aca658 100644 --- a/manager/assets/modext/widgets/core/modx.grid.js +++ b/manager/assets/modext/widgets/core/modx.grid.js @@ -1581,13 +1581,8 @@ Ext.extend(MODx.grid.GridBase, Ext.grid.EditorGridPanel, { }, removeActiveRow: function(record) { - if (!this.fireEvent('afterRemoveRow', record)) { - return; - } - const selection = this.getSelectionModel().getSelected(); - if (selection) { - this.getStore().remove(selection); - } + this.getStore().remove(record); + this.fireEvent('afterRemoveRow', record); }, refresh: function() { From a6474f9ed172fb1144f203ddde8cc40d2f0ab10c Mon Sep 17 00:00:00 2001 From: Bochkarev Ivan Date: Tue, 18 Aug 2026 21:39:17 +0600 Subject: [PATCH 4/5] Update manager/assets/modext/widgets/core/modx.grid.settings.js Co-authored-by: Jim Graham --- manager/assets/modext/widgets/core/modx.grid.settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/manager/assets/modext/widgets/core/modx.grid.settings.js b/manager/assets/modext/widgets/core/modx.grid.settings.js index 6ffbf56c99a..cdad05be632 100644 --- a/manager/assets/modext/widgets/core/modx.grid.settings.js +++ b/manager/assets/modext/widgets/core/modx.grid.settings.js @@ -304,7 +304,6 @@ MODx.grid.SettingsGrid = function(config = {}) { // store.remove(selection) — that races the refresh and can drop another // row, so later edit/delete hits setting_err_nf (#14280). this.refreshFilterOptions(gridFilterData); - return false; } }); From e5d146ca995931799af85193976eedc7cedd6c52 Mon Sep 17 00:00:00 2001 From: Bochkarev Ivan Date: Tue, 18 Aug 2026 21:39:22 +0600 Subject: [PATCH 5/5] Update manager/assets/modext/widgets/core/modx.grid.settings.js Co-authored-by: Jim Graham --- manager/assets/modext/widgets/core/modx.grid.settings.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/manager/assets/modext/widgets/core/modx.grid.settings.js b/manager/assets/modext/widgets/core/modx.grid.settings.js index cdad05be632..ba4ebeef9ff 100644 --- a/manager/assets/modext/widgets/core/modx.grid.settings.js +++ b/manager/assets/modext/widgets/core/modx.grid.settings.js @@ -300,9 +300,6 @@ MODx.grid.SettingsGrid = function(config = {}) { } }, afterRemoveRow: function() { - // Reload filters + grid. Return false so removeActiveRow does not also - // store.remove(selection) — that races the refresh and can drop another - // row, so later edit/delete hits setting_err_nf (#14280). this.refreshFilterOptions(gridFilterData); } });