all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Christian Ebner <c.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com, pmg-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v2 proxmox-widget-toolkit 1/2] fix #4442: adapt DateTimeField to be more declarative
Date: Wed,  9 Aug 2023 12:55:26 +0200	[thread overview]
Message-ID: <20230809105529.58459-2-c.ebner@proxmox.com> (raw)
In-Reply-To: <20230809105529.58459-1-c.ebner@proxmox.com>

Reworks the current implementation of the DateTimeField to be more
declarative by using a ViewModel and data bindings as well as formulas,
in order to reduce code and unwanted complexity.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---

changes since v1:
- This patch was not part of the previous series, but it reworks the
  component, including modifications made by an applied patch of v1.

 src/form/DateTimeField.js | 281 ++++++++++++++++----------------------
 1 file changed, 121 insertions(+), 160 deletions(-)

diff --git a/src/form/DateTimeField.js b/src/form/DateTimeField.js
index 13b1ed1..4bfa9bd 100644
--- a/src/form/DateTimeField.js
+++ b/src/form/DateTimeField.js
@@ -6,205 +6,166 @@ Ext.define('Proxmox.DateTimeField', {
 
     layout: 'hbox',
 
-    referenceHolder: true,
+    viewModel: {
+	data: {
+	    datetime: null,
+	    minDatetime: null,
+	    maxDatetime: null,
+	},
+
+	formulas: {
+	    date: {
+		get: function(get) {
+		    return get('datetime');
+		},
+		set: function(date) {
+		    if (!date) {
+			this.set('datetime', null);
+			return;
+		    }
+		    let datetime = new Date(this.get('datetime'));
+		    datetime.setDate(date.getDate());
+		    datetime.setMonth(date.getMonth());
+		    datetime.setFullYear(date.getFullYear());
+		    this.set('datetime', datetime);
+		},
+	    },
+
+	    time: {
+		get: function(get) {
+		    return get('datetime');
+		},
+		set: function(time) {
+		    if (!time) {
+			this.set('datetime', null);
+			return;
+		    }
+		    let datetime = new Date(this.get('datetime'));
+		    datetime.setHours(time.getHours());
+		    datetime.setMinutes(time.getMinutes());
+		    datetime.setSeconds(time.getSeconds());
+		    datetime.setMilliseconds(time.getMilliseconds());
+		    this.set('datetime', datetime);
+		},
+	    },
+
+	    minDate: {
+		get: function(get) {
+		    let datetime = get('minDatetime');
+		    return datetime ? new Date(datetime) : null;
+		},
+	    },
+
+	    maxDate: {
+		get: function(get) {
+		    let datetime = get('maxDatetime');
+		    return datetime ? new Date(datetime) : null;
+		},
+	    },
+
+	    minTime: {
+		get: function(get) {
+		    let current = get('datetime');
+		    let min = get('minDatetime');
+		    if (min && current && !this.isSameDay(current, min)) {
+			return new Date(min).setHours('00', '00', '00', '000');
+		    }
+		    return min;
+		},
+	    },
+
+	    maxTime: {
+		get: function(get) {
+		    let current = get('datetime');
+		    let max = get('maxDatetime');
+		    if (max && current && !this.isSameDay(current, max)) {
+			return new Date(max).setHours('23', '59', '59', '999');
+		    }
+		    return max;
+		},
+	    },
+	},
+
+	// Helper function to check if dates are the same day of the year
+	isSameDay: function(date1, date2) {
+	    return date1.getDate() === date2.getDate() &&
+		date1.getMonth() === date2.getMonth() &&
+		date1.getFullYear() === date2.getFullYear();
+	},
+    },
 
     config: {
+	value: null,
 	submitFormat: 'U',
 	disabled: false,
     },
 
     setValue: function(value) {
-	let me = this;
-	me.setDate(value);
-	me.setTime(value);
-
-	// Notify all 'value' bindings of state change
-	me.publishState('value', value);
+	this.getViewModel().set('datetime', value);
     },
 
     getValue: function() {
-	let me = this;
-	let date = me.lookupReference('dateentry').getValue();
-
-	if (date === undefined || date === null) { return null; }
-
-	let time = me.lookupReference('timeentry').getValue();
+	return this.getViewModel().get('datetime');
+    },
 
-	if (time === undefined || time === null) { return null; }
+    getSubmitValue: function() {
+	let me = this;
+	let value = me.getValue();
+	return value ? Ext.Date.format(value, me.submitFormat) : null;
+    },
 
-	date.setHours(time.getHours());
-	date.setMinutes(time.getMinutes());
-	date.setSeconds(time.getSeconds());
-	return date;
+    setMinValue: function(value) {
+	this.getViewModel().set('minDatetime', value);
     },
 
-    getSubmitValue: function() {
-        let me = this;
-        let format = me.submitFormat;
-        let value = me.getValue();
+    getMinValue: function() {
+	return this.getViewModel().get('minDatetime');
+    },
 
-        return value ? Ext.Date.format(value, format) : null;
+    setMaxValue: function(value) {
+	this.getViewModel().set('maxDatetime', value);
     },
 
-    setDate: function(date) {
-	let me = this;
-	let dateEntry = me.lookupReference('dateentry');
-	dateEntry.setValue(date);
-	dateEntry.publishState('value', date);
+    getMaxValue: function() {
+	return this.getViewModel().get('maxDatetime');
     },
 
-    setTime: function(time) {
+    initComponent: function() {
 	let me = this;
-	let timeEntry = me.lookupReference('timeentry');
-	timeEntry.setValue(time);
-	timeEntry.publishState('value', time);
+	me.callParent();
+
+	let vm = me.getViewModel();
+	vm.set('datetime', me.config.value);
+	// Propagate state change to binding
+	vm.bind('{datetime}', function(value) {
+	    me.publishState('value', value);
+	    me.fireEvent('change', value);
+	});
     },
 
     items: [
 	{
 	    xtype: 'datefield',
 	    editable: false,
-	    reference: 'dateentry',
 	    flex: 1,
 	    format: 'Y-m-d',
 	    bind: {
-		disabled: '{disabled}',
-	    },
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    let dateTimeField = field.up('fieldcontainer');
-		    dateTimeField.setDate(newValue);
-		    let value = dateTimeField.getValue();
-		    dateTimeField.publishState('value', value);
-		},
+		value: '{date}',
+		minValue: '{minDate}',
+		maxValue: '{maxDate}',
 	    },
 	},
 	{
 	    xtype: 'timefield',
-	    reference: 'timeentry',
 	    format: 'H:i',
 	    width: 80,
 	    value: '00:00',
 	    increment: 60,
 	    bind: {
-		disabled: '{disabled}',
-	    },
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    let dateTimeField = field.up('fieldcontainer');
-		    dateTimeField.setTime(newValue);
-		    let value = dateTimeField.getValue();
-		    dateTimeField.publishState('value', value);
-		},
+		value: '{time}',
+		minValue: '{minTime}',
+		maxValue: '{maxTime}',
 	    },
 	},
     ],
-
-    setMinValue: function(value) {
-	let me = this;
-	let current = me.getValue();
-	if (!value || !current) {
-	    return;
-	}
-
-	// Clone to avoid modifying the referenced value
-	let clone = new Date(value);
-	let minhours = clone.getHours();
-	let minminutes = clone.getMinutes();
-
-	let hours = current.getHours();
-	let minutes = current.getMinutes();
-
-	clone.setHours(0);
-	clone.setMinutes(0);
-	clone.setSeconds(0);
-	current.setHours(0);
-	current.setMinutes(0);
-	current.setSeconds(0);
-
-	let time = new Date();
-	if (current-clone > 0) {
-	    time.setHours(0);
-	    time.setMinutes(0);
-	    time.setSeconds(0);
-	    time.setMilliseconds(0);
-	} else {
-	    time.setHours(minhours);
-	    time.setMinutes(minminutes);
-	}
-	me.lookup('timeentry').setMinValue(time);
-
-	// current time is smaller than the time part of the new minimum
-	// so we have to add 1 to the day
-	if (minhours*60+minminutes > hours*60+minutes) {
-	    clone.setDate(clone.getDate()+1);
-	}
-	me.lookup('dateentry').setMinValue(clone);
-    },
-
-    setMaxValue: function(value) {
-	let me = this;
-	let current = me.getValue();
-	if (!value || !current) {
-	    return;
-	}
-
-	// Clone to avoid modifying the referenced value
-	let clone = new Date(value);
-	let maxhours = clone.getHours();
-	let maxminutes = clone.getMinutes();
-
-	let hours = current.getHours();
-	let minutes = current.getMinutes();
-
-	clone.setHours(0);
-	clone.setMinutes(0);
-	clone.setSeconds(0);
-	clone.setMilliseconds(0);
-	current.setHours(0);
-	current.setMinutes(0);
-	current.setSeconds(0);
-	current.setMilliseconds(0);
-
-	let time = new Date();
-	if (clone-current > 0) {
-	    time.setHours(23);
-	    time.setMinutes(59);
-	    time.setSeconds(59);
-	} else {
-	    time.setHours(maxhours);
-	    time.setMinutes(maxminutes);
-	}
-	me.lookup('timeentry').setMaxValue(time);
-
-	// current time is bigger than the time part of the new maximum
-	// so we have to subtract 1 to the day
-	if (maxhours*60+maxminutes < hours*60+minutes) {
-	    clone.setDate(clone.getDate()-1);
-	}
-
-	me.lookup('dateentry').setMaxValue(clone);
-    },
-
-    initComponent: function() {
-	let me = this;
-
-	me.callParent();
-
-	let value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	if (me.minValue) {
-	    me.setMinValue(me.minValue);
-	}
-
-	if (me.maxValue) {
-	    me.setMaxValue(me.maxValue);
-	}
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    },
 });
-- 
2.39.2





WARNING: multiple messages have this Message-ID
From: Christian Ebner <c.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com, pmg-devel@lists.proxmox.com
Subject: [pmg-devel] [PATCH v2 proxmox-widget-toolkit 1/2] fix #4442: adapt DateTimeField to be more declarative
Date: Wed,  9 Aug 2023 12:55:26 +0200	[thread overview]
Message-ID: <20230809105529.58459-2-c.ebner@proxmox.com> (raw)
In-Reply-To: <20230809105529.58459-1-c.ebner@proxmox.com>

Reworks the current implementation of the DateTimeField to be more
declarative by using a ViewModel and data bindings as well as formulas,
in order to reduce code and unwanted complexity.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---

changes since v1:
- This patch was not part of the previous series, but it reworks the
  component, including modifications made by an applied patch of v1.

 src/form/DateTimeField.js | 281 ++++++++++++++++----------------------
 1 file changed, 121 insertions(+), 160 deletions(-)

diff --git a/src/form/DateTimeField.js b/src/form/DateTimeField.js
index 13b1ed1..4bfa9bd 100644
--- a/src/form/DateTimeField.js
+++ b/src/form/DateTimeField.js
@@ -6,205 +6,166 @@ Ext.define('Proxmox.DateTimeField', {
 
     layout: 'hbox',
 
-    referenceHolder: true,
+    viewModel: {
+	data: {
+	    datetime: null,
+	    minDatetime: null,
+	    maxDatetime: null,
+	},
+
+	formulas: {
+	    date: {
+		get: function(get) {
+		    return get('datetime');
+		},
+		set: function(date) {
+		    if (!date) {
+			this.set('datetime', null);
+			return;
+		    }
+		    let datetime = new Date(this.get('datetime'));
+		    datetime.setDate(date.getDate());
+		    datetime.setMonth(date.getMonth());
+		    datetime.setFullYear(date.getFullYear());
+		    this.set('datetime', datetime);
+		},
+	    },
+
+	    time: {
+		get: function(get) {
+		    return get('datetime');
+		},
+		set: function(time) {
+		    if (!time) {
+			this.set('datetime', null);
+			return;
+		    }
+		    let datetime = new Date(this.get('datetime'));
+		    datetime.setHours(time.getHours());
+		    datetime.setMinutes(time.getMinutes());
+		    datetime.setSeconds(time.getSeconds());
+		    datetime.setMilliseconds(time.getMilliseconds());
+		    this.set('datetime', datetime);
+		},
+	    },
+
+	    minDate: {
+		get: function(get) {
+		    let datetime = get('minDatetime');
+		    return datetime ? new Date(datetime) : null;
+		},
+	    },
+
+	    maxDate: {
+		get: function(get) {
+		    let datetime = get('maxDatetime');
+		    return datetime ? new Date(datetime) : null;
+		},
+	    },
+
+	    minTime: {
+		get: function(get) {
+		    let current = get('datetime');
+		    let min = get('minDatetime');
+		    if (min && current && !this.isSameDay(current, min)) {
+			return new Date(min).setHours('00', '00', '00', '000');
+		    }
+		    return min;
+		},
+	    },
+
+	    maxTime: {
+		get: function(get) {
+		    let current = get('datetime');
+		    let max = get('maxDatetime');
+		    if (max && current && !this.isSameDay(current, max)) {
+			return new Date(max).setHours('23', '59', '59', '999');
+		    }
+		    return max;
+		},
+	    },
+	},
+
+	// Helper function to check if dates are the same day of the year
+	isSameDay: function(date1, date2) {
+	    return date1.getDate() === date2.getDate() &&
+		date1.getMonth() === date2.getMonth() &&
+		date1.getFullYear() === date2.getFullYear();
+	},
+    },
 
     config: {
+	value: null,
 	submitFormat: 'U',
 	disabled: false,
     },
 
     setValue: function(value) {
-	let me = this;
-	me.setDate(value);
-	me.setTime(value);
-
-	// Notify all 'value' bindings of state change
-	me.publishState('value', value);
+	this.getViewModel().set('datetime', value);
     },
 
     getValue: function() {
-	let me = this;
-	let date = me.lookupReference('dateentry').getValue();
-
-	if (date === undefined || date === null) { return null; }
-
-	let time = me.lookupReference('timeentry').getValue();
+	return this.getViewModel().get('datetime');
+    },
 
-	if (time === undefined || time === null) { return null; }
+    getSubmitValue: function() {
+	let me = this;
+	let value = me.getValue();
+	return value ? Ext.Date.format(value, me.submitFormat) : null;
+    },
 
-	date.setHours(time.getHours());
-	date.setMinutes(time.getMinutes());
-	date.setSeconds(time.getSeconds());
-	return date;
+    setMinValue: function(value) {
+	this.getViewModel().set('minDatetime', value);
     },
 
-    getSubmitValue: function() {
-        let me = this;
-        let format = me.submitFormat;
-        let value = me.getValue();
+    getMinValue: function() {
+	return this.getViewModel().get('minDatetime');
+    },
 
-        return value ? Ext.Date.format(value, format) : null;
+    setMaxValue: function(value) {
+	this.getViewModel().set('maxDatetime', value);
     },
 
-    setDate: function(date) {
-	let me = this;
-	let dateEntry = me.lookupReference('dateentry');
-	dateEntry.setValue(date);
-	dateEntry.publishState('value', date);
+    getMaxValue: function() {
+	return this.getViewModel().get('maxDatetime');
     },
 
-    setTime: function(time) {
+    initComponent: function() {
 	let me = this;
-	let timeEntry = me.lookupReference('timeentry');
-	timeEntry.setValue(time);
-	timeEntry.publishState('value', time);
+	me.callParent();
+
+	let vm = me.getViewModel();
+	vm.set('datetime', me.config.value);
+	// Propagate state change to binding
+	vm.bind('{datetime}', function(value) {
+	    me.publishState('value', value);
+	    me.fireEvent('change', value);
+	});
     },
 
     items: [
 	{
 	    xtype: 'datefield',
 	    editable: false,
-	    reference: 'dateentry',
 	    flex: 1,
 	    format: 'Y-m-d',
 	    bind: {
-		disabled: '{disabled}',
-	    },
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    let dateTimeField = field.up('fieldcontainer');
-		    dateTimeField.setDate(newValue);
-		    let value = dateTimeField.getValue();
-		    dateTimeField.publishState('value', value);
-		},
+		value: '{date}',
+		minValue: '{minDate}',
+		maxValue: '{maxDate}',
 	    },
 	},
 	{
 	    xtype: 'timefield',
-	    reference: 'timeentry',
 	    format: 'H:i',
 	    width: 80,
 	    value: '00:00',
 	    increment: 60,
 	    bind: {
-		disabled: '{disabled}',
-	    },
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    let dateTimeField = field.up('fieldcontainer');
-		    dateTimeField.setTime(newValue);
-		    let value = dateTimeField.getValue();
-		    dateTimeField.publishState('value', value);
-		},
+		value: '{time}',
+		minValue: '{minTime}',
+		maxValue: '{maxTime}',
 	    },
 	},
     ],
-
-    setMinValue: function(value) {
-	let me = this;
-	let current = me.getValue();
-	if (!value || !current) {
-	    return;
-	}
-
-	// Clone to avoid modifying the referenced value
-	let clone = new Date(value);
-	let minhours = clone.getHours();
-	let minminutes = clone.getMinutes();
-
-	let hours = current.getHours();
-	let minutes = current.getMinutes();
-
-	clone.setHours(0);
-	clone.setMinutes(0);
-	clone.setSeconds(0);
-	current.setHours(0);
-	current.setMinutes(0);
-	current.setSeconds(0);
-
-	let time = new Date();
-	if (current-clone > 0) {
-	    time.setHours(0);
-	    time.setMinutes(0);
-	    time.setSeconds(0);
-	    time.setMilliseconds(0);
-	} else {
-	    time.setHours(minhours);
-	    time.setMinutes(minminutes);
-	}
-	me.lookup('timeentry').setMinValue(time);
-
-	// current time is smaller than the time part of the new minimum
-	// so we have to add 1 to the day
-	if (minhours*60+minminutes > hours*60+minutes) {
-	    clone.setDate(clone.getDate()+1);
-	}
-	me.lookup('dateentry').setMinValue(clone);
-    },
-
-    setMaxValue: function(value) {
-	let me = this;
-	let current = me.getValue();
-	if (!value || !current) {
-	    return;
-	}
-
-	// Clone to avoid modifying the referenced value
-	let clone = new Date(value);
-	let maxhours = clone.getHours();
-	let maxminutes = clone.getMinutes();
-
-	let hours = current.getHours();
-	let minutes = current.getMinutes();
-
-	clone.setHours(0);
-	clone.setMinutes(0);
-	clone.setSeconds(0);
-	clone.setMilliseconds(0);
-	current.setHours(0);
-	current.setMinutes(0);
-	current.setSeconds(0);
-	current.setMilliseconds(0);
-
-	let time = new Date();
-	if (clone-current > 0) {
-	    time.setHours(23);
-	    time.setMinutes(59);
-	    time.setSeconds(59);
-	} else {
-	    time.setHours(maxhours);
-	    time.setMinutes(maxminutes);
-	}
-	me.lookup('timeentry').setMaxValue(time);
-
-	// current time is bigger than the time part of the new maximum
-	// so we have to subtract 1 to the day
-	if (maxhours*60+maxminutes < hours*60+minutes) {
-	    clone.setDate(clone.getDate()-1);
-	}
-
-	me.lookup('dateentry').setMaxValue(clone);
-    },
-
-    initComponent: function() {
-	let me = this;
-
-	me.callParent();
-
-	let value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	if (me.minValue) {
-	    me.setMinValue(me.minValue);
-	}
-
-	if (me.maxValue) {
-	    me.setMaxValue(me.maxValue);
-	}
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    },
 });
-- 
2.39.2





  reply	other threads:[~2023-08-09 10:55 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-09 10:55 [pve-devel] [PATCH v2 proxmox-widget-toolkit manager pmg-gui 0/4] #4442: impl firewall log filtering Christian Ebner
2023-08-09 10:55 ` [pmg-devel] " Christian Ebner
2023-08-09 10:55 ` Christian Ebner [this message]
2023-08-09 10:55   ` [pmg-devel] [PATCH v2 proxmox-widget-toolkit 1/2] fix #4442: adapt DateTimeField to be more declarative Christian Ebner
2023-08-09 10:55 ` [pve-devel] [PATCH v2 proxmox-widget-toolkit 2/2] fix #4442: Extend LogView for firewall datetime filtering Christian Ebner
2023-08-09 10:55   ` [pmg-devel] " Christian Ebner
2023-08-09 10:55 ` [pve-devel] [PATCH v2 manager 3/3] fix #4442: Add date-time filtering for firewall logs Christian Ebner
2023-08-09 10:55   ` [pmg-devel] " Christian Ebner
2023-08-09 10:55 ` [pve-devel] [PATCH v2 pmg-gui 4/4] Revert "fix tracking center with newer proxmox-widget-toolkit" Christian Ebner
2023-08-09 10:55   ` [pmg-devel] " Christian Ebner
2023-11-09  9:22 ` [pve-devel] [PATCH v2 proxmox-widget-toolkit manager pmg-gui 0/4] #4442: impl firewall log filtering Christian Ebner
2023-11-09  9:22   ` [pmg-devel] " Christian Ebner
2023-11-14 15:45 ` [pve-devel] applied: " Thomas Lamprecht
2023-11-14 15:45   ` [pmg-devel] applied: [pve-devel] " Thomas Lamprecht
2023-11-16  8:28   ` [pmg-devel] Unsubscribe Deepen Dhulla

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230809105529.58459-2-c.ebner@proxmox.com \
    --to=c.ebner@proxmox.com \
    --cc=pmg-devel@lists.proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal