Adding Now button to Zabbix 4.4

One of the many reasons I have held onto Zabbix 3.0 LTS is because the now function in maintenance windows. This is very useful when I need to put something into maintenance for a specific time period. The lack of this has held me off for many years from wanting to upgrade.

Finally I got around to writing something that works with Zabbix 4.4. Hopefully the upcoming 5.0 LTS release will be compatible. Below is a diff of the changes I made to class.calendar.js to enable this. I’m sure a more seasoned Zabbix developer to could implant this better than I did.

Additionally, this is tracked as a feature request to Zabbix that has existed since 4.0.1 as seen here: “Now” button is missing in the calendar Date/Time picker.

--- /js/class.calendar.js.bak	2020-03-20 10:35:12.828372837 -0700
+++ /js/class.calendar.js	2020-05-10 14:19:22.907333621 -0700
@@ -59,13 +59,17 @@
 	hl_year: null,				// highlighted year number
 	hl_day: null,				// highlighted days number
 	active_section: null,		// Active calendar section. See 'sections' array. Default value set in method clndrshow.
+
+	hours: null,
+	minutes: null,
+
 	monthname: new Array(t('S_JANUARY'), t('S_FEBRUARY'), t('S_MARCH'), t('S_APRIL'), t('S_MAY'), t('S_JUNE'),
 		t('S_JULY'), t('S_AUGUST'), t('S_SEPTEMBER'), t('S_OCTOBER'), t('S_NOVEMBER'), t('S_DECEMBER')
 	),
 	dayname: new Array(t('S_SUNDAY'), t('S_MONDAY'), t('S_TUESDAY'), t('S_WEDNESDAY'), t('S_THURSDAY'), t('S_FRIDAY'),
 		t('S_SATURDAY')
 	),
-	sections: new Array('.calendar-year', '.calendar-month', '.calendar-date'),
+	sections: new Array('.calendar-year', '.calendar-month', '.calendar-date', '#cur-hour', '#cur-minute'),
 	date_time_format: PHP_ZBX_FULL_DATE_TIME,
 	trigger_elmnt: null,		// Calendar visibility trigger element.
 
@@ -107,6 +111,7 @@
 		this.syncBSDateBySDT();
 		this.syncHlDate();
 		this.setCDate();
+		this.setTime();
 
 		this.calendarPositionHandler();
 		this.clndr_calendar.show();
@@ -284,7 +289,7 @@
 					this.active_section++;
 					this.focusSection();
 				}
-				else if (active_section === '.calendar-date') {
+				else if (active_section === '.calendar-date' || active_section === '#cur-hour' ||  active_section === '#cur-minute') {
 					this.setday(event, this.hl_day, this.hl_month, this.hl_year);
 				}
 
@@ -303,6 +308,9 @@
 		if (section_to_focus === '.calendar-year' ||  section_to_focus === '.calendar-month') {
 			jQuery(section_to_focus, this.clndr_calendar).addClass('highlighted').focus();
 		}
+		else if (section_to_focus === '#cur-hour' ||  section_to_focus === '#cur-minute') {
+			jQuery(section_to_focus).attr('tabindex', '0').select();
+		}
 		else if (section_to_focus === '.calendar-date') {
 			/**
 			 * Switching between months and years, date picker will highlight previously selected date. If
@@ -347,7 +355,7 @@
 		this.sdt = new CDate();
 		this.has_user_time = false;
 
-		if (date.length === 3 && this.setSDateDMY(date[2], date[1], date[0])) {
+		if (date.length === 3 && this.setSDateDMY(date[2], date[1], date[0], time[0], time[1])) {
 			this.sdt.setTimeObject(null, null, null, 0, 0, 0);
 
 			// Set time to calendar, so time doesn't change when selecting different date.
@@ -357,19 +365,26 @@
 				this.has_user_time = true;
 				this.sdt.setHours(time[0]);
 				this.sdt.setMinutes(time[1]);
+				this.hours = time[0];
+				this.minutes = time[1];
 
 				if (time.length === 3 && time[2] > -1 && time[2] < 60) {
 					this.sdt.setSeconds(time[2]);
 				}
 			}
 		}
+		else
+		{
+			this.hours = (new Date()).getHours();
+			this.minutes = (new Date()).getMinutes();
+		}
 	},
 
-	setSDateDMY: function(d, m, y) {
-		var dateHolder = new Date(y, m - 1, d, 0, 0, 0);
+	setSDateDMY: function(d, m, y, h, min) {
+		var dateHolder = new Date(y, m - 1, d, h, min, 0);
 
 		if (y >= 1970 && dateHolder.getFullYear() == y && dateHolder.getMonth() == m - 1 && dateHolder.getDate() == d) {
-			this.sdt.setTimeObject(y, m - 1, d);
+			this.sdt.setTimeObject(y, m - 1, d, h, min);
 			return true;
 		}
 
@@ -377,6 +392,8 @@
 	},
 
 	setDateToOuterObj: function() {
+		this.sdt.setHours(this.hours);
+		this.sdt.setMinutes(this.minutes);
 		var $input = jQuery(this.timeobject),
 			new_val = this.sdt.format(this.date_time_format);
 
@@ -389,6 +406,8 @@
 		this.day = day;
 		this.month = month;
 		this.year = year;
+		this.hours = jQuery('#cur-hour').val();
+		this.minutes = jQuery('#cur-minute').val();
 		this.syncSDT();
 		this.syncBSDateBySDT();
 		this.ondateselected();
@@ -700,7 +719,97 @@
 					cal_obj.focusSection();
 				});
 		});
+
+		// Main time Box
+		this.clndr_time_div = document.createElement('div');
+		this.clndr_time_div.className = 'calendar-time';
+		this.clndr_calendar.appendChild(this.clndr_time_div);
+
+		// Now Div
+		this.clndr_now_div = document.createElement('div');
+		this.clndr_now_div.className = 'calendar-now';
+		this.clndr_now_div.setAttribute('role', 'presentation');
+		this.clndr_now_div.setAttribute('style', 'float: left; padding-right: 1em;');
+		this.clndr_time_div.appendChild(this.clndr_now_div);
+
+		// Now Button
+		this.clndr_now_button = document.createElement('button');
+		this.clndr_now_button.className = 'btn-alt';
+		this.clndr_now_button.setAttribute('name', 'now');
+		this.clndr_now_button.setAttribute('id', 'time-now');
+		this.clndr_now_button.appendChild(document.createTextNode('Now'));
+		this.clndr_now_div.appendChild(this.clndr_now_button);
+		addListener(this.clndr_now_button, 'click', this.setToCurrentDate.bindAsEventListener(this));
+
+		// Time Label
+		this.clndr_time_wrap = document.createElement('span');
+		this.clndr_time_wrap.className = 'calendar-timelabel';
+		this.clndr_time_wrap.appendChild(document.createTextNode('Time'));
+		this.clndr_time_div.appendChild(this.clndr_time_wrap);
+
+		// Hours Div
+		this.clndr_hour_div = document.createElement('div');
+		this.clndr_hour_div.className = 'calendar-hour';
+		this.clndr_hour_div.setAttribute('role', 'presentation');
+		this.clndr_hour_div.setAttribute('style', 'display: inline;');
+		this.clndr_time_div.appendChild(this.clndr_hour_div);
+
+		// Hours Entry
+		this.clndr_hour_input = document.createElement('input');
+		this.clndr_hour_input.setAttribute('type', 'text');
+		this.clndr_hour_input.setAttribute('name', 'hour');
+		this.clndr_hour_input.setAttribute('id', 'cur-hour');
+		this.clndr_hour_input.setAttribute('maxlength', '2');
+		this.clndr_hour_div.appendChild(this.clndr_hour_input);
+
+		// Seperator Label
+		this.clndr_seperate_wrap = document.createElement('span');
+		this.clndr_seperate_wrap.className = 'calendar-seperatelabel';
+		this.clndr_seperate_wrap.appendChild(document.createTextNode(':'));
+		this.clndr_time_div.appendChild(this.clndr_seperate_wrap);
+
+		// Minutes Div
+		this.clndr_minute_div = document.createElement('div');
+		this.clndr_minute_div.className = 'calendar-minute';
+		this.clndr_minute_div.setAttribute('role', 'presentation');
+		this.clndr_minute_div.setAttribute('style', 'display: inline;');
+		this.clndr_time_div.appendChild(this.clndr_minute_div);
+
+		// Minutes Entry
+		this.clndr_minute_input = document.createElement('input');
+		this.clndr_minute_input.setAttribute('type', 'text');
+		this.clndr_minute_input.setAttribute('name', 'minute');
+		this.clndr_minute_input.setAttribute('id', 'cur-minute');
+		this.clndr_minute_input.setAttribute('maxlength', '2');
+		this.clndr_minute_div.appendChild(this.clndr_minute_input);
+
+		// DONE
+
+	},
+	setTime: function() {
+		this.clndr_hour_input.setAttribute('value', this.hours);
+		this.clndr_minute_input.setAttribute('value', this.minutes);
+	},
+
+	setToCurrentDate: function ()
+	{
+		var currentDate = new Date();
+
+		this.has_user_time = true;
+		this.day = currentDate.getDate();
+		this.month = currentDate.getMonth();
+		this.year = currentDate.getFullYear();
+		this.hours = currentDate.getHours();
+		this.minutes = currentDate.getMinutes();
+		this.seconds = currentDate.getSeconds();
+
+		this.syncSDT();
+		this.syncBSDateBySDT();
+		this.setDateToOuterObj();
+		this.syncHlDate();
+		this.setCDate();
 	},
+
 	/**
 	 * Remove calendar DOM element. Detach event listeners.
 	 */

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.