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 1BD0C1FF0AF for ; Fri, 06 Nov 2026 18:23:02 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id BC9A321625; Fri, 06 Nov 2026 18:22:56 +0100 (CET) From: Christian Ebner To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-widget-toolkit v2 05/43] form: date time field: track value like other form fields Date: Fri, 6 Nov 2026 18:21:57 +0100 Message-ID: <20261106172235.890542-6-c.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261106172235.890542-1-c.ebner@proxmox.com> References: <20261106172235.890542-1-c.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1793985773164 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.486 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: MY5Z56N5MURLHMEMY6NYPP7NCO4QWLIV X-Message-ID-Hash: MY5Z56N5MURLHMEMY6NYPP7NCO4QWLIV X-MailFrom: c.ebner@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: The value was only kept in the view model and every change of it fired a change event with just the new value, without ever checking the dirty state. Forms thus never got a dirtychange event and did not notice that the field was modified, for example for enabling the reset button of edit windows. Keep the value via the form field mixin, so changes go through its change detection, which fires change and dirtychange events as for any other form field. Values are compared by their timestamp, and values that are not dates are parsed, for example timestamps in milliseconds, while invalid ones are treated as no value. The change event now passes the field, new and old value, like other form fields do, instead of only the new value. Signed-off-by: Christian Ebner --- src/form/DateTimeField.js | 47 ++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/form/DateTimeField.js b/src/form/DateTimeField.js index 1f1fa7f..edb984a 100644 --- a/src/form/DateTimeField.js +++ b/src/form/DateTimeField.js @@ -110,17 +110,34 @@ Ext.define('Proxmox.DateTimeField', { }, config: { - value: null, submitFormat: 'U', disabled: false, }, + parseDatetime: function (value) { + if (value === undefined || value === null || value === '') { + return null; + } + let date = Ext.isDate(value) ? value : new Date(value); + return Number.isNaN(date.getTime()) ? null : date; + }, + setValue: function (value) { - this.getViewModel().set('datetime', value); + let me = this; + me.value = me.parseDatetime(value); + me.getViewModel().set('datetime', me.value); + me.checkChange(); + return me; }, getValue: function () { - return this.getViewModel().get('datetime'); + return this.value ?? null; + }, + + isEqual: function (value1, value2) { + let time1 = value1 ? value1.getTime() : null; + let time2 = value2 ? value2.getTime() : null; + return time1 === time2; }, getSubmitValue: function () { @@ -138,8 +155,17 @@ Ext.define('Proxmox.DateTimeField', { return { [me.getName()]: value }; }, + onChange: function (newValue) { + let me = this; + if (me.validateOnChange) { + me.validate(); + } + me.checkDirty(); + me.publishState('value', newValue); + }, + setMinValue: function (value) { - this.getViewModel().set('minDatetime', value); + this.getViewModel().set('minDatetime', this.parseDatetime(value)); }, getMinValue: function () { @@ -147,7 +173,7 @@ Ext.define('Proxmox.DateTimeField', { }, setMaxValue: function (value) { - this.getViewModel().set('maxDatetime', value); + this.getViewModel().set('maxDatetime', this.parseDatetime(value)); }, getMaxValue: function () { @@ -158,9 +184,7 @@ Ext.define('Proxmox.DateTimeField', { let me = this; me.callParent(); - let vm = me.getViewModel(); - vm.set('datetime', me.config.value); - me.resetOriginalValue(); + me.initField(); if (me.minValue) { me.setMinValue(me.minValue); @@ -169,11 +193,8 @@ Ext.define('Proxmox.DateTimeField', { me.setMaxValue(me.maxValue); } - // Propagate state change to binding - vm.bind('{datetime}', function (value) { - me.publishState('value', value); - me.fireEvent('change', value); - }); + // propagate changes made via the inner date and time fields + me.getViewModel().bind('{datetime}', (value) => me.setValue(value)); }, items: [ -- 2.47.3