From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 1C5D81FF0AB for ; Wed, 07 Oct 2026 15:45:28 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id A4FB42133C; Wed, 07 Oct 2026 15:45:26 +0200 (CEST) From: Jonas Theisen To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup v2 4/6] fix #7904: ui: job edit: introduce "Enable" checkbox for {sync,verify,tape,GC} jobs Date: Wed, 7 Oct 2026 15:43:52 +0200 Message-ID: <20261007134500.323872-5-j.theisen@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261007134500.323872-1-j.theisen@proxmox.com> References: <20261007134500.323872-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: 1791380722578 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.183 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: NCIGSA37RTKNLYIHD36JGCZEC4YY7GNZ X-Message-ID-Hash: NCIGSA37RTKNLYIHD36JGCZEC4YY7GNZ 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 allow users to disable jobs from the UI using the "enable" API paramter. This also disallows the schedule from being empty since disabling jobs can now be done with the "enable" parameter. To avoid user confusion and remain backwards compatible, the setValues function automatically sets the "enable" parameter to false if the schedule is currently empty i.e. the job is disabled. Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=7904 Signed-off-by: Jonas Theisen --- www/config/GCView.js | 2 ++ www/tape/window/TapeBackupJob.js | 30 ++++++++++++++++++++++-- www/window/GCJobEdit.js | 39 ++++++++++++++++++++++++++++---- www/window/SyncJobEdit.js | 26 +++++++++++++++++++-- www/window/VerifyJobEdit.js | 30 ++++++++++++++++++++++-- 5 files changed, 116 insertions(+), 11 deletions(-) diff --git a/www/config/GCView.js b/www/config/GCView.js index 9fcc22344..5077f0566 100644 --- a/www/config/GCView.js +++ b/www/config/GCView.js @@ -5,6 +5,7 @@ Ext.define('pbs-gc-jobs-status', { 'upid', 'removed-bytes', 'pending-bytes', + 'enable', 'schedule', 'next-run', 'last-run-endtime', @@ -73,6 +74,7 @@ Ext.define('PBS.config.GCJobView', { datastore: data.store, id: data.store, schedule: data.schedule, + enable: data.enable, listeners: { destroy: () => this.reload(), }, diff --git a/www/tape/window/TapeBackupJob.js b/www/tape/window/TapeBackupJob.js index ad03b6076..2c50470e5 100644 --- a/www/tape/window/TapeBackupJob.js +++ b/www/tape/window/TapeBackupJob.js @@ -46,6 +46,14 @@ Ext.define('PBS.TapeManagement.BackupJobEdit', { }, }, + setValues: function (values) { + let me = this; + if (!values.schedule || values.schedule === '') { + values.enable = false; + } + me.callParent([values]); + }, + items: { xtype: 'tabpanel', bodyPadding: 10, @@ -112,13 +120,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 task.'), + }, + listeners: { + change: function (field, enabled) { + let me = this; + let view = me.up('pbsTapeBackupJobEdit'); + let schedule = view.down('field[name=schedule]'); + schedule.setDisabled(!enabled); + }, + }, + uncheckedValue: false, + value: true, + }, { fieldLabel: gettext('Schedule'), xtype: 'pbsCalendarEvent', name: 'schedule', - emptyText: gettext('none (disabled)'), + allowBlank: false, cbind: { - deleteEmpty: '{!isCreate}', value: '{scheduleValue}', }, }, diff --git a/www/window/GCJobEdit.js b/www/window/GCJobEdit.js index 6afcf7de1..e1a94754d 100644 --- a/www/window/GCJobEdit.js +++ b/www/window/GCJobEdit.js @@ -19,10 +19,39 @@ Ext.define('PBS.window.GCJobEdit', { return {}; }, - items: { - xtype: 'pbsCalendarEvent', - name: 'gc-schedule', - fieldLabel: gettext('GC Schedule'), - emptyText: gettext('none (disabled)'), + setValues: function (values) { + let me = this; + if (!values['gc-schedule'] || values['gc-schedule'] === '') { + values['gc-enable'] = false; + } + me.callParent([values]); }, + + items: [ + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Enable'), + name: 'gc-enable', + autoEl: { + tag: 'div', + 'data-qtip': gettext('Enable scheduled execution of this task.'), + }, + listeners: { + change: function (field, enabled) { + let me = this; + let view = me.up('pbsGCJobEdit'); + let schedule = view.down('field[name=gc-schedule]'); + schedule.setDisabled(!enabled); + }, + }, + uncheckedValue: false, + value: true, + }, + { + xtype: 'pbsCalendarEvent', + name: 'gc-schedule', + fieldLabel: gettext('GC Schedule'), + allowBlank: false, + }, + ], }); diff --git a/www/window/SyncJobEdit.js b/www/window/SyncJobEdit.js index 961ce2951..9ff949b22 100644 --- a/www/window/SyncJobEdit.js +++ b/www/window/SyncJobEdit.js @@ -97,6 +97,10 @@ Ext.define('PBS.window.SyncJobEdit', { } else { values.location = 'remote'; } + + if (!values.schedule || values.schedule === '') { + values.enable = false; + } me.callParent([values]); }, @@ -203,13 +207,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 task.'), + }, + listeners: { + change: function (field, enabled) { + let me = this; + let view = me.up('pbsSyncJobEdit'); + let schedule = view.down('field[name=schedule]'); + schedule.setDisabled(!enabled); + }, + }, + uncheckedValue: false, + value: true, + }, { xtype: 'pbsCalendarEvent', name: 'schedule', fieldLabel: gettext('Sync Schedule'), - emptyText: gettext('none'), + allowBlank: false, cbind: { - deleteEmpty: '{!isCreate}', value: '{scheduleValue}', }, }, diff --git a/www/window/VerifyJobEdit.js b/www/window/VerifyJobEdit.js index b8d8b5810..c8e54e0f2 100644 --- a/www/window/VerifyJobEdit.js +++ b/www/window/VerifyJobEdit.js @@ -80,6 +80,14 @@ Ext.define('PBS.window.VerifyJobEdit', { }, }, + setValues: function (values) { + let me = this; + if (!values.schedule || values.schedule === '') { + values.enable = false; + } + me.callParent([values]); + }, + items: { xtype: 'inputpanel', onGetValues: function (values) { @@ -124,14 +132,32 @@ Ext.define('PBS.window.VerifyJobEdit', { ], column2: [ + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Enable'), + name: 'enable', + autoEl: { + tag: 'div', + 'data-qtip': gettext('Enable scheduled execution of this task.'), + }, + listeners: { + change: function (field, enabled) { + let me = this; + let view = me.up('pbsVerifyJobEdit'); + let schedule = view.down('field[name=schedule]'); + schedule.setDisabled(!enabled); + }, + }, + uncheckedValue: false, + value: true, + }, { xtype: 'pbsCalendarEvent', name: 'schedule', fieldLabel: gettext('Schedule'), - emptyText: gettext('none (disabled)'), + allowBlank: false, cbind: { value: '{scheduleValue}', - deleteEmpty: '{!isCreate}', }, }, { -- 2.47.3