From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id F115C1FF0C0 for ; Wed, 04 Nov 2026 15:54:44 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 2FFF621420; Wed, 04 Nov 2026 15:54:44 +0100 (CET) From: Jonas Theisen To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup v5 7/9] fix #7904: ui: add "Enable" checkbox to {sync,verify,tape,GC} job edit Date: Wed, 4 Nov 2026 15:53:33 +0100 Message-ID: <20261104145405.441861-8-j.theisen@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261104145405.441861-1-j.theisen@proxmox.com> References: <20261104145405.441861-1-j.theisen@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1793804076782 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.100 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: BTKKQVG6GQZZRJV5PFE4HUUR23BDMZ5L X-Message-ID-Hash: BTKKQVG6GQZZRJV5PFE4HUUR23BDMZ5L X-MailFrom: j.theisen@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This allows users to disable jobs from the UI using the "disable" API parameter. This also disallows the schedule from being empty, since disabling jobs can now be done with the "disable" parameter. To avoid user confusion and remain backwards compatible, the setValues function automatically sets the "disable" parameter to true if the schedule is currently empty, i.e. the job is disabled. For this to work the value for the checkbox needs to be set explicitely despite the bind, since the viewModel binds the value asynchronously and such the GET could finish before that happend which would lose the value from the config. Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=7904 Signed-off-by: Jonas Theisen --- www/tape/window/TapeBackupJob.js | 37 +++++++++++++++++++++-- www/window/GCJobEdit.js | 52 +++++++++++++++++++++++++++++--- www/window/SyncJobEdit.js | 34 +++++++++++++++++++-- www/window/VerifyJobEdit.js | 33 ++++++++++++++++++-- 4 files changed, 142 insertions(+), 14 deletions(-) diff --git a/www/tape/window/TapeBackupJob.js b/www/tape/window/TapeBackupJob.js index ad03b6076..4b431b8ad 100644 --- a/www/tape/window/TapeBackupJob.js +++ b/www/tape/window/TapeBackupJob.js @@ -46,6 +46,20 @@ Ext.define('PBS.TapeManagement.BackupJobEdit', { }, }, + viewModel: { + data: { + jobEnabled: true, + }, + }, + + setValues: function (values) { + let me = this; + if (!values.schedule) { + values.disable = true; + } + me.callParent([values]); + }, + items: { xtype: 'tabpanel', bodyPadding: 10, @@ -66,8 +80,9 @@ Ext.define('PBS.TapeManagement.BackupJobEdit', { delete values.delete; } - return values; + return PBS.Utils.enableToDisable(values); }, + onSetValues: (values) => PBS.Utils.disableToEnable(values), cbind: { isCreate: '{isCreate}', // pass it through }, @@ -112,15 +127,31 @@ Ext.define('PBS.TapeManagement.BackupJobEdit', { ], column2: [ + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Enable'), + name: 'enable', + autoEl: { + tag: 'div', + 'data-qtip': gettext('Enable scheduled execution of this job.'), + }, + bind: { + value: '{jobEnabled}', + }, + uncheckedValue: false, + value: true, // value needs to be set despite bind for setValues to work + }, { fieldLabel: gettext('Schedule'), xtype: 'pbsCalendarEvent', name: 'schedule', - emptyText: gettext('none (disabled)'), + allowBlank: false, cbind: { - deleteEmpty: '{!isCreate}', value: '{scheduleValue}', }, + bind: { + disabled: '{!jobEnabled}', + }, }, { fieldLabel: gettext('Export Media-Set'), diff --git a/www/window/GCJobEdit.js b/www/window/GCJobEdit.js index 6afcf7de1..ae221726d 100644 --- a/www/window/GCJobEdit.js +++ b/www/window/GCJobEdit.js @@ -19,10 +19,52 @@ Ext.define('PBS.window.GCJobEdit', { return {}; }, - items: { - xtype: 'pbsCalendarEvent', - name: 'gc-schedule', - fieldLabel: gettext('GC Schedule'), - emptyText: gettext('none (disabled)'), + viewModel: { + data: { + gcEnabled: true, + }, }, + + setValues: function (values) { + let me = this; + if (!values['gc-schedule']) { + values['gc-disable'] = true; + } + + PBS.Utils.disableToEnable(values, 'gc-'); + me.callParent([values]); + }, + + getValues: function (dirtyOnly) { + let me = this; + let values = me.callParent([dirtyOnly]); + + return PBS.Utils.enableToDisable(values, 'gc-'); + }, + + items: [ + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Enable'), + name: 'gc-enable', + autoEl: { + tag: 'div', + 'data-qtip': gettext('Enable scheduled execution of this job.'), + }, + bind: { + value: '{gcEnabled}', + }, + uncheckedValue: false, + value: true, // value needs to be set despite bind for setValues to work + }, + { + xtype: 'pbsCalendarEvent', + name: 'gc-schedule', + fieldLabel: gettext('GC Schedule'), + allowBlank: false, + bind: { + disabled: '{!gcEnabled}', + }, + }, + ], }); diff --git a/www/window/SyncJobEdit.js b/www/window/SyncJobEdit.js index 961ce2951..0f12c9d65 100644 --- a/www/window/SyncJobEdit.js +++ b/www/window/SyncJobEdit.js @@ -90,6 +90,12 @@ Ext.define('PBS.window.SyncJobEdit', { }, }, + viewModel: { + data: { + jobEnabled: true, + }, + }, + setValues: function (values) { let me = this; if (values.id && !values.remote) { @@ -97,6 +103,10 @@ Ext.define('PBS.window.SyncJobEdit', { } else { values.location = 'remote'; } + + if (!values.schedule) { + values.disable = true; + } me.callParent([values]); }, @@ -130,8 +140,10 @@ Ext.define('PBS.window.SyncJobEdit', { PBS.Utils.delete_if_default(values, 'rate-out'); PBS.Utils.delete_if_default(values, 'remote'); } - return values; + + return PBS.Utils.enableToDisable(values); }, + onSetValues: (values) => PBS.Utils.disableToEnable(values), cbind: { isCreate: '{isCreate}', // pass it through }, @@ -203,15 +215,31 @@ Ext.define('PBS.window.SyncJobEdit', { deleteEmpty: '{!isCreate}', }, }, + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Enable'), + name: 'enable', + autoEl: { + tag: 'div', + 'data-qtip': gettext('Enable scheduled execution of this job.'), + }, + bind: { + value: '{jobEnabled}', + }, + uncheckedValue: false, + value: true, // value needs to be set despite bind for setValues to work + }, { xtype: 'pbsCalendarEvent', name: 'schedule', fieldLabel: gettext('Sync Schedule'), - emptyText: gettext('none'), + allowBlank: false, cbind: { - deleteEmpty: '{!isCreate}', value: '{scheduleValue}', }, + bind: { + disabled: '{!jobEnabled}', + }, }, { xtype: 'pmxBandwidthField', diff --git a/www/window/VerifyJobEdit.js b/www/window/VerifyJobEdit.js index b8d8b5810..4b3fdae87 100644 --- a/www/window/VerifyJobEdit.js +++ b/www/window/VerifyJobEdit.js @@ -34,6 +34,7 @@ Ext.define('PBS.window.VerifyJobEdit', { ignoreVerified: true, defaultReadThreads: null, defaultVerifyThreads: null, + jobEnabled: true, }, }, @@ -80,6 +81,14 @@ Ext.define('PBS.window.VerifyJobEdit', { }, }, + setValues: function (values) { + let me = this; + if (!values.schedule) { + values.disable = true; + } + me.callParent([values]); + }, + items: { xtype: 'inputpanel', onGetValues: function (values) { @@ -88,8 +97,10 @@ Ext.define('PBS.window.VerifyJobEdit', { if (!values.id && me.up('pbsVerifyJobEdit').isCreate) { values.id = 'v-' + Ext.data.identifier.Uuid.Global.generate().slice(0, 13); } - return values; + + return PBS.Utils.enableToDisable(values); }, + onSetValues: (values) => PBS.Utils.disableToEnable(values), column1: [ { xtype: 'pmxDisplayEditField', @@ -124,14 +135,30 @@ Ext.define('PBS.window.VerifyJobEdit', { ], column2: [ + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Enable'), + name: 'enable', + autoEl: { + tag: 'div', + 'data-qtip': gettext('Enable scheduled execution of this job.'), + }, + bind: { + value: '{jobEnabled}', + }, + uncheckedValue: false, + value: true, // value needs to be set despite bind for setValues to work + }, { xtype: 'pbsCalendarEvent', name: 'schedule', fieldLabel: gettext('Schedule'), - emptyText: gettext('none (disabled)'), + allowBlank: false, cbind: { value: '{scheduleValue}', - deleteEmpty: '{!isCreate}', + }, + bind: { + disabled: '{!jobEnabled}', }, }, { -- 2.47.3