From e9d68b9444bf7941be1d6938a891197bcab4e583 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Wed, 15 Apr 2026 07:08:05 +0200 Subject: [PATCH 1/9] Update mobile.class.php backupExclude --- core/class/mobile.class.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/class/mobile.class.php b/core/class/mobile.class.php index 3c1d0e08..19a4fa3b 100755 --- a/core/class/mobile.class.php +++ b/core/class/mobile.class.php @@ -34,6 +34,16 @@ class mobile extends eqLogic /* * ***********************Methode static*************************** */ + /** + * Core callback to returns the directory of data not to be saved in the Jeedom backup + * + * @return array + */ + public static function backupExclude() + { + return ['data']; + } + public static function cronDaily() { foreach (eqLogic::byType('mobile') as $mobile) { From d06cba9da911d19d7552355a2b694fa6344fb610 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:06:51 +0200 Subject: [PATCH 2/9] Add css file --- desktop/css/notification.css | 129 +++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 desktop/css/notification.css diff --git a/desktop/css/notification.css b/desktop/css/notification.css new file mode 100644 index 00000000..75786447 --- /dev/null +++ b/desktop/css/notification.css @@ -0,0 +1,129 @@ +.notification-box { + padding: 32px; +} + +.notification-step { + display: flex; + margin-bottom: 32px; + position: relative; +} + +.notification-step:last-child { + margin-bottom: 0px; +} + +.notification-line { + position: absolute; + left: 114px; + top: 40px; + bottom: -32px; + width: 2px; + background-color: var(--logo-primary-color); + z-index: 1; +} + +.notification-date { + display: flex; + height: 40px; + align-items: center; + margin-right: 16px; + width: 79px; + font-size: 12px; + padding: 5px; + text-align: center; + border-radius: var(--border-radius) var(--border-radius) var(--border-radius) var(--border-radius) !important; + background-color: var(--form-bg-color); + /* z-index: 1;*/ +} + +.notification-step:last-child .notification-line { + display: none; +} + +.notification-circle { + width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-right: 16px; + background-color: var(--form-bg-color); + border: 2px solid var(--txt-color); + z-index: 2; +} + +.ask-timeout .notification-circle { + color: var(--linkHoverLight-color) !important; + background-color: var(--al-info-color) !important; + border: none; +} + +.ask-success .notification-circle { + color: var(--linkHoverLight-color) !important; + background-color: var(--al-success-color) !important; + border: none; +} + +.ask-in-progress .notification-circle { + color: var(--linkHoverLight-color) !important; + background-color: var(--al-warning-color) !important; + border: none; +} + +.stepper-critical .notification-circle { + border: 1px solid red; +} + +.notification-content { + flex: 1; + padding: 10px; + border-radius: var(--border-radius) var(--border-radius) var(--border-radius) var(--border-radius); + background-color: var(--form-bg-color); +} + +.notification-img { + margin-top: 10px; +} + +.notification-img img { + max-width: 250px; +} + +.notification-title { + font-weight: 600; + margin-bottom: 4px; + font-size: 18px; +} + +.notification-status { + font-size: 13px; + display: inline-block; + padding: 2px 8px; + border-radius: 12px; + margin-top: 4px; +} + +.ask-success .notification-status { + color: var(--linkHoverLight-color) !important; + background-color: var(--al-success-color) !important; + border: none; +} + +.ask-timeout .notification-status { + color: var(--linkHoverLight-color) !important; + background-color: var(--al-info-color) !important; + border: none; +} + +.ask-in-progress .notification-status { + color: var(--linkHoverLight-color) !important; + background-color: var(--al-warning-color) !important; + border: none; +} + +.notification-button { + display: flex; + margin-bottom: 32px; + justify-content: end; +} \ No newline at end of file From 72c40c943379c63348561cea3ef516d5b4c4e974 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:12:59 +0200 Subject: [PATCH 3/9] Update mobile.ajax.php --- core/ajax/mobile.ajax.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/ajax/mobile.ajax.php b/core/ajax/mobile.ajax.php index 893cfd2c..d67b0f5a 100755 --- a/core/ajax/mobile.ajax.php +++ b/core/ajax/mobile.ajax.php @@ -59,6 +59,20 @@ } ajax::success($return); } + + if (init('action') == 'getNotificationsV2') { + $return = ''; + $iq = init('iq'); + $mobile = eqLogic::byLogicalId($iq, 'mobile'); + if (is_object($mobile)) { + $return = mobile::getNotificationsV2($iq); + } + ajax::success($return); + } + + if (init('action') == 'removeNotificationV2') { + ajax::success(mobile::removeNotification(init('iq', ''), init('id', ''))); + } // APP V1 From 0e4509fb419a7d218d3a5b77386898743e674ad9 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:17:37 +0200 Subject: [PATCH 4/9] Update mobile.ajax.php change function name --- core/ajax/mobile.ajax.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ajax/mobile.ajax.php b/core/ajax/mobile.ajax.php index d67b0f5a..378aca98 100755 --- a/core/ajax/mobile.ajax.php +++ b/core/ajax/mobile.ajax.php @@ -71,7 +71,7 @@ } if (init('action') == 'removeNotificationV2') { - ajax::success(mobile::removeNotification(init('iq', ''), init('id', ''))); + ajax::success(mobile::removeNotificationV2(init('iq', ''), init('id', ''))); } // APP V1 From 06f471e978fb2ef7ea314fcc5d6e60e745657c91 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:27:28 +0200 Subject: [PATCH 5/9] Update mobile.class.php --- core/class/mobile.class.php | 49 +++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/core/class/mobile.class.php b/core/class/mobile.class.php index 19a4fa3b..d063c501 100755 --- a/core/class/mobile.class.php +++ b/core/class/mobile.class.php @@ -1012,6 +1012,51 @@ public static function notification($arn, $os, $titre, $message, $type, $idNotif log::add('mobile', 'debug', '|└────────────────────'); } + /** + * Get all notifications from Iq + * Call by ajax getNotificationsV2 + * @return array + */ + public static function getNotificationsV2($Iq) + { + $return = ''; + $filePath = dirname(__FILE__) . '/../data/notifications/' . $Iq . '.json'; + if (file_exists($filePath)) { + $notifs = json_decode(file_get_contents($filePath), true); + if (is_array($notifs) && count($notifs) > 0) $return = json_encode(array_reverse($notifs)); + else $return = __('Aucune notifications.', __FILE__); + } else { + $return = __('Fichier de notifications non trouvé.', __FILE__); + } + return $return; + } + + /** + * remove notification from Id into filepath id + * Call by ajax removeNotificationV2 + */ + public static function removeNotificationV2($_iq, $_id) + { + $pathNotificationData = '/../data/notifications'; + $filePath = dirname(__FILE__) . $pathNotificationData . '/' . $_iq . '.json'; + if (file_exists($filePath)) { + $notificationsContent = file_get_contents($filePath); + $notifications = json_decode($notificationsContent, true); + if ($notifications === null) { + throw new Exception(__('Fichier de notification vide !.', __FILE__)); + } + if (isset($notifications[$_id])) { + unset($notifications[$_id]); + file_put_contents($filePath, json_encode($notifications)); + return count($notifications); + } else { + throw new Exception(__('Id notification introuvable :', __FILE__) . ' ' . $_id); + } + } else { + throw new Exception(__('Fichier de notifications non trouvé : ', __FILE__) . $filePath); + } + } + /** * Create and update cmd geoloc * Call By api : setConfigs @@ -1851,7 +1896,7 @@ public function execute($_options = array()) $askParams = json_decode($notif['data']['askParams'], true); $notifTime = strtotime($notif['data']['date']); $currentTime = time(); - $timeout = $askParams['timeout'] / 1000; + $timeout = (isset($askParams['timeout'])) ? $askParams['timeout'] / 1000 : 0; return $notif['data']['askVariable'] == 'rien' || ($currentTime - $notifTime) < $timeout; }); file_put_contents($filePath, json_encode($notifs)); @@ -1860,7 +1905,7 @@ public function execute($_options = array()) case 3: $notifs = json_decode(file_get_contents($filePath), true); $notifs = array_filter($notifs, function ($notif) { - return $notif['data']['choiceAsk'] == ''; + return !isset($notif['data']['choiceAsk']) || $notif['data']['choiceAsk'] == ''; }); file_put_contents($filePath, json_encode($notifs)); log::add('mobile', 'info', '| Suppression des asks répondus effectuée'); From 6c3bd83b2d70202b76da6cfa6b33cf97be7d50f4 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:38:51 +0200 Subject: [PATCH 6/9] Update mobile.js --- desktop/js/mobile.js | 141 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 4 deletions(-) diff --git a/desktop/js/mobile.js b/desktop/js/mobile.js index 21e385eb..1074c907 100755 --- a/desktop/js/mobile.js +++ b/desktop/js/mobile.js @@ -54,6 +54,7 @@ document.querySelector("#bt_pluginmobile")?.addEventListener("click", function ( contentUrl: "index.php?v=d&plugin=mobile&modal=AppV1Plugin", }); }); + document.querySelector("#bt_piecemobile")?.addEventListener("click", function (event) { jeeDialog.dialog({ id: "objectsModal", @@ -61,6 +62,7 @@ document.querySelector("#bt_piecemobile")?.addEventListener("click", function (e contentUrl: "index.php?v=d&plugin=mobile&modal=AppV1Piece", }); }); + document.querySelector("#bt_scenariomobile")?.addEventListener("click", function (event) { jeeDialog.dialog({ id: "scenariosModal", @@ -68,6 +70,7 @@ document.querySelector("#bt_scenariomobile")?.addEventListener("click", function contentUrl: "index.php?v=d&plugin=mobile&modal=AppV1Scenario", }); }); + document.querySelector("#bt_regenConfig")?.addEventListener("click", function (event) { domUtils.ajax({ type: "POST", @@ -89,6 +92,48 @@ document.querySelector("#bt_regenConfig")?.addEventListener("click", function (e }); }); +// NotificationsV2 +document.querySelector(".notification-box")?.addEventListener("click", function (event) { + var _target = null + if (_target = event.target.closest('.bt_removeNotification')) { + let notification = _target.closest('.notification-step') + let id = notification.getAttribute('data-id'); + let iq = notification.getAttribute('data-iq'); + domUtils.ajax({ + type: "POST", + url: "plugins/mobile/core/ajax/mobile.ajax.php", + data: { + action: "removeNotificationV2", + id: id, + iq: iq + }, + dataType: "json", + error: function (request, status, error) { + domUtils.handleAjaxError(request, status, error) + }, + success: function (data) { + if (data.state != "ok") { + jeedomUtils.showAlert({ message: data.result, level: "danger" }) + return + } + notification.remove() + if (data.result == '0' && is_object(el = document.querySelector(".notification-box"))) { + el.innerHTML = '
{{Aucune notifications}}
' + } + jeedomUtils.showAlert({ message: "{{Notification supprimées.}}", level: "success"}); + }, + }); + return + } + + if (_target = event.target.closest('.bt_refreshNotifications')) { + let iq = _target.getAttribute('data-iq') + printNotification(iq) + jeedomUtils.showAlert({ message: "{{Terminé.}}", level: "success"}); + return + } +}); + // Copie pour monitoring var toCopy = document.getElementById("to-copy-monitoring"); var arnComplet = document.getElementById("arnComplet"); @@ -107,14 +152,13 @@ document.getElementById("copy-monitoring")?.addEventListener("click", function ( function printEqLogic(_eqLogic) { let appVersion = _eqLogic.configuration.appVersion; - console.log(appVersion) if (appVersion == 2) { document.querySelectorAll(".paramV1").unseen() document.querySelectorAll(".paramV2").seen() + printNotification(_eqLogic.logicalId) } else { document.querySelectorAll(".paramV2").unseen() document.querySelectorAll(".paramV1").seen() - } // AppV1 @@ -243,7 +287,6 @@ function printEqLogic(_eqLogic) { } function addCmdToTable(_cmd) { - console.log('addCmdToTable') if (document.getElementById('table_cmd') == null) return if (!isset(_cmd)) { var _cmd = { configuration: {} } @@ -307,6 +350,96 @@ function addCmdToTable(_cmd) { }) } +function printNotification(_iq) { + domUtils.ajax({ + type: "POST", + url: "plugins/mobile/core/ajax/mobile.ajax.php", + data: { + action: "getNotificationsV2", + iq: _iq, + }, + dataType: "json", + global: false, + error: function (request, status, error) { + domUtils.handleAjaxError(request, status, error) + }, + success: function (data) { + if (data.state != "ok") { + jeedomUtils.showAlert({ message: data.result, level: "danger" }) + return + } + + let el = document.querySelector(".notification-box"); + + try { + var objectData = JSON.parse(data.result); + } catch { + el.innerHTML = '
' + data.result + '
' + return + } + + if (typeof objectData == "object") { + let notification = '' + notification += '
Rafraichir
' + moment.locale(jeeFrontEnd.language.substring(0, 2)) + for (var i in objectData) { + // ASK + let askStatus = '' + let askChoice = '' + if (isset(objectData[i].data.choiceAsk)) { + askStatus = 'ask-success' + askChoice = objectData[i].data.choiceAsk + } else if (objectData[i].data.askVariable != 'rien') { + let notifTime = moment(objectData[i].data.date, "YYYY-MM-DD hh:mm:ss").unix() + let currentTime = moment().unix() + try { + let askParams = (isset(objectData[i].data.askParams)) ? JSON.parse(objectData[i].data.askParams) : '' + if (isset(askParams.timeout)) { + let timeout = askParams.timeout / 1000 + if ((currentTime - notifTime) > timeout) { + askStatus = 'ask-timeout' + askChoice = '{{Timeout}}' + } else { + askStatus += 'ask-in-progress' + askChoice = '{{En cours...}}' + } + } + } catch { } + } + + notification += '
' + notification += '
' + objectData[i].data.date + '
' + if (objectData[i].data.askVariable != 'rien') { + notification += '
ASK
' + } else if (objectData[i].data.critical == 'true') { + notification += '
N
' + } else if (objectData[i].data.silent == 'true') { + notification += '
NS
' + } else { + notification += '
N
' + } + notification += '
' + notification += '
' + //notification += ' {{Supprimer}}' + notification += '' + notification += '
' + objectData[i].data.title + '
' + notification += '
' + objectData[i].data.body + '
' + if (isset(objectData[i].data.image)) { + notification += '
' + } + if (askChoice != '') notification += '
' + askChoice + '
' + notification += '
' + notification += '
' + //console.log(objectData[i]) + } + el.innerHTML = notification + jeedomUtils.initTooltips(el) + } + }, + }); + +} + // WIZARD var _contentContainer = document.getElementById('wizard_container'); @@ -500,4 +633,4 @@ function allowNavigation(_direction = 'both', _allowed = true) { function exitWizard() { window.location.href = 'index.php?v=d&m=mobile&p=mobile'; -} \ No newline at end of file +} From 4acb27f8794a5008f81436420e13ec205a11533f Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:41:21 +0200 Subject: [PATCH 7/9] Update mobile.php --- desktop/php/mobile.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/desktop/php/mobile.php b/desktop/php/mobile.php index ead82a54..cf288f8f 100755 --- a/desktop/php/mobile.php +++ b/desktop/php/mobile.php @@ -178,6 +178,7 @@
  • {{Commandes}}
  • +
  • {{Notifications}}
  • @@ -362,8 +363,14 @@
    +
    +
    +
    Compatible AppV2 uniquement.
    +
    +
    + - \ No newline at end of file + From 047fa9995a451a032f6cee0048de5c28b04a9699 Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:18:59 +0200 Subject: [PATCH 8/9] Update mobile.js --- desktop/js/mobile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop/js/mobile.js b/desktop/js/mobile.js index 1074c907..5861fb3f 100755 --- a/desktop/js/mobile.js +++ b/desktop/js/mobile.js @@ -159,6 +159,8 @@ function printEqLogic(_eqLogic) { } else { document.querySelectorAll(".paramV2").unseen() document.querySelectorAll(".paramV1").seen() + let el = document.querySelector(".notification-box"); + el.innerHTML = '
    Compatible AppV2 uniquement.
    ' } // AppV1 From 6a934df23c34f0dc70cd05b986c6fb65b7eaca9a Mon Sep 17 00:00:00 2001 From: David <79108364+Phpvarious@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:25:01 +0200 Subject: [PATCH 9/9] Update mobile.class.php --- core/class/mobile.class.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/class/mobile.class.php b/core/class/mobile.class.php index d063c501..89dd8a4b 100755 --- a/core/class/mobile.class.php +++ b/core/class/mobile.class.php @@ -1019,14 +1019,11 @@ public static function notification($arn, $os, $titre, $message, $type, $idNotif */ public static function getNotificationsV2($Iq) { - $return = ''; + $return = __('Aucune notification.', __FILE__); $filePath = dirname(__FILE__) . '/../data/notifications/' . $Iq . '.json'; if (file_exists($filePath)) { $notifs = json_decode(file_get_contents($filePath), true); if (is_array($notifs) && count($notifs) > 0) $return = json_encode(array_reverse($notifs)); - else $return = __('Aucune notifications.', __FILE__); - } else { - $return = __('Fichier de notifications non trouvé.', __FILE__); } return $return; }