From 49f608159cbce4abf1fac2bc3e3b9c3713fcaaee Mon Sep 17 00:00:00 2001 From: ralf Date: Thu, 13 Oct 2022 16:30:35 +0200 Subject: [PATCH] WIP timesheet timer: ask user to start/stop working time with session/login/logout if working time is not disabled in timesheet config, or asking is disabled in user preferences --- api/js/framework/fw_desktop.js | 8 +- api/js/jsapi/egw_timer.js | 150 +++++++++++++++----- timesheet/inc/class.timesheet_hooks.inc.php | 12 ++ timesheet/lang/egw_de.lang | 5 + timesheet/lang/egw_en.lang | 5 + 5 files changed, 138 insertions(+), 42 deletions(-) diff --git a/api/js/framework/fw_desktop.js b/api/js/framework/fw_desktop.js index dacf85db4e..192348ee16 100644 --- a/api/js/framework/fw_desktop.js +++ b/api/js/framework/fw_desktop.js @@ -402,8 +402,10 @@ import "sortablejs/Sortable.min.js"; { $logout.on('click', function(e){ e.preventDefault(); - self.callOnLogout(e); - window.framework.redirect(this.href); + egw.onLogout_timer().then(() => { + self.callOnLogout(e); + window.framework.redirect(this.href); + }); }); $logout.addClass('onLogout'); } @@ -556,4 +558,4 @@ import "sortablejs/Sortable.min.js"; } } }); -})(window); +})(window); \ No newline at end of file diff --git a/api/js/jsapi/egw_timer.js b/api/js/jsapi/egw_timer.js index 2bd2385ece..4add4b0d42 100644 --- a/api/js/jsapi/egw_timer.js +++ b/api/js/jsapi/egw_timer.js @@ -96,6 +96,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() * @param {string} _action * @param {string} _time * @param {string} _app_id + * @return Promise from egw.request() to wait for state being persisted on server * @throws string error-message */ function timerAction(_action, _time, _app_id) @@ -135,7 +136,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() specific.app_id = _app_id; } // persist state - egw.request('timesheet.EGroupware\\Timesheet\\Events.ajax_event', [getState(_action, _time)]).then((tse_id) => { + return egw.request('timesheet.EGroupware\\Timesheet\\Events.ajax_event', [getState(_action, _time)]).then((tse_id) => { if (_action.substring(0, 8) === 'specific') { specific.id = tse_id; @@ -390,6 +391,59 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() return formatTime(new Date(date.valueOf() - egw.getTimezoneOffset() * 60000)); } + /** + * Open the timer dialog to start/stop timers + * + * @param {Array} disable + * @param {string} _title default "Start & stop timer" + */ + function timerDialog(disable, _title) + { + // Pass egw in the constructor + dialog = new Et2Dialog(egw); + + // Set attributes. They can be set in any way, but this is convenient. + dialog.transformAttributes({ + // If you use a template, the second parameter will be the value of the template, as if it were submitted. + callback: (button_id, value) => // return false to prevent dialog closing + { + if (button_id !== 'close') { + try { + timerAction(button_id.replace(/_([a-z]+)\[([a-z]+)\]/, '$1-$2'), + // eT2 operates in user-time, while timers here always operate in UTC + value.time ? new Date((new Date(value.time)).valueOf() + egw.getTimezoneOffset() * 60000) : undefined); + dialog._overlayContentNode.querySelector('et2-date-time').value = ''; + } + catch (e) { + Et2Dialog.alert(e, egw.lang('Invalid Input'), Et2Dialog.ERROR_MESSAGE); + } + setButtonState(); + return false; + } + dialog = undefined; + }, + title: _title || 'Start & stop timer', + template: egw.webserverUrl + '/timesheet/templates/default/timer.xet', + buttons: [ + {label: egw.lang("Close"), id: "close", default: true, image: "cancel"}, + ], + value: { + content: { + disable: disable.join(':') + }, + sel_options: {} + } + }); + // Add to DOM, dialog will auto-open + document.body.appendChild(dialog); + dialog.getUpdateComplete().then(() => { + // enable/disable buttons based on timer state + setButtonState(); + // update timers in dialog + update(); + }); + } + return { /** * Start timer for given app and id @@ -449,50 +503,68 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() // bind click handler timer_container.addEventListener('click', (ev) => { - // Pass egw in the constructor - dialog = new Et2Dialog(egw); + timerDialog(state.disable); + }); - // Set attributes. They can be set in any way, but this is convenient. - dialog.transformAttributes({ - // If you use a template, the second parameter will be the value of the template, as if it were submitted. - callback: (button_id, value) => // return false to prevent dialog closing + // check if overall working time is not disabled + if (state.disable.indexOf('overall') === -1) + { + // check if we should ask on login to start working time + this.preference('workingtime_session', 'timesheet', true).then(pref => + { + if (pref === 'no') return; + + // overall timer not running, ask to start + if (overall && !overall.start) { - if (button_id !== 'close') { - try { - timerAction(button_id.replace(/_([a-z]+)\[([a-z]+)\]/, '$1-$2'), - // eT2 operates in user-time, while timers here always operate in UTC - value.time ? new Date((new Date(value.time)).valueOf() + egw.getTimezoneOffset() * 60000) : undefined); - dialog._overlayContentNode.querySelector('et2-date-time').value = ''; + Et2Dialog.show_dialog((button) => { + if (button === Et2Dialog.YES_BUTTON) + { + timerAction('overall-start'); } - catch (e) { - Et2Dialog.alert(e, egw.lang('Invalid Input'), Et2Dialog.ERROR_MESSAGE); - } - setButtonState(); - return false; - } - dialog = undefined; - }, - title: 'Start & stop timer', - template: egw.webserverUrl + '/timesheet/templates/default/timer.xet', - buttons: [ - {label: egw.lang("Close"), id: "close", default: true, image: "cancel"}, - ], - value: { - content: { - disable: state.disable.join(':') - }, - sel_options: {} + }, 'Do you want to start your working time?', 'Working time', {}, Et2Dialog.BUTTONS_YES_NO); + } + // overall timer running for more than 16 hours, ask to stop + else if (overall?.start && (((new Date()).valueOf() - overall.start.valueOf()) / 3600000) >= 16) + { + // gives a JS error, if called direct + window.setTimeout(() => { + timerDialog(state.disable, 'Forgot to switch off working time?'); + }, 1000); } }); - // Add to DOM, dialog will auto-open - document.body.appendChild(dialog); - dialog.getUpdateComplete().then(() => { - // enable/disable buttons based on timer state - setButtonState(); - // update timers in dialog - update(); + } + }, + + /** + * Ask user to stop working time + * + * @returns {Promise} resolved once user answered, to continue logout + */ + onLogout_timer: function() + { + let promise; + if (overall.start || overall.paused) + { + promise = new Promise((_resolve, _reject) => + { + Et2Dialog.show_dialog((button) => { + if (button === Et2Dialog.YES_BUTTON) + { + timerAction('overall-stop').then(_resolve); + } + else + { + _resolve(); + } + }, 'Do you want to stop your working time?', 'Working time', {}, Et2Dialog.BUTTONS_YES_NO); }); - }); + } + else + { + promise = Promise.resolve(); + } + return promise; } }; }); \ No newline at end of file diff --git a/timesheet/inc/class.timesheet_hooks.inc.php b/timesheet/inc/class.timesheet_hooks.inc.php index fda27ea584..55e7edac3c 100644 --- a/timesheet/inc/class.timesheet_hooks.inc.php +++ b/timesheet/inc/class.timesheet_hooks.inc.php @@ -165,6 +165,18 @@ class timesheet_hooks if (is_null(self::$timesheet_bo)) self::$timesheet_bo = new timesheet_bo(); if (self::$timesheet_bo->status_labels) { + $settings['workingtime_session'] = array( + 'type' => 'select', + 'label' => 'Ask to start and stop working time with session', + 'name' => 'workingtime_session', + 'values' => [ + '' => 'yes', + 'no' => 'no', + ], + 'help' => 'Would you like to be asked, to start and stop working time, when login in or off', + 'xmlrpc' => True, + 'admin' => False, + ); $settings['predefined_status'] = array( 'type' => 'select', 'label' => 'Status of created timesheets', diff --git a/timesheet/lang/egw_de.lang b/timesheet/lang/egw_de.lang index bfd1fc4b05..607df59d0b 100644 --- a/timesheet/lang/egw_de.lang +++ b/timesheet/lang/egw_de.lang @@ -8,6 +8,7 @@ all projects timesheet de Alle Projekte and its members timesheet de und die Mitglieder applies the changes timesheet de Änderungen durchführen apply the action on the whole query, not only the shown timesheets!!! timesheet de Wendet den Befehl auf die gesamte Abfrage an, NICHT nur die angezeigten Stundenzettel!! +ask to start and stop working time with session timesheet de Fragen die Arbeitszeit mit der Sitzung zu starten oder stoppen both: allow to use projectmanager and free project-names admin de Beides: verwende Projektmanager und freie Projektnamen by timesheet de von category for 'working time' admin de Kategorie für 'Arbeitszeit' @@ -30,6 +31,8 @@ determines the order the fields are displayed timesheet de verändert die Reihen directory with documents to insert entries timesheet de Ordner mit Dokumenten zum Einfügen. disable timers timesheet de Zeitnehmer ausschalten do you want to associate it with the selected %1 entry? common de Wollen Sie ihn mit dem ausgewählten %1 Eintrag verbinden? +do you want to start your working time? common de Wollen Sie Ihre Arbeitszeit starten? +do you want to stop your working time? common de Wollen Sie Ihre Arbeitszeit beenden? each value is a line like [=