From eef60ba2cfa54db9053e2b7ab1ef0146e495506b Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Wed, 24 Dec 2025 08:50:19 +0100 Subject: [PATCH 01/84] Update checkPHP.yml --- .github/workflows/checkPHP.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checkPHP.yml b/.github/workflows/checkPHP.yml index a6cbfbe3..24a76b5e 100644 --- a/.github/workflows/checkPHP.yml +++ b/.github/workflows/checkPHP.yml @@ -12,8 +12,8 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: PHP Syntax Checker (Lint) - uses: StephaneBour/actions-php-lint@8.2 + uses: StephaneBour/actions-php-lint@8.4 with: dir: '.' From ba8586706b961ff04aea2005deff9cc7805081c5 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Mon, 29 Dec 2025 17:30:26 +0100 Subject: [PATCH 02/84] update gitignore --- .gitignore | 53 +++++++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 2 ++ 2 files changed, 55 insertions(+) diff --git a/.gitignore b/.gitignore index 8b137891..be7f335c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,54 @@ +# IDE & Editors +.vscode/* +!.vscode/settings.json +!.vscode/extensions.json +# OS Generated Files +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# Editor Temporary Files +*.swp +*.swo +*~ +*.bak +*.orig + +# PHP Temporary Files +*.tmp +*.cache + +# Environment & Configuration +.env +.env.local +.env.*.local + +# Logs +logs/ +*.log + +# Temporary Directories +tmp/ +temp/ +cache/ + +# PHP Development Tools +.php_cs.cache +.php-cs-fixer.cache + +# PHPUnit +/phpunit.xml +/.phpunit.result.cache +/coverage/ + +# Build & Distribution +/build/ +/dist/ + +# Security & Credentials +*.pem +*.key +id_rsa* diff --git a/.vscode/settings.json b/.vscode/settings.json index e7d6b117..8aa8d4e8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -48,6 +48,7 @@ "iface", "ifname", "ifnames", + "isset", "jffs", "loadavg", "Localor", @@ -68,6 +69,7 @@ "paramaction", "PCPVERS", "pcpversion", + "phpunit", "physmem", "portssh", "POSTSAVE", From d1de593cd4d886f256e15fd241e3e45a7d795d41 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:13:47 +0100 Subject: [PATCH 03/84] Rewrite JS --- .vscode/settings.json | 2 + desktop/js/Monitoring.js | 548 +++++++++++++++++++++++++++------------ plugin_info/info.json | 2 +- 3 files changed, 381 insertions(+), 171 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8aa8d4e8..56f38015 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,6 +26,7 @@ "deporte", "distri", "dnsmasq", + "ehthumbs", "ELEC", "Eqlogic", "eqlogictab", @@ -44,6 +45,7 @@ "hddusb", "hddv", "Historized", + "htmlstate", "hwmon", "iface", "ifname", diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 4bc87368..0bd8fc67 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -14,179 +14,387 @@ * along with Jeedom. If not, see . */ -/* Fonction permettant l'affichage des commandes dans l'équipement */ +// Protect against multiple script loads (Jeedom SPA navigation, cache, etc.) +(function() { +'use strict' + +// DOM Selectors constants (better minification + no string repetition + immutable) +const SELECTORS = Object.freeze({ + TABLE_CMD: '#table_cmd', + EQ_ID: '.eqLogicAttr[data-l1key=id]', + SYNO_CHECKBOX: '.eqLogicAttr[data-l2key=synology]', + QNAP_CHECKBOX: '.eqLogicAttr[data-l2key=qnap]', + ASUS_CHECKBOX: '.eqLogicAttr[data-l2key=asuswrt]', + SYNO_CONF: '.syno_conf', + ASUS_CONF: '.asuswrt_conf' +}) + +// Liste des commandes pouvant être historisées (en constant pour performance) +const HISTORIZED_COMMANDS = Object.freeze([ + 'cron_status', 'uptime_sec', 'load_avg_1mn', 'load_avg_5mn', 'load_avg_15mn', + 'memory_total', 'memory_used', 'memory_free', 'memory_buffcache', 'memory_available', + 'memory_free_percent', 'memory_used_percent', 'memory_available_percent', + 'swap_free_percent', 'swap_used_percent', 'swap_total', 'swap_used', 'swap_free', + 'network_tx', 'network_rx', 'hdd_total', 'hdd_used', 'hdd_free', + 'hdd_used_percent', 'hdd_free_percent', 'cpu_temp', + 'perso1', 'perso2', 'perso3', 'perso4', + 'syno_hddv2_total', 'syno_hddv2_used', 'syno_hddv2_free', 'syno_hddv2_used_percent', 'syno_hddv2_free_percent', + 'syno_hddusb_total', 'syno_hddusb_used', 'syno_hddusb_used_percent', 'syno_hddusb_free', 'syno_hddusb_free_percent', + 'syno_hddesata_total', 'syno_hddesata_used', 'syno_hddesata_used_percent', 'syno_hddesata_free', 'syno_hddesata_free_percent', + 'asus_clients_total', 'asus_clients_wifi24', 'asus_clients_wifi5', 'asus_clients_wired', + 'asus_fw_check', 'asus_wifi2g_temp', 'asus_wifi5g_temp' +]) + +// Commandes avec seuils verts (bas) vers rouges (haut) +const GREEN_TO_RED_COMMANDS = Object.freeze([ + 'load_avg_1mn', 'load_avg_5mn', 'load_avg_15mn', + 'memory_used_percent', 'swap_used_percent', 'cpu_temp', + 'hdd_used_percent', 'syno_hddv2_used_percent', 'syno_hddusb_used_percent', 'syno_hddesata_used_percent' +]) + +// Commandes avec seuils rouges (bas) vers verts (haut) +const RED_TO_GREEN_COMMANDS = Object.freeze([ + 'memory_free_percent', 'swap_free_percent', 'memory_available_percent', + 'hdd_free_percent', 'syno_hddv2_free_percent', 'syno_hddusb_free_percent', 'syno_hddesata_free_percent' +]) + +// Commandes personnalisables +const CUSTOM_COMMANDS = Object.freeze(['perso1', 'perso2', 'perso3', 'perso4']) + +// Commandes liées (pour select value) +const LINKED_COMMANDS = Object.freeze(['cron_status', 'cron_on', 'cron_off']) + +/** + * Helper pour générer les champs de seuils de couleurs + */ +const buildColorThresholds = (logicalId, reverseColors = false) => { + if (reverseColors) { + return `[{{Rouge}}] < ≤ [{{Orange}}] ≤ < [{{Vert}}]` + } + return `[{{Vert}}] < ≤ [{{Orange}}] ≤ < [{{Rouge}}]` +} + +/** + * Fonction permettant l'affichage des commandes dans l'équipement + * @param {Object} _cmd - Commande à ajouter + */ function addCmdToTable(_cmd) { - if (!isset(_cmd)) { - var _cmd = { configuration: {} }; - } - if (!isset(_cmd.configuration)) { - _cmd.configuration = {} - } - - let tr = ''; - tr += ''; - tr += ''; - tr += ''; - tr += ''; - tr += '
' - tr += ''; - tr += ''; - tr += ''; - tr += ''; - tr += '
'; - - if (['cron_status', 'cron_on', 'cron_off'].includes(init(_cmd.logicalId))) { - tr += ''; - } - tr += ''; - tr += ''; - if (['load_avg_1mn', 'load_avg_5mn', 'load_avg_15mn', 'memory_used_percent', 'swap_used_percent', 'cpu_temp', 'hdd_used_percent', 'syno_hddv2_used_percent', 'syno_hddusb_used_percent', 'syno_hddesata_used_percent'].includes(init(_cmd.logicalId))) { - tr += '[{{Vert}}] \< \u{2264} [{{Orange}}] \u{2264} \< [{{Rouge}}]'; - } - if (['memory_free_percent', 'swap_free_percent', 'memory_available_percent', 'hdd_free_percent', 'syno_hddv2_free_percent', 'syno_hddusb_free_percent', 'syno_hddesata_free_percent'].includes(init(_cmd.logicalId))) { - tr += '[{{Rouge}}] \< \u{2264} [{{Orange}}] \u{2264} \< [{{Vert}}]'; - } - if (['perso1', 'perso2', 'perso3', 'perso4'].includes(init(_cmd.logicalId))) { - tr += ''; - tr += ' {{Unité}} : '; - tr += '
[{{Vert}}] \< \u{2264} [{{Orange}}] \u{2264} \< [{{Rouge}}]'; - } - tr += ''; - tr += ''; - tr += ''; - - // Liste des commandes de base pouvant être historisées - let historizedCommands = ['cron_status', 'uptime_sec', 'load_avg_1mn', 'load_avg_5mn', 'load_avg_15mn', 'memory_total', 'memory_used', 'memory_free', 'memory_buffcache', 'memory_available', 'memory_free_percent', 'memory_used_percent', 'memory_available_percent', 'swap_free_percent', 'swap_used_percent', 'swap_total', 'swap_used', 'swap_free', 'network_tx', 'network_rx', 'hdd_total', 'hdd_used', 'hdd_free', 'hdd_used_percent', 'hdd_free_percent', 'cpu_temp', 'perso1', 'perso2', 'perso3', 'perso4', 'syno_hddv2_total', 'syno_hddv2_used', 'syno_hddv2_free', 'syno_hddv2_used_percent', 'syno_hddv2_free_percent', 'syno_hddusb_total', 'syno_hddusb_used', 'syno_hddusb_used_percent', 'syno_hddusb_free', 'syno_hddusb_free_percent', 'syno_hddesata_total', 'syno_hddesata_used', 'syno_hddesata_used_percent', 'syno_hddesata_free', 'syno_hddesata_free_percent', 'asus_clients_total', 'asus_clients_wifi24', 'asus_clients_wifi5', 'asus_clients_wired', 'asus_fw_check', 'asus_wifi2g_temp', 'asus_wifi5g_temp']; - - // Vérifier si c'est une commande standard ou une commande de carte réseau supplémentaire - let canBeHistorized = historizedCommands.includes(init(_cmd.logicalId)) || - init(_cmd.logicalId).startsWith('network_tx_') || - init(_cmd.logicalId).startsWith('network_rx_'); - - if (canBeHistorized) { - tr += ''; - } - tr += ''; - tr += ''; - if (['perso1', 'perso2', 'perso3', 'perso4', 'cron_status'].includes(init(_cmd.logicalId))) { - tr += ''; - tr += ''; - } - tr += ''; - tr += ''; - tr += ''; - tr += ''; - - tr += ''; - if (is_numeric(_cmd.id)) { - tr += ' '; - tr += ' {{Tester}}'; - } - tr += ''; - tr += ''; - tr += ''; - - let newRow = document.createElement('tr') - newRow.innerHTML = tr - newRow.addClass('cmd') - newRow.setAttribute('data-cmd_id', init(_cmd.id)) - document.getElementById('table_cmd').querySelector('tbody').appendChild(newRow) - - jeedom.eqLogic.buildSelectCmd({ - id: document.querySelector('.eqLogicAttr[data-l1key="id"]').jeeValue(), - filter: { type: 'info' }, - error: function(error) { - jeedomUtils.showAlert({ message: error.message, level: 'danger' }) - }, - success: function(result) { - newRow.querySelector('.cmdAttr[data-l1key="value"]')?.insertAdjacentHTML('beforeend', result) - newRow.setJeeValues(_cmd, '.cmdAttr') - jeedom.cmd.changeType(newRow, init(_cmd.subType)) - } - }) + if (!isset(_cmd)) { + var _cmd = { configuration: {} } + } + if (!isset(_cmd.configuration)) { + _cmd.configuration = {} + } + + const logicalId = init(_cmd.logicalId) + + // Vérifier si c'est une commande standard ou une commande de carte réseau supplémentaire + const canBeHistorized = HISTORIZED_COMMANDS.includes(logicalId) || + logicalId.startsWith('network_tx_') || + logicalId.startsWith('network_rx_') + + // Déterminer le type de configuration + const hasGreenToRed = GREEN_TO_RED_COMMANDS.includes(logicalId) + const hasRedToGreen = RED_TO_GREEN_COMMANDS.includes(logicalId) + const isCustom = CUSTOM_COMMANDS.includes(logicalId) + const isLinked = LINKED_COMMANDS.includes(logicalId) + const hasTypeSubType = isCustom || logicalId === 'cron_status' + + // Générer les différentes parties du HTML + let configCell = '' + if (hasGreenToRed) { + configCell = buildColorThresholds(logicalId, false) + } else if (hasRedToGreen) { + configCell = buildColorThresholds(logicalId, true) + } else if (isCustom) { + configCell = ` + {{Unité}} : +
${buildColorThresholds(logicalId, false)}` + } + + // Construction du HTML avec template literals (optimal V8 performance) + const testButtons = is_numeric(_cmd.id) + ? ' {{Tester}}' + : '' + + const rowHtml = ` + + +
+ + + + +
+ ${isLinked ? '' : ''} + + ${configCell} + + + ${canBeHistorized ? '' : ''} + + + ${hasTypeSubType ? `` : ''} + + + + ${testButtons} + + ` + + // Create and configure row element (optimal: Object.assign for batch properties) + const newRow = Object.assign(document.createElement('tr'), { + className: 'cmd', + innerHTML: rowHtml + }) + newRow.setAttribute('data-cmd_id', init(_cmd.id)) + + // Cache table body for performance + const tableBody = document.querySelector(`${SELECTORS.TABLE_CMD} tbody`) + if (!tableBody) return console.error('Table body not found') + + tableBody.appendChild(newRow) + + // Cache eqLogic ID to avoid multiple DOM queries + const eqLogicIdElement = document.querySelector(SELECTORS.EQ_ID) + if (!eqLogicIdElement) return console.error('Equipment ID element not found') + + jeedom.eqLogic.buildSelectCmd({ + id: eqLogicIdElement.jeeValue(), + filter: { type: 'info' }, + error: function(error) { + jeedomUtils.showAlert({ message: error.message, level: 'danger' }) + }, + success: function(result) { + newRow.querySelector('.cmdAttr[data-l1key="value"]')?.insertAdjacentHTML('beforeend', result) + newRow.setJeeValues(_cmd, '.cmdAttr') + jeedom.cmd.changeType(newRow, init(_cmd.subType)) + } + }) } -document.querySelector(".eqLogicAttr[data-l2key='synology']").addEventListener('change', function() { - if (this.checked) { - document.querySelector(".syno_conf").style.display = "block"; - document.querySelector(".asuswrt_conf").style.display = "none"; - document.querySelector('input.eqLogicAttr[data-l2key="asuswrt"]').checked = false; - document.querySelector('input.eqLogicAttr[data-l2key="qnap"]').checked = false; - } else { - document.querySelector(".syno_conf").style.display = "none"; - } -}); - -document.querySelector(".eqLogicAttr[data-l2key='qnap']").addEventListener('change', function() { - if (this.checked) { - document.querySelector('input.eqLogicAttr[data-l2key="asuswrt"]').checked = false; - document.querySelector('input.eqLogicAttr[data-l2key="synology"]').checked = false; - document.querySelector(".syno_conf").style.display = "none"; - document.querySelector(".asuswrt_conf").style.display = "none"; - } -}); - -document.querySelector(".eqLogicAttr[data-l2key='asuswrt']").addEventListener('change', function() { - if (this.checked) { - document.querySelector('input.eqLogicAttr[data-l2key="qnap"]').checked = false; - document.querySelector('input.eqLogicAttr[data-l2key="synology"]').checked = false; - document.querySelector(".syno_conf").style.display = "none"; - document.querySelector(".asuswrt_conf").style.display = "block"; - } else { - document.querySelector(".asuswrt_conf").style.display = "none"; - } -}); - -document.querySelectorAll('.pluginAction[data-action=openLocation]').forEach(function (element) { - element.addEventListener('click', function () { - window.open(this.getAttribute("data-location"), "_blank", null); - }); -}); - -document.querySelector(".eqLogicAttr[data-l2key='syno_use_temp_path']").addEventListener('change', function () { - if(this.checked){ - document.querySelector(".syno_conf_temppath").style.display = "block"; - } else { - document.querySelector(".syno_conf_temppath").style.display = "none"; - } -}); - -document.querySelector(".eqLogicAttr[data-l2key='linux_use_temp_cmd']").addEventListener('change', function() { - if (this.checked) { - document.querySelector(".linux_class_temp_cmd").style.display = "block"; - } else { - document.querySelector(".linux_class_temp_cmd").style.display = "none"; - } -}); - -document.querySelector(".eqLogicAttr[data-l2key='pull_use_custom']").addEventListener('change', function () { - if(this.checked){ - document.querySelector(".pull_class").style.display = "block"; - } else { - document.querySelector(".pull_class").style.display = "none"; - } -}); - -document.querySelector(".eqLogicAttr[data-l2key='multi_if']").addEventListener('change', function () { - if(this.checked){ - document.querySelector(".multi_if_conf").style.display = "block"; - } else { - document.querySelector(".multi_if_conf").style.display = "none"; - } -}); - -document.querySelector(".eqLogicAttr[data-l2key='localoudistant']").addEventListener('change', function () { - if (this.selectedIndex == 1) { - document.querySelector(".distant").style.display = "block"; - document.querySelector(".local").style.display = "none"; - } else { - document.querySelector(".distant").style.display = "none"; - document.querySelector(".local").style.display = "block"; - } -}); +// Helper functions pour une meilleure réutilisation +const updateCheckboxGroup = (checkbox, showElements = [], hideElements = [], uncheckElements = []) => { + if (!checkbox) return + + if (checkbox.checked) { + showElements.forEach(el => el?.seen()) + hideElements.forEach(el => el?.unseen()) + uncheckElements.forEach(el => el?.value(0)) + } else { + showElements.forEach(el => el?.unseen()) + hideElements.forEach(el => el?.unseen()) + } +} + +// Handlers nommés pour pouvoir les remove/add proprement (spécifiques à chaque équipement) +const handleSynologyChange = function() { + updateCheckboxGroup( + this, + [document.querySelector(SELECTORS.SYNO_CONF)], + [document.querySelector(SELECTORS.ASUS_CONF)], + [document.querySelector(SELECTORS.ASUS_CHECKBOX), document.querySelector(SELECTORS.QNAP_CHECKBOX)] + ) +} + +const handleQnapChange = function() { + if (this.checked) { + const asusCheckbox = document.querySelector(SELECTORS.ASUS_CHECKBOX) + const synoCheckbox = document.querySelector(SELECTORS.SYNO_CHECKBOX) + const synoConf = document.querySelector(SELECTORS.SYNO_CONF) + const asusConf = document.querySelector(SELECTORS.ASUS_CONF) + + asusCheckbox?.value(0) + synoCheckbox?.value(0) + synoConf?.unseen() + asusConf?.unseen() + } +} + +const handleAsusChange = function() { + updateCheckboxGroup( + this, + [document.querySelector(SELECTORS.ASUS_CONF)], + [document.querySelector(SELECTORS.SYNO_CONF)], + [document.querySelector(SELECTORS.QNAP_CHECKBOX), document.querySelector(SELECTORS.SYNO_CHECKBOX)] + ) +} + +const handleSynoTempPath = function() { + const tempPath = document.querySelector('.syno_conf_temppath') + if (this.checked) { + tempPath?.seen() + } else { + tempPath?.unseen() + } +} + +const handleLinuxTempCmd = function() { + const tempCmd = document.querySelector('.linux_class_temp_cmd') + if (this.checked) { + tempCmd?.seen() + } else { + tempCmd?.unseen() + } +} + +const handlePullCustom = function() { + const pullClass = document.querySelector('.pull_class') + if (this.checked) { + pullClass?.seen() + } else { + pullClass?.unseen() + } +} + +const handleMultiIf = function() { + const multiIfConf = document.querySelector('.multi_if_conf') + if (this.checked) { + multiIfConf?.seen() + } else { + multiIfConf?.unseen() + } +} + +const handleLocalDistant = function() { + const distantDiv = document.querySelector('.distant') + const localDiv = document.querySelector('.local') + + if (this.selectedIndex === 1) { + distantDiv?.seen() + localDiv?.unseen() + } else { + distantDiv?.unseen() + localDiv?.seen() + } +} + +// Event delegation pour openLocation (global, attaché une seule fois) +if (!window.monitoringOpenLocationAttached) { + window.monitoringOpenLocationAttached = true + + document.addEventListener('click', (event) => { + const target = event.target.closest('.pluginAction[data-action=openLocation]') + if (target) { + event.preventDefault() + window.open(target.getAttribute('data-location'), '_blank', null) + } + }) +} function printEqLogic(_eqLogic) { - buildSelectHost(_eqLogic.configuration.SSHHostId); + if (!_eqLogic) return + + // Cache DOM elements once + const elements = { + synoCheckbox: document.querySelector(SELECTORS.SYNO_CHECKBOX), + qnapCheckbox: document.querySelector(SELECTORS.QNAP_CHECKBOX), + asusCheckbox: document.querySelector(SELECTORS.ASUS_CHECKBOX), + synoConf: document.querySelector(SELECTORS.SYNO_CONF), + asusConf: document.querySelector(SELECTORS.ASUS_CONF), + synoTempPath: document.querySelector('.eqLogicAttr[data-l2key="syno_use_temp_path"]'), + synoTempPathDiv: document.querySelector('.syno_conf_temppath'), + linuxTempCmd: document.querySelector('.eqLogicAttr[data-l2key="linux_use_temp_cmd"]'), + linuxTempCmdDiv: document.querySelector('.linux_class_temp_cmd'), + pullCustom: document.querySelector('.eqLogicAttr[data-l2key="pull_use_custom"]'), + pullDiv: document.querySelector('.pull_class'), + multiIf: document.querySelector('.eqLogicAttr[data-l2key="multi_if"]'), + multiIfDiv: document.querySelector('.multi_if_conf'), + localDistant: document.querySelector('.eqLogicAttr[data-l2key="localoudistant"]'), + distantDiv: document.querySelector('.distant'), + localDiv: document.querySelector('.local') + } + + // Attach event listeners for equipment-specific checkboxes (re-attached on each equipment load) + if (elements.synoCheckbox) { + elements.synoCheckbox.removeEventListener('change', handleSynologyChange) + elements.synoCheckbox.addEventListener('change', handleSynologyChange) + } + + if (elements.qnapCheckbox) { + elements.qnapCheckbox.removeEventListener('change', handleQnapChange) + elements.qnapCheckbox.addEventListener('change', handleQnapChange) + } + + if (elements.asusCheckbox) { + elements.asusCheckbox.removeEventListener('change', handleAsusChange) + elements.asusCheckbox.addEventListener('change', handleAsusChange) + } + + if (elements.synoTempPath) { + elements.synoTempPath.removeEventListener('change', handleSynoTempPath) + elements.synoTempPath.addEventListener('change', handleSynoTempPath) + // Initialiser l'affichage au chargement + if (elements.synoTempPath.checked) { + elements.synoTempPathDiv?.seen() + } else { + elements.synoTempPathDiv?.unseen() + } + } + + if (elements.linuxTempCmd) { + elements.linuxTempCmd.removeEventListener('change', handleLinuxTempCmd) + elements.linuxTempCmd.addEventListener('change', handleLinuxTempCmd) + // Initialiser l'affichage au chargement + if (elements.linuxTempCmd.checked) { + elements.linuxTempCmdDiv?.seen() + } else { + elements.linuxTempCmdDiv?.unseen() + } + } + + if (elements.pullCustom) { + elements.pullCustom.removeEventListener('change', handlePullCustom) + elements.pullCustom.addEventListener('change', handlePullCustom) + // Initialiser l'affichage au chargement + if (elements.pullCustom.checked) { + elements.pullDiv?.seen() + } else { + elements.pullDiv?.unseen() + } + } + + if (elements.multiIf) { + elements.multiIf.removeEventListener('change', handleMultiIf) + elements.multiIf.addEventListener('change', handleMultiIf) + // Initialiser l'affichage au chargement + if (elements.multiIf.checked) { + elements.multiIfDiv?.seen() + } else { + elements.multiIfDiv?.unseen() + } + } + + if (elements.localDistant) { + elements.localDistant.removeEventListener('change', handleLocalDistant) + elements.localDistant.addEventListener('change', handleLocalDistant) + // Initialiser l'affichage au chargement + if (elements.localDistant.selectedIndex === 1) { + elements.distantDiv?.seen() + elements.localDiv?.unseen() + } else { + elements.distantDiv?.unseen() + elements.localDiv?.seen() + } + } + + // Initialiser l'affichage des sections Synology/QNAP/Asus au chargement + if (elements.synoCheckbox?.checked) { + elements.synoConf?.seen() + elements.asusConf?.unseen() + } else if (elements.asusCheckbox?.checked) { + elements.asusConf?.seen() + elements.synoConf?.unseen() + } else { + elements.synoConf?.unseen() + elements.asusConf?.unseen() + } + + buildSelectHost(_eqLogic.configuration.SSHHostId) } + +// Expose functions globally for Jeedom to call them +window.addCmdToTable = addCmdToTable +window.printEqLogic = printEqLogic + +})() // End of IIFE protection diff --git a/plugin_info/info.json b/plugin_info/info.json index c297e0f8..64de35e7 100644 --- a/plugin_info/info.json +++ b/plugin_info/info.json @@ -1,7 +1,7 @@ { "id": "Monitoring", "name": "Monitoring", - "pluginVersion": "3.3.0", + "pluginVersion": "3.3.1", "description": { "fr_FR": "Plugin permettant le monitoring des équipements locaux et distants (via SSH). Le plugin affichera les informations systèmes d'équipements sous Linux ou Synology (Distribution, CPU, Mémoire, Disques, Swap).", "en_US": "Plugin to monitor local and remote equipments (through SSH). The plugin will display system informations from Linux or Synology (Distribution, CPU, Memory, Disks, Swap).", From acfa48ecdbdc0db5c8546f38c5a8cb2920bd8747 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 1 Jan 2026 21:41:48 +0100 Subject: [PATCH 04/84] Rewrite JS code --- core/class/Monitoring.class.php | 20 +- core/template/dashboard/AsusWRT.html | 530 +++++++++------- core/template/dashboard/Monitoring.html | 781 +++++++++++++++--------- core/template/mobile/AsusWRT.html | 526 ++++++++++------ core/template/mobile/Monitoring.html | 717 ++++++++++++++-------- 5 files changed, 1643 insertions(+), 931 deletions(-) diff --git a/core/class/Monitoring.class.php b/core/class/Monitoring.class.php index f1019b7d..23ff2898 100644 --- a/core/class/Monitoring.class.php +++ b/core/class/Monitoring.class.php @@ -2287,18 +2287,26 @@ public function toHtml($_version = 'dashboard') {
#network_' . $if_safe . '_icon#
'; } } diff --git a/core/template/dashboard/AsusWRT.html b/core/template/dashboard/AsusWRT.html index 0fb59438..97581dc0 100644 --- a/core/template/dashboard/AsusWRT.html +++ b/core/template/dashboard/AsusWRT.html @@ -75,64 +75,71 @@
@@ -145,13 +152,15 @@
@@ -164,260 +173,373 @@
#load_avg_icon#
#memory_icon#
#swap_icon#
#network_infos_icon#
#network_icon#
#asus_clients_icon#
#asus_wan0_ip_icon#
#asus_wifi_temp_icon#
#hdd_icon#
#cpu_icon#
#perso1_icon#
#perso2_icon#
#perso3_icon#
#perso4_icon#
#divGraphInfo# diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index e412847a..9640f1cf 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -75,81 +75,80 @@
@@ -162,13 +161,17 @@
@@ -181,108 +184,175 @@
#load_avg_icon#
#memory_icon#
#swap_icon#
#network_infos_icon#
#network_icon#
#multi_network_cards# @@ -291,220 +361,379 @@
#cpu_icon#
#perso1_icon#
#perso2_icon#
#perso3_icon#
#perso4_icon#
#divGraphInfo# diff --git a/core/template/mobile/AsusWRT.html b/core/template/mobile/AsusWRT.html index 8e5bdacc..9eee1c45 100644 --- a/core/template/mobile/AsusWRT.html +++ b/core/template/mobile/AsusWRT.html @@ -71,48 +71,69 @@ @@ -125,13 +146,19 @@ @@ -145,258 +172,379 @@
#load_avg_icon#
#memory_icon#
#swap_icon#
#network_infos_icon#
#network_icon#
#asus_clients_icon#
#asus_wan0_ip_icon#
#asus_wifi_temp_icon#
#hdd_icon#
#cpu_icon#
#perso1_icon#
#perso2_icon#
#perso3_icon#
#perso4_icon#
#divGraphInfo# diff --git a/core/template/mobile/Monitoring.html b/core/template/mobile/Monitoring.html index b525a877..ea13f61c 100644 --- a/core/template/mobile/Monitoring.html +++ b/core/template/mobile/Monitoring.html @@ -71,50 +71,68 @@ - + @@ -126,13 +144,16 @@ @@ -146,106 +167,137 @@
#load_avg_icon#
#memory_icon#
#swap_icon#
#network_infos_icon#
#network_icon#
#multi_network_cards# @@ -254,220 +306,373 @@
#cpu_icon#
#perso1_icon#
#perso2_icon#
#perso3_icon#
#perso4_icon#
#divGraphInfo# From 4de6d278a047bfd7427f3146b510d5e389b1fbe3 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 1 Jan 2026 23:15:15 +0100 Subject: [PATCH 05/84] update JS --- core/template/dashboard/Monitoring.html | 34 ++++++++++++------------- core/template/mobile/AsusWRT.html | 10 ++++---- core/template/mobile/Monitoring.html | 9 ++++--- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index 9640f1cf..11b919a9 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -102,7 +102,7 @@ const label = isOn ? 'ON' : 'OFF' const customLabel = isCustom ? 'Custom' : 'Default' const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') - + iconCron.innerHTML = `` })() @@ -110,22 +110,22 @@ @@ -737,4 +737,4 @@ #divGraphInfo# - \ No newline at end of file + diff --git a/core/template/mobile/AsusWRT.html b/core/template/mobile/AsusWRT.html index 9eee1c45..9ed29370 100644 --- a/core/template/mobile/AsusWRT.html +++ b/core/template/mobile/AsusWRT.html @@ -94,11 +94,11 @@ const isCustom = '#cron_status_custom#' === '1' if (status === '1') { - const color = isCustom ? 'var(--al-warning-color)' : 'var(--al-success-color)' - const label = isCustom ? 'Cron ON (Custom)' : 'Cron ON (Default)' - el.innerHTML = `` - } else if (status === '0') { - const color = isCustom ? 'var(--al-warning-color)' : 'var(--al-danger-color)' + const color = isCustom ? 'var(--al-warning-color)' : 'var(--al-success-color)' + const label = isCustom ? 'Cron ON (Custom)' : 'Cron ON (Default)' + el.innerHTML = `` + } else if (status === '0') { + const color = isCustom ? 'var(--al-warning-color)' : 'var(--al-danger-color)' const label = isCustom ? 'Cron OFF (Custom)' : 'Cron OFF (Default)' el.innerHTML = `` } diff --git a/core/template/mobile/Monitoring.html b/core/template/mobile/Monitoring.html index ea13f61c..85f3baf4 100644 --- a/core/template/mobile/Monitoring.html +++ b/core/template/mobile/Monitoring.html @@ -89,10 +89,11 @@ 'use strict' const el = document.getElementById('iconCron#id#') if (!el) return - - const isCustom = '#cron_status_custom#' === '1' - const color = isCustom ? 'var(--al-warning-color)' : (('#cron_status#' === '1') ? 'var(--al-success-color)' : 'var(--al-danger-color)') - const customLabel = isCustom ? ' (Custom)' : ' (Default)' + + const isCustom = '#cron_status_custom#' === '1' + const color = isCustom ? 'var(--al-warning-color)' : (('#cron_status#' === '1') ? 'var(--al-success-color)' : 'var(--al-danger-color)') + const customLabel = isCustom ? ' (Custom)' : ' (Default)' + if ('#cron_status#' === '1') { el.innerHTML = `` From 824b108fb25f042087abb28d9f69ee3ce32c7e5a Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 12:42:42 +0100 Subject: [PATCH 06/84] rewrite dashboard template Monitoring --- .vscode/settings.json | 1 + core/template/dashboard/Monitoring.html | 1013 +++++++++++------------ 2 files changed, 495 insertions(+), 519 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 56f38015..c3395223 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,7 @@ "eqlogictab", "equipement", "Equipement", + "esata", "Etat", "firmver", "Formated", diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index 11b919a9..2e715e2a 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -74,82 +74,13 @@
- - - -
#name_display# #object_name# @@ -160,19 +91,6 @@
-
@@ -183,56 +101,389 @@ #uptime_icon#
-
#load_avg_icon#
- -
- #memory_icon# - -
- -
- #swap_icon# - -
- -
- #network_infos_icon# - -
- -
- #network_icon# - -
- - - #multi_network_cards# -
- #hdd_icon# - -
- -
- -
- -
- -
- -
- -
- #cpu_icon# - -
- -
- #perso1_icon# - -
- -
- #perso2_icon# - -
- -
- #perso3_icon# - -
- -
- #perso4_icon# - -
- -
- #divGraphInfo# + el.innerHTML = `${value}${dataset.persoUnite}${dataset.persoTendance}` + } + + // ======================================== + // === INITIALIZATION === + // ======================================== + + // Only initialize if template is properly instantiated + if ('#uid#') { + // Icon handlers + initIconSSH() + initIconCron() + + // Button handlers + initRebootButton() + initPoweroffButton() + initRefreshButton() + + // Simple value displays + initUptime() + initNetworkInfos() + initNetwork() + + // Value displays with thresholds + initLoadAverage() + initMemory() + initSwap() + initHDD() + + // Synology volumes - generic initialization using data attributes + document.querySelectorAll('[data-syno-id]').forEach(initSynoVolume) + + // CPU with temperature + initCPU() + + // Custom commands - generic initialization using data attributes + document.querySelectorAll('[data-perso-id]').forEach(initPerso) + } + })() + From 46a43c0ae73e80ffc2a67e627dbae74ed77b6659 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 12:59:30 +0100 Subject: [PATCH 07/84] Update AsusWRT.html --- core/template/dashboard/AsusWRT.html | 833 +++++++++++++++------------ 1 file changed, 463 insertions(+), 370 deletions(-) diff --git a/core/template/dashboard/AsusWRT.html b/core/template/dashboard/AsusWRT.html index 97581dc0..42cd756a 100644 --- a/core/template/dashboard/AsusWRT.html +++ b/core/template/dashboard/AsusWRT.html @@ -74,73 +74,11 @@
- - - - + -
#name_display# #object_name# @@ -151,17 +89,6 @@
-
@@ -172,375 +99,541 @@ #uptime_icon#
-
#load_avg_icon#
-
#memory_icon#
-
#swap_icon#
-
#network_infos_icon#
-
#network_icon#
-
#asus_clients_icon#
-
#asus_wan0_ip_icon#
-
#asus_wifi_temp_icon#
-
#hdd_icon#
- -
- #cpu_icon# - -
- -
- #perso1_icon# - -
- -
- #perso2_icon# - -
- -
- #perso3_icon# - -
- -
- #perso4_icon# - -
- -
- #divGraphInfo# - \ No newline at end of file + const low = parseFloat(dataset.persoLow) + const high = parseFloat(dataset.persoHigh) + const history = JSON.parse(dataset.persoHistory) + const title = `Stats : ${dataset.persoName}
Min: ${history.min} | Moy : ${history.avg} | Max : ${history.max}` + const color = getColorStyle(val, low, high, false) + + el.innerHTML = `${value}${dataset.persoUnite}${dataset.persoTendance}` + } + + // ======================================== + // === INITIALIZATION === + // ======================================== + + // Only initialize if template is properly instantiated + if ('#uid#') { + // Icon handlers + initIconSSH() + initIconCron() + initIconCheckFirmware() + + // Button handlers + initRebootButton() + initRefreshButton() + + // Simple value displays + initUptime() + initNetworkInfos() + initNetwork() + initAsusClients() + initAsusWan0IP() + initAsusWifiTemp() + + // Value displays with thresholds + initLoadAverage() + initMemory() + initSwap() + initHDD() + + // CPU with temperature + initCPU() + + // Custom commands - generic initialization using data attributes + document.querySelectorAll('[data-perso-id]').forEach(initPerso) + } + })() + + From 10f3f88ee643fcf48f43667d3ef33bf5388635b6 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 13:15:55 +0100 Subject: [PATCH 08/84] Rewrite Asus and Monitoring Templates for mobile --- core/template/mobile/AsusWRT.html | 754 ++++++++++++----------- core/template/mobile/Monitoring.html | 886 +++++++++++++-------------- 2 files changed, 815 insertions(+), 825 deletions(-) diff --git a/core/template/mobile/AsusWRT.html b/core/template/mobile/AsusWRT.html index 9ed29370..1a89e011 100644 --- a/core/template/mobile/AsusWRT.html +++ b/core/template/mobile/AsusWRT.html @@ -70,71 +70,11 @@ - - - - - @@ -145,21 +85,6 @@ -
@@ -171,381 +96,490 @@ #uptime_icon#
-
#load_avg_icon#
-
#memory_icon#
-
#swap_icon#
-
#network_infos_icon#
-
#network_icon#
-
#asus_clients_icon#
-
#asus_wan0_ip_icon#
-
#asus_wifi_temp_icon#
-
#hdd_icon#
- -
- #cpu_icon# - -
- -
- #perso1_icon# - -
- -
- #perso2_icon# - -
- -
- #perso3_icon# - -
- -
- #perso4_icon# - -
- - + } + + // ======================================== + // === INITIALIZATION === + // ======================================== + + // Only initialize if template is properly instantiated + if ('#uid#') { + // Icon handlers + initIconSSH() + initIconCron() + initIconCheckFirmware() + + // Button handlers + initRebootButton() + initRefreshButton() + + // Simple value displays + initUptime() + initNetworkInfos() + initNetwork() + + // AsusWRT-specific displays + initAsusClients() + initAsusWanIP() + initAsusWiFiTemp() + + // Value displays with thresholds + initLoadAverage() + initMemory() + initSwap() + initHDD() + + // CPU with temperature + initCPU() + + // Custom commands - generic initialization using data attributes + document.querySelectorAll('[data-perso-id]').forEach(initPerso) + } + })() + #divGraphInfo# diff --git a/core/template/mobile/Monitoring.html b/core/template/mobile/Monitoring.html index 85f3baf4..edff6266 100644 --- a/core/template/mobile/Monitoring.html +++ b/core/template/mobile/Monitoring.html @@ -70,70 +70,13 @@ - - - - @@ -144,18 +87,6 @@ -
@@ -167,353 +98,416 @@ #uptime_icon#
-
#load_avg_icon#
-
#memory_icon#
-
#swap_icon#
-
#network_infos_icon#
-
#network_icon#
- #multi_network_cards#
#hdd_icon#
- -
- -
- -
- -
- -
- -
- #cpu_icon# - -
- -
- #perso1_icon# - -
- -
- #perso2_icon# - -
- -
- #perso3_icon# - -
- -
- #perso4_icon# - -
- - - #divGraphInfo# + } + + // ======================================== + // === INITIALIZATION === + // ======================================== + + // Only initialize if template is properly instantiated + if ('#uid#') { + // Icon handlers + initIconSSH() + initIconCron() + + // Button handlers + initRebootButton() + initPoweroffButton() + initRefreshButton() + + // Simple value displays + initUptime() + initNetworkInfos() + initNetwork() + + // Value displays with thresholds + initLoadAverage() + initMemory() + initSwap() + initHDD() + + // CPU with temperature + initCPU() + + // Synology volumes - generic initialization using data attributes + document.querySelectorAll('[data-syno-id]').forEach(initSynoVolume) + + // Custom commands - generic initialization using data attributes + document.querySelectorAll('[data-perso-id]').forEach(initPerso) + } + })() + From 17bd3e4324c5ae700620b5a7d02611a6146ec613 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 13:18:01 +0100 Subject: [PATCH 09/84] Update info.json --- plugin_info/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_info/info.json b/plugin_info/info.json index 64de35e7..4aaeb7e4 100644 --- a/plugin_info/info.json +++ b/plugin_info/info.json @@ -1,7 +1,7 @@ { "id": "Monitoring", "name": "Monitoring", - "pluginVersion": "3.3.1", + "pluginVersion": "3.4.0", "description": { "fr_FR": "Plugin permettant le monitoring des équipements locaux et distants (via SSH). Le plugin affichera les informations systèmes d'équipements sous Linux ou Synology (Distribution, CPU, Mémoire, Disques, Swap).", "en_US": "Plugin to monitor local and remote equipments (through SSH). The plugin will display system informations from Linux or Synology (Distribution, CPU, Memory, Disks, Swap).", From eb93b2572b742779afe71dc896e2041bb1f52a41 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:21:27 +0100 Subject: [PATCH 10/84] Update Monitoring.js --- desktop/js/Monitoring.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 0bd8fc67..edf2f124 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -197,8 +197,8 @@ const handleSynologyChange = function() { ) } -const handleQnapChange = function() { - if (this.checked) { +const handleQnapChange = function(event) { + if (event.currentTarget.checked) { const asusCheckbox = document.querySelector(SELECTORS.ASUS_CHECKBOX) const synoCheckbox = document.querySelector(SELECTORS.SYNO_CHECKBOX) const synoConf = document.querySelector(SELECTORS.SYNO_CONF) @@ -211,56 +211,57 @@ const handleQnapChange = function() { } } -const handleAsusChange = function() { +const handleAsusChange = function(event) { updateCheckboxGroup( - this, + event.currentTarget, [document.querySelector(SELECTORS.ASUS_CONF)], [document.querySelector(SELECTORS.SYNO_CONF)], [document.querySelector(SELECTORS.QNAP_CHECKBOX), document.querySelector(SELECTORS.SYNO_CHECKBOX)] ) } -const handleSynoTempPath = function() { +const handleSynoTempPath = function(event) { const tempPath = document.querySelector('.syno_conf_temppath') - if (this.checked) { + if (event.currentTarget.checked) { tempPath?.seen() } else { tempPath?.unseen() } } -const handleLinuxTempCmd = function() { +const handleLinuxTempCmd = function(event) { const tempCmd = document.querySelector('.linux_class_temp_cmd') - if (this.checked) { + if (event.currentTarget.checked) { tempCmd?.seen() } else { tempCmd?.unseen() } } -const handlePullCustom = function() { +const handlePullCustom = function(event) { const pullClass = document.querySelector('.pull_class') - if (this.checked) { + if (event.currentTarget.checked) { pullClass?.seen() } else { pullClass?.unseen() } } -const handleMultiIf = function() { +const handleMultiIf = function(event) { const multiIfConf = document.querySelector('.multi_if_conf') - if (this.checked) { + if (event.currentTarget.checked) { multiIfConf?.seen() } else { multiIfConf?.unseen() } } -const handleLocalDistant = function() { +const handleLocalDistant = function(event) { const distantDiv = document.querySelector('.distant') const localDiv = document.querySelector('.local') + const selectedValue = event.currentTarget.value - if (this.selectedIndex === 1) { + if (selectedValue === 'distant') { distantDiv?.seen() localDiv?.unseen() } else { From bd6b162c6f80de63c3c090d22fab391e92a07da2 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:25:49 +0100 Subject: [PATCH 11/84] Update Monitoring.js --- desktop/js/Monitoring.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index edf2f124..338c9972 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -370,7 +370,7 @@ function printEqLogic(_eqLogic) { elements.localDistant.removeEventListener('change', handleLocalDistant) elements.localDistant.addEventListener('change', handleLocalDistant) // Initialiser l'affichage au chargement - if (elements.localDistant.selectedIndex === 1) { + if (elements.localDistant.value === 'distant') { elements.distantDiv?.seen() elements.localDiv?.unseen() } else { From bfe4ef237291fad01608051394b46cabb7074d5f Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:29:20 +0100 Subject: [PATCH 12/84] Update Monitoring.js --- desktop/js/Monitoring.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 338c9972..44c4ea11 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -180,7 +180,7 @@ const updateCheckboxGroup = (checkbox, showElements = [], hideElements = [], unc if (checkbox.checked) { showElements.forEach(el => el?.seen()) hideElements.forEach(el => el?.unseen()) - uncheckElements.forEach(el => el?.value(0)) + uncheckElements.forEach(el => el?.jeeValue(0)) } else { showElements.forEach(el => el?.unseen()) hideElements.forEach(el => el?.unseen()) @@ -188,9 +188,9 @@ const updateCheckboxGroup = (checkbox, showElements = [], hideElements = [], unc } // Handlers nommés pour pouvoir les remove/add proprement (spécifiques à chaque équipement) -const handleSynologyChange = function() { +const handleSynologyChange = function(event) { updateCheckboxGroup( - this, + event.currentTarget, [document.querySelector(SELECTORS.SYNO_CONF)], [document.querySelector(SELECTORS.ASUS_CONF)], [document.querySelector(SELECTORS.ASUS_CHECKBOX), document.querySelector(SELECTORS.QNAP_CHECKBOX)] @@ -204,8 +204,8 @@ const handleQnapChange = function(event) { const synoConf = document.querySelector(SELECTORS.SYNO_CONF) const asusConf = document.querySelector(SELECTORS.ASUS_CONF) - asusCheckbox?.value(0) - synoCheckbox?.value(0) + asusCheckbox?.jeeValue(0) + synoCheckbox?.jeeValue(0) synoConf?.unseen() asusConf?.unseen() } From 20fba80050c25005e9ded09110951d0abbe62f3f Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:33:40 +0100 Subject: [PATCH 13/84] Update Monitoring.js --- desktop/js/Monitoring.js | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 44c4ea11..af60f182 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -177,13 +177,14 @@ function addCmdToTable(_cmd) { const updateCheckboxGroup = (checkbox, showElements = [], hideElements = [], uncheckElements = []) => { if (!checkbox) return + // hideElements sont toujours masqués (les autres options exclusives) + hideElements.forEach(el => el?.unseen()) + if (checkbox.checked) { showElements.forEach(el => el?.seen()) - hideElements.forEach(el => el?.unseen()) uncheckElements.forEach(el => el?.jeeValue(0)) } else { showElements.forEach(el => el?.unseen()) - hideElements.forEach(el => el?.unseen()) } } @@ -310,6 +311,15 @@ function printEqLogic(_eqLogic) { if (elements.synoCheckbox) { elements.synoCheckbox.removeEventListener('change', handleSynologyChange) elements.synoCheckbox.addEventListener('change', handleSynologyChange) + // Initialiser l'affichage au chargement + if (elements.synoCheckbox.checked) { + elements.synoConf?.seen() + elements.asusConf?.unseen() + elements.asusCheckbox?.jeeValue(0) + elements.qnapCheckbox?.jeeValue(0) + } else { + elements.synoConf?.unseen() + } } if (elements.qnapCheckbox) { @@ -320,6 +330,15 @@ function printEqLogic(_eqLogic) { if (elements.asusCheckbox) { elements.asusCheckbox.removeEventListener('change', handleAsusChange) elements.asusCheckbox.addEventListener('change', handleAsusChange) + // Initialiser l'affichage au chargement + if (elements.asusCheckbox.checked) { + elements.asusConf?.seen() + elements.synoConf?.unseen() + elements.qnapCheckbox?.jeeValue(0) + elements.synoCheckbox?.jeeValue(0) + } else { + elements.asusConf?.unseen() + } } if (elements.synoTempPath) { @@ -379,18 +398,6 @@ function printEqLogic(_eqLogic) { } } - // Initialiser l'affichage des sections Synology/QNAP/Asus au chargement - if (elements.synoCheckbox?.checked) { - elements.synoConf?.seen() - elements.asusConf?.unseen() - } else if (elements.asusCheckbox?.checked) { - elements.asusConf?.seen() - elements.synoConf?.unseen() - } else { - elements.synoConf?.unseen() - elements.asusConf?.unseen() - } - buildSelectHost(_eqLogic.configuration.SSHHostId) } From 8dbefd95b78eb76c95cbfe7acac7e581c1312141 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:35:08 +0100 Subject: [PATCH 14/84] Update Monitoring.js --- desktop/js/Monitoring.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index af60f182..42c74e1e 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -177,14 +177,12 @@ function addCmdToTable(_cmd) { const updateCheckboxGroup = (checkbox, showElements = [], hideElements = [], uncheckElements = []) => { if (!checkbox) return - // hideElements sont toujours masqués (les autres options exclusives) - hideElements.forEach(el => el?.unseen()) - if (checkbox.checked) { showElements.forEach(el => el?.seen()) - uncheckElements.forEach(el => el?.jeeValue(0)) + hideElements.forEach(el => el?.unseen()) // Masquer les blocs des autres options + uncheckElements.forEach(el => el?.jeeValue(0)) // Décocher les autres options } else { - showElements.forEach(el => el?.unseen()) + showElements.forEach(el => el?.unseen()) // Masquer le bloc de cette option } } From 92a6bca58fa0dd59e110a3dda60a7ecf10022195 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 19:44:33 +0100 Subject: [PATCH 15/84] Add Edit SSHHost code --- desktop/js/Monitoring.js | 27 +++++++++++++++++++++++++++ desktop/php/Monitoring.php | 3 +++ 2 files changed, 30 insertions(+) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 42c74e1e..50f626f8 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -397,6 +397,33 @@ function printEqLogic(_eqLogic) { } buildSelectHost(_eqLogic.configuration.SSHHostId) + + // Toggle add/edit button based on SSH host selection + const sshHostSelect = document.querySelector('.sshmanagerHelper[data-helper="list"]') + if (sshHostSelect) { + sshHostSelect.addEventListener('change', toggleSSHButtons) + // Initialize button display + toggleSSHButtons({ currentTarget: sshHostSelect }) + } +} + +/** + * Toggle between add and edit SSH buttons based on selection + */ +function toggleSSHButtons(event) { + const selectedValue = event.currentTarget.value + const addBtn = document.querySelector('.sshmanagerHelper[data-helper="add"]') + const editBtn = document.querySelector('.sshmanagerHelper[data-helper="edit"]') + + if (selectedValue && selectedValue !== '') { + // Host selected → show edit, hide add + addBtn?.unseen() + editBtn?.seen() + } else { + // No host selected → show add, hide edit + addBtn?.seen() + editBtn?.unseen() + } } // Expose functions globally for Jeedom to call them diff --git a/desktop/php/Monitoring.php b/desktop/php/Monitoring.php index 75c985da..a82dc978 100644 --- a/desktop/php/Monitoring.php +++ b/desktop/php/Monitoring.php @@ -224,6 +224,9 @@ +
From 6be60db6c7da83d8d436f21bffa4d0bc24451088 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 20:37:11 +0100 Subject: [PATCH 16/84] Add Health page --- .vscode/settings.json | 1 + core/ajax/Monitoring.ajax.php | 52 ++++++++ desktop/js/Monitoring.js | 29 ++++- desktop/js/health.monitoring.js | 187 ++++++++++++++++++++++++++++ desktop/modal/health.monitoring.php | 66 ++++++++++ desktop/php/Monitoring.php | 5 + 6 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 desktop/js/health.monitoring.js create mode 100644 desktop/modal/health.monitoring.php diff --git a/.vscode/settings.json b/.vscode/settings.json index c3395223..42e45c9e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "cSpell.words": [ "addressip", + "ajax", "armv", "asus", "asuswrt", diff --git a/core/ajax/Monitoring.ajax.php b/core/ajax/Monitoring.ajax.php index 031ee441..e017a30d 100644 --- a/core/ajax/Monitoring.ajax.php +++ b/core/ajax/Monitoring.ajax.php @@ -41,6 +41,58 @@ } } + if (init('action') == 'getHealthData') { + $eqLogics = eqLogic::byType('Monitoring'); + $healthData = array(); + + foreach ($eqLogics as $eqLogic) { + $eqData = array( + 'id' => $eqLogic->getId(), + 'name' => $eqLogic->getName(), + 'isEnable' => $eqLogic->getIsEnable(), + 'isVisible' => $eqLogic->getIsVisible(), + 'type' => $eqLogic->getConfiguration('localoudistant', 'local'), + 'sshHostId' => $eqLogic->getConfiguration('SSHHostId', ''), + 'sshHostName' => '', + 'commands' => array() + ); + + // Get SSH host name if distant + if ($eqData['type'] === 'distant' && $eqData['sshHostId'] !== '') { + $sshHost = eqLogic::byId($eqData['sshHostId']); + if (is_object($sshHost)) { + $eqData['sshHostName'] = $sshHost->getName(); + } + } + + // Get specific commands values + $cmdNames = array( + 'sshStatus' => 'SSH Status', + 'cronStatus' => 'Cron Status', + 'uptime' => 'Uptime', + 'loadAvg1' => 'Charge Système 1 min', + 'ip' => 'Adresse IP' + ); + + foreach ($cmdNames as $key => $cmdName) { + $cmd = $eqLogic->getCmd('info', $cmdName); + if (is_object($cmd)) { + $eqData['commands'][$key] = array( + 'id' => $cmd->getId(), + 'value' => $cmd->execCmd(), + 'unit' => $cmd->getUnite() + ); + } else { + $eqData['commands'][$key] = null; + } + } + + $healthData[] = $eqData; + } + + ajax::success($healthData); + } + throw new Exception(__('Aucune méthode correspondante à : ', __FILE__) . init('action')); /* * *********Catch exeption*************** */ } catch (Exception $e) { diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 50f626f8..18ac65ff 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -15,7 +15,7 @@ */ // Protect against multiple script loads (Jeedom SPA navigation, cache, etc.) -(function() { +(() => { 'use strict' // DOM Selectors constants (better minification + no string repetition + immutable) @@ -426,8 +426,35 @@ function toggleSSHButtons(event) { } } +// Health button click handler +const healthButton = document.querySelector('#bt_healthMonitoring') +if (healthButton) { + healthButton.addEventListener('click', function() { + jeeDialog.dialog({ + id: 'md_healthMonitoring', + title: '{{Santé des équipements Monitoring}}', + width: '95%', + height: '90%', + top: '5vh', + contentUrl: 'index.php?v=d&plugin=Monitoring&modal=health.monitoring', + buttons: { + close: { + label: '{{Fermer}}', + className: 'warning', + callback: { + click: function() { + jeeDialog.get('#md_healthMonitoring').destroy() + } + } + } + } + }) + }) +} + // Expose functions globally for Jeedom to call them window.addCmdToTable = addCmdToTable window.printEqLogic = printEqLogic })() // End of IIFE protection + diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js new file mode 100644 index 00000000..95d511b7 --- /dev/null +++ b/desktop/js/health.monitoring.js @@ -0,0 +1,187 @@ +/* This file is part of Jeedom. + * + * Jeedom is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Jeedom is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jeedom. If not, see . + */ + +(() => { +'use strict' + +// ======================================== +// === SELECTORS === +// ======================================== + +const SELECTORS = { + TABLE_BODY: '#table_healthMonitoring tbody' +} + +// ======================================== +// === CORE FUNCTIONS === +// ======================================== + +/** + * Initialize health monitoring modal + * Called from modal PHP file + */ +const initModalHealthMonitoring = () => { + loadHealthData() +} + +/** + * Load health data from backend + */ +const loadHealthData = () => { + domUtils.ajax({ + type: 'POST', + url: 'plugins/Monitoring/core/ajax/Monitoring.ajax.php', + data: { action: 'getHealthData' }, + dataType: 'json', + error: (error) => { + const tbody = document.querySelector(SELECTORS.TABLE_BODY) + if (tbody) { + tbody.innerHTML = ` ${error.message}` + } + }, + success: (data) => { + displayHealthData(data.result) + } + }) +} + +/** + * Display health data in table + * @param {Array} healthData - Array of equipment health data + */ +const displayHealthData = (healthData) => { + const tbody = document.querySelector(SELECTORS.TABLE_BODY) + if (!tbody) return + + if (!healthData || healthData.length === 0) { + tbody.innerHTML = '{{Aucun équipement trouvé}}' + return + } + + let html = '' + + healthData.forEach(eqLogic => { + const isActive = eqLogic.isEnable === '1' || eqLogic.isEnable === 1 + const isVisible = eqLogic.isVisible === '1' || eqLogic.isVisible === 1 + const isLocal = eqLogic.type === 'local' + + html += '' + + // Nom + html += `${eqLogic.name}` + + // Actif + html += '' + html += isActive ? '' : '' + html += '' + + // Visible + html += '' + html += isVisible ? '' : '' + html += '' + + // Type (Local/Distant) + html += '' + html += isLocal + ? 'Local' + : 'Distant' + html += '' + + // Hôte SSH + html += '' + html += eqLogic.sshHostName || '-' + html += '' + + // SSH Status + html += '' + html += `` + html += formatCmdValue(eqLogic.commands?.sshStatus) + html += '' + html += '' + + // Cron Status + html += '' + html += `` + html += formatCmdValue(eqLogic.commands?.cronStatus) + html += '' + html += '' + + // Uptime + html += '' + html += `` + html += formatCmdValue(eqLogic.commands?.uptime) + html += '' + html += '' + + // Charge système 1 min + html += '' + html += `` + html += formatCmdValue(eqLogic.commands?.loadAvg1) + html += '' + html += '' + + // Adresse IP + html += '' + html += `` + html += formatCmdValue(eqLogic.commands?.ip) + html += '' + html += '' + + html += '' + }) + + tbody.innerHTML = html + + // Initialize Jeedom's automatic command update system for dynamically inserted elements + jeedom.cmd.refreshValue(tbody.querySelectorAll('.cmd[data-cmd_id]')) +} + +// ======================================== +// === HELPER FUNCTIONS === +// ======================================== + +/** + * Format command value for display + * @param {Object} cmdData - Command data object + * @returns {string} Formatted HTML + */ +const formatCmdValue = (cmdData) => { + if (!cmdData || cmdData.value === null || cmdData.value === undefined || cmdData.value === '') { + return '-' + } + + const value = cmdData.value + const unit = cmdData.unit || '' + + // Format special values + if (value === 'OK' || value === 'Running') { + return `${value}` + } else if (value === 'KO' || value === 'Stopped') { + return `${value}` + } + + return `${value}${unit ? ' ' + unit : ''}` +} + +// ======================================== +// === GLOBAL EXPOSURE === +// ======================================== + +// Expose function globally for modal to call +window.initModalHealthMonitoring = initModalHealthMonitoring + +})() // End of IIFE protection + diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php new file mode 100644 index 00000000..6915d299 --- /dev/null +++ b/desktop/modal/health.monitoring.php @@ -0,0 +1,66 @@ +. + */ + +if (!isConnect()) { + throw new Exception('{{401 - Accès non autorisé}}'); +} + +?> + + + +
+ {{Santé des équipements Monitoring}} +
+ +
+ {{Résumé de l'état de santé de tous vos équipements Monitoring}} +
+ + + + + + + + + + + + + + + + + + + + + +
{{Nom}}{{Actif}}{{Visible}}{{Type}}{{Hôte SSH}}{{SSH Status}}{{Cron Status}}{{Uptime}}{{Charge 1min}}{{Adresse IP}}
+ {{Chargement des données...}} +
+
+ + + + diff --git a/desktop/php/Monitoring.php b/desktop/php/Monitoring.php index a82dc978..ea4307cb 100644 --- a/desktop/php/Monitoring.php +++ b/desktop/php/Monitoring.php @@ -51,6 +51,11 @@
{{Configuration}} +
+ +
+ {{Santé}} +

From 2e0853e0d1bbcdae78d93453cf1dc1a5ffc465b2 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:08:29 +0100 Subject: [PATCH 17/84] Update install.php --- plugin_info/install.php | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin_info/install.php b/plugin_info/install.php index 0fe7b36a..6db7146e 100644 --- a/plugin_info/install.php +++ b/plugin_info/install.php @@ -188,7 +188,6 @@ function Monitoring_update() { try { $dirToDelete = array( __DIR__ . '/../ressources', - __DIR__ . '/../desktop/modal', __DIR__ . '/../mobile', __DIR__ . '/../core/img', __DIR__ . '/../resources', From 1b69b9c12ebcbfec6c9adeee2c757c1b885783fb Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:29:01 +0100 Subject: [PATCH 18/84] update health.monitoring.js --- .vscode/settings.json | 1 + core/ajax/Monitoring.ajax.php | 25 ++++---- desktop/js/health.monitoring.js | 105 +++++++++++--------------------- 3 files changed, 48 insertions(+), 83 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 42e45c9e..e6be91e0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -104,6 +104,7 @@ "timeoutssh", "totalsize", "txrx", + "unconfigured", "upnpmodelname", "virt", "wlan", diff --git a/core/ajax/Monitoring.ajax.php b/core/ajax/Monitoring.ajax.php index e017a30d..5a462fd1 100644 --- a/core/ajax/Monitoring.ajax.php +++ b/core/ajax/Monitoring.ajax.php @@ -46,12 +46,13 @@ $healthData = array(); foreach ($eqLogics as $eqLogic) { + $type = $eqLogic->getConfiguration('localoudistant', ''); $eqData = array( 'id' => $eqLogic->getId(), 'name' => $eqLogic->getName(), - 'isEnable' => $eqLogic->getIsEnable(), - 'isVisible' => $eqLogic->getIsVisible(), - 'type' => $eqLogic->getConfiguration('localoudistant', 'local'), + 'isEnable' => (int)$eqLogic->getIsEnable(), + 'isVisible' => (int)$eqLogic->getIsVisible(), + 'type' => $type !== '' ? $type : 'unconfigured', 'sshHostId' => $eqLogic->getConfiguration('SSHHostId', ''), 'sshHostName' => '', 'commands' => array() @@ -65,17 +66,17 @@ } } - // Get specific commands values - $cmdNames = array( - 'sshStatus' => 'SSH Status', - 'cronStatus' => 'Cron Status', - 'uptime' => 'Uptime', - 'loadAvg1' => 'Charge Système 1 min', - 'ip' => 'Adresse IP' + // Get specific commands values by logicalId + $cmdLogicalIds = array( + 'sshStatus' => 'cnx_ssh', + 'cronStatus' => 'cron_status', + 'uptime' => 'uptime', + 'loadAvg1' => 'load_avg_1mn', + 'ip' => 'ip' ); - foreach ($cmdNames as $key => $cmdName) { - $cmd = $eqLogic->getCmd('info', $cmdName); + foreach ($cmdLogicalIds as $key => $logicalId) { + $cmd = $eqLogic->getCmd('info', $logicalId); if (is_object($cmd)) { $eqData['commands'][$key] = array( 'id' => $cmd->getId(), diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 95d511b7..33a7116f 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -71,77 +71,40 @@ const displayHealthData = (healthData) => { return } - let html = '' - - healthData.forEach(eqLogic => { - const isActive = eqLogic.isEnable === '1' || eqLogic.isEnable === 1 - const isVisible = eqLogic.isVisible === '1' || eqLogic.isVisible === 1 - const isLocal = eqLogic.type === 'local' - - html += '' - - // Nom - html += `${eqLogic.name}` - - // Actif - html += '' - html += isActive ? '' : '' - html += '' - - // Visible - html += '' - html += isVisible ? '' : '' - html += '' - - // Type (Local/Distant) - html += '' - html += isLocal - ? 'Local' - : 'Distant' - html += '' - - // Hôte SSH - html += '' - html += eqLogic.sshHostName || '-' - html += '' - - // SSH Status - html += '' - html += `` - html += formatCmdValue(eqLogic.commands?.sshStatus) - html += '' - html += '' - - // Cron Status - html += '' - html += `` - html += formatCmdValue(eqLogic.commands?.cronStatus) - html += '' - html += '' - - // Uptime - html += '' - html += `` - html += formatCmdValue(eqLogic.commands?.uptime) - html += '' - html += '' - - // Charge système 1 min - html += '' - html += `` - html += formatCmdValue(eqLogic.commands?.loadAvg1) - html += '' - html += '' - - // Adresse IP - html += '' - html += `` - html += formatCmdValue(eqLogic.commands?.ip) - html += '' - html += '' - - html += '' - }) + const html = healthData.map(eqLogic => { + const isActive = eqLogic.isEnable === 1 + const isVisible = eqLogic.isVisible === 1 + + let typeLabel = '' + switch (eqLogic.type) { + case 'local': + typeLabel = 'Local' + break + case 'distant': + typeLabel = 'Distant' + break + case 'unconfigured': + typeLabel = '{{Non configuré}}' + break + default: + typeLabel = '-' + } + + return ` + + ${eqLogic.name} + ${isActive ? '' : ''} + ${isVisible ? '' : ''} + ${typeLabel} + ${eqLogic.sshHostName || '-'} + ${formatCmdValue(eqLogic.commands?.sshStatus)} + ${formatCmdValue(eqLogic.commands?.cronStatus)} + ${formatCmdValue(eqLogic.commands?.uptime)} + ${formatCmdValue(eqLogic.commands?.loadAvg1)} + ${formatCmdValue(eqLogic.commands?.ip)} + + ` + }).join('') tbody.innerHTML = html From c1642b4456687a9c11088e35b000cad1560e92fc Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:37:50 +0100 Subject: [PATCH 19/84] update Health page --- core/ajax/Monitoring.ajax.php | 1 + desktop/js/health.monitoring.js | 34 +++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/core/ajax/Monitoring.ajax.php b/core/ajax/Monitoring.ajax.php index 5a462fd1..9675a191 100644 --- a/core/ajax/Monitoring.ajax.php +++ b/core/ajax/Monitoring.ajax.php @@ -70,6 +70,7 @@ $cmdLogicalIds = array( 'sshStatus' => 'cnx_ssh', 'cronStatus' => 'cron_status', + 'cronCustom' => 'cron_status_custom', 'uptime' => 'uptime', 'loadAvg1' => 'load_avg_1mn', 'ip' => 'ip' diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 33a7116f..df12ab2b 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -84,7 +84,7 @@ const displayHealthData = (healthData) => { typeLabel = 'Distant' break case 'unconfigured': - typeLabel = '{{Non configuré}}' + typeLabel = '{{Non configuré}}' break default: typeLabel = '-' @@ -98,7 +98,7 @@ const displayHealthData = (healthData) => { ${typeLabel} ${eqLogic.sshHostName || '-'} ${formatCmdValue(eqLogic.commands?.sshStatus)} - ${formatCmdValue(eqLogic.commands?.cronStatus)} + ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} ${formatCmdValue(eqLogic.commands?.uptime)} ${formatCmdValue(eqLogic.commands?.loadAvg1)} ${formatCmdValue(eqLogic.commands?.ip)} @@ -119,9 +119,12 @@ const displayHealthData = (healthData) => { /** * Format command value for display * @param {Object} cmdData - Command data object + * @param {string} type - Type of command (optional, e.g., 'cron') + * @param {string} eqType - Equipment type (optional, e.g., 'local', 'distant') + * @param {Object} cronCustomData - Cron custom status data (optional) * @returns {string} Formatted HTML */ -const formatCmdValue = (cmdData) => { +const formatCmdValue = (cmdData, type = null, eqType = null, cronCustomData = null) => { if (!cmdData || cmdData.value === null || cmdData.value === undefined || cmdData.value === '') { return '-' } @@ -129,7 +132,30 @@ const formatCmdValue = (cmdData) => { const value = cmdData.value const unit = cmdData.unit || '' - // Format special values + // Special handling for Cron Status + if (type === 'cron') { + const isOn = value === '1' || value === 1 || value === 'Yes' + const isCustom = cronCustomData && (cronCustomData.value === '1' || cronCustomData.value === 1) + + // Custom ON = orange badge with play icon + if (isCustom && isOn) { + return ' ON (Custom)' + } + // Custom OFF = orange badge with pause icon + else if (isCustom && !isOn) { + return ' OFF (Custom)' + } + // Default ON = green badge with play icon + else if (isOn) { + return ' ON' + } + // Default OFF = red badge with pause icon + else { + return ' OFF' + } + } + + // Format other special values if (value === 'OK' || value === 'Running') { return `${value}` } else if (value === 'KO' || value === 'Stopped') { From 33b3688722b7a52e64a82ad7e311bd9c634301da Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:40:40 +0100 Subject: [PATCH 20/84] Update health.monitoring.js --- desktop/js/health.monitoring.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index df12ab2b..17df4ce2 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -97,7 +97,7 @@ const displayHealthData = (healthData) => { ${isVisible ? '' : ''} ${typeLabel} ${eqLogic.sshHostName || '-'} - ${formatCmdValue(eqLogic.commands?.sshStatus)} + ${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')} ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} ${formatCmdValue(eqLogic.commands?.uptime)} ${formatCmdValue(eqLogic.commands?.loadAvg1)} @@ -132,6 +132,17 @@ const formatCmdValue = (cmdData, type = null, eqType = null, cronCustomData = nu const value = cmdData.value const unit = cmdData.unit || '' + // Special handling for SSH Status + if (type === 'ssh') { + if (value === 'OK') { + return ' OK' + } else if (value === 'KO') { + return ' KO' + } else if (value === 'No') { + return '-' + } + } + // Special handling for Cron Status if (type === 'cron') { const isOn = value === '1' || value === 1 || value === 'Yes' From 69669f6934dc6caaff4bc580a4930c16381192f7 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:41:55 +0100 Subject: [PATCH 21/84] Update Monitoring.ajax.php --- core/ajax/Monitoring.ajax.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ajax/Monitoring.ajax.php b/core/ajax/Monitoring.ajax.php index 9675a191..0025bbaf 100644 --- a/core/ajax/Monitoring.ajax.php +++ b/core/ajax/Monitoring.ajax.php @@ -73,7 +73,7 @@ 'cronCustom' => 'cron_status_custom', 'uptime' => 'uptime', 'loadAvg1' => 'load_avg_1mn', - 'ip' => 'ip' + 'ip' => 'network_ip' ); foreach ($cmdLogicalIds as $key => $logicalId) { From e8d8846b543c1465a414b4c0218f253aa81fcc46 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:58:47 +0100 Subject: [PATCH 22/84] update Health page --- core/ajax/Monitoring.ajax.php | 13 ++- desktop/js/health.monitoring.js | 122 ++++++++++++++++++++++++++-- desktop/modal/health.monitoring.php | 4 +- 3 files changed, 129 insertions(+), 10 deletions(-) diff --git a/core/ajax/Monitoring.ajax.php b/core/ajax/Monitoring.ajax.php index 0025bbaf..f5cbfa65 100644 --- a/core/ajax/Monitoring.ajax.php +++ b/core/ajax/Monitoring.ajax.php @@ -47,6 +47,14 @@ foreach ($eqLogics as $eqLogic) { $type = $eqLogic->getConfiguration('localoudistant', ''); + + // Get last refresh from uptime command collectDate + $uptimeCmd = $eqLogic->getCmd('info', 'uptime'); + $lastUptime = null; + if (is_object($uptimeCmd)) { + $lastUptime = $uptimeCmd->getCollectDate(); + } + $eqData = array( 'id' => $eqLogic->getId(), 'name' => $eqLogic->getName(), @@ -55,6 +63,7 @@ 'type' => $type !== '' ? $type : 'unconfigured', 'sshHostId' => $eqLogic->getConfiguration('SSHHostId', ''), 'sshHostName' => '', + 'lastRefresh' => $lastUptime, 'commands' => array() ); @@ -82,7 +91,9 @@ $eqData['commands'][$key] = array( 'id' => $cmd->getId(), 'value' => $cmd->execCmd(), - 'unit' => $cmd->getUnite() + 'unit' => $cmd->getUnite(), + 'collectDate' => $cmd->getCollectDate(), + 'valueDate' => $cmd->getValueDate() ); } else { $eqData['commands'][$key] = null; diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 17df4ce2..37a2c7b2 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -49,7 +49,7 @@ const loadHealthData = () => { error: (error) => { const tbody = document.querySelector(SELECTORS.TABLE_BODY) if (tbody) { - tbody.innerHTML = ` ${error.message}` + tbody.innerHTML = ` ${error.message}` } }, success: (data) => { @@ -67,7 +67,7 @@ const displayHealthData = (healthData) => { if (!tbody) return if (!healthData || healthData.length === 0) { - tbody.innerHTML = '{{Aucun équipement trouvé}}' + tbody.innerHTML = '{{Aucun équipement trouvé}}' return } @@ -97,11 +97,13 @@ const displayHealthData = (healthData) => { ${isVisible ? '' : ''} ${typeLabel} ${eqLogic.sshHostName || '-'} - ${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')} - ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} - ${formatCmdValue(eqLogic.commands?.uptime)} - ${formatCmdValue(eqLogic.commands?.loadAvg1)} - ${formatCmdValue(eqLogic.commands?.ip)} + ${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')} + ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} + ${formatCmdValue(eqLogic.commands?.uptime)} + ${formatCmdValue(eqLogic.commands?.loadAvg1)} + ${formatCmdValue(eqLogic.commands?.ip)} + ${formatDate(eqLogic.lastRefresh)} + ${getLastValueDate(eqLogic.commands)} ` }).join('') @@ -109,13 +111,43 @@ const displayHealthData = (healthData) => { tbody.innerHTML = html // Initialize Jeedom's automatic command update system for dynamically inserted elements - jeedom.cmd.refreshValue(tbody.querySelectorAll('.cmd[data-cmd_id]')) + const cmdElements = tbody.querySelectorAll('.cmd[data-cmd_id]') + if (cmdElements.length > 0) { + jeedom.cmd.refreshValue(cmdElements) + + // Register update listeners for real-time updates via WebSocket + cmdElements.forEach(element => { + const cmdId = element.getAttribute('data-cmd_id') + if (cmdId && cmdId !== '') { + jeedom.cmd.update[cmdId] = function(event) { + element.textContent = event.display_value || event.value || '-' + } + } + }) + } } // ======================================== // === HELPER FUNCTIONS === // ======================================== +/** + * Format tooltip with command dates + * @param {string} label - Label for the command + * @param {Object} cmdData - Command data object + * @returns {string} Formatted tooltip text + */ +const formatTooltip = (label, cmdData) => { + if (!cmdData) { + return label + } + + const valueDate = cmdData.valueDate || '-' + const collectDate = cmdData.collectDate || '-' + + return `${label}\nDate de valeur : ${valueDate}\nDate de collecte : ${collectDate}` +} + /** * Format command value for display * @param {Object} cmdData - Command data object @@ -176,6 +208,80 @@ const formatCmdValue = (cmdData, type = null, eqType = null, cronCustomData = nu return `${value}${unit ? ' ' + unit : ''}` } +/** + * Format date for display + * @param {string} dateStr - Date string to format + * @returns {string} Formatted date or dash if invalid + */ +const formatDate = (dateStr) => { + if (!dateStr || dateStr === '' || dateStr === '0000-00-00 00:00:00') { + return '-' + } + + try { + const date = new Date(dateStr) + if (isNaN(date.getTime())) { + return '-' + } + + const now = new Date() + const diffMs = now - date + const diffMins = Math.floor(diffMs / 60000) + + // Less than 1 minute + if (diffMins < 1) { + return '{{À l\'instant}}' + } + // Less than 60 minutes + else if (diffMins < 60) { + return `{{Il y a}} ${diffMins} {{min}}` + } + // Less than 24 hours + else if (diffMins < 1440) { + const hours = Math.floor(diffMins / 60) + return `{{Il y a}} ${hours} {{h}}` + } + // More than 24 hours + else { + const days = Math.floor(diffMins / 1440) + return `{{Il y a}} ${days} {{j}}` + } + } catch (e) { + return '-' + } +} + +/** + * Get the most recent valueDate from all commands + * @param {Object} commands - Commands object + * @returns {string} Formatted most recent date + */ +const getLastValueDate = (commands) => { + if (!commands) { + return '-' + } + + let mostRecentDate = null + + // Check all commands for the most recent valueDate + Object.values(commands).forEach(cmd => { + if (cmd && cmd.valueDate && cmd.valueDate !== '' && cmd.valueDate !== '0000-00-00 00:00:00') { + const cmdDate = new Date(cmd.valueDate) + if (!isNaN(cmdDate.getTime())) { + if (!mostRecentDate || cmdDate > mostRecentDate) { + mostRecentDate = cmdDate + } + } + } + }) + + if (!mostRecentDate) { + return '-' + } + + return formatDate(mostRecentDate.toISOString().slice(0, 19).replace('T', ' ')) +} + // ======================================== // === GLOBAL EXPOSURE === // ======================================== diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index 6915d299..6255f0f5 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -45,11 +45,13 @@ {{Uptime}} {{Charge 1min}} {{Adresse IP}} + {{Dernière Communication}} + {{Dernière Valeur}} - + {{Chargement des données...}} From ca3f403461f9ab050bb9a1aedbc707454eb532ad Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:08:42 +0100 Subject: [PATCH 23/84] Update health.monitoring.js --- desktop/js/health.monitoring.js | 61 +++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 37a2c7b2..30e348e2 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -97,13 +97,13 @@ const displayHealthData = (healthData) => { ${isVisible ? '' : ''} ${typeLabel} ${eqLogic.sshHostName || '-'} - ${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')} - ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} + ${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')} + ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} ${formatCmdValue(eqLogic.commands?.uptime)} ${formatCmdValue(eqLogic.commands?.loadAvg1)} ${formatCmdValue(eqLogic.commands?.ip)} - ${formatDate(eqLogic.lastRefresh)} - ${getLastValueDate(eqLogic.commands)} + ${formatDate(eqLogic.lastRefresh, eqLogic.type)} + ${getLastValueDate(eqLogic.commands, eqLogic.type)} ` }).join('') @@ -120,7 +120,21 @@ const displayHealthData = (healthData) => { const cmdId = element.getAttribute('data-cmd_id') if (cmdId && cmdId !== '') { jeedom.cmd.update[cmdId] = function(event) { - element.textContent = event.display_value || event.value || '-' + const cmdType = element.getAttribute('data-cmd-type') + const value = event.display_value || event.value + + // Format value based on command type + if (cmdType === 'ssh') { + element.innerHTML = formatCmdValue({ value: value }, 'ssh') + } else if (cmdType === 'cron') { + const eqType = element.getAttribute('data-eq-type') + const cronCustomValue = element.getAttribute('data-cron-custom') + const cronCustomData = cronCustomValue ? { value: cronCustomValue } : null + element.innerHTML = formatCmdValue({ value: value }, 'cron', eqType, cronCustomData) + } else { + // Standard display for other commands + element.innerHTML = formatCmdValue({ value: value }) + } } } }) @@ -211,9 +225,10 @@ const formatCmdValue = (cmdData, type = null, eqType = null, cronCustomData = nu /** * Format date for display * @param {string} dateStr - Date string to format + * @param {string} eqType - Equipment type ('local' or 'distant') * @returns {string} Formatted date or dash if invalid */ -const formatDate = (dateStr) => { +const formatDate = (dateStr, eqType = null) => { if (!dateStr || dateStr === '' || dateStr === '0000-00-00 00:00:00') { return '-' } @@ -228,23 +243,18 @@ const formatDate = (dateStr) => { const diffMs = now - date const diffMins = Math.floor(diffMs / 60000) - // Less than 1 minute - if (diffMins < 1) { - return '{{À l\'instant}}' - } - // Less than 60 minutes - else if (diffMins < 60) { - return `{{Il y a}} ${diffMins} {{min}}` - } - // Less than 24 hours - else if (diffMins < 1440) { - const hours = Math.floor(diffMins / 60) - return `{{Il y a}} ${hours} {{h}}` - } - // More than 24 hours - else { - const days = Math.floor(diffMins / 1440) - return `{{Il y a}} ${days} {{j}}` + // Color based on age and equipment type + const formattedDate = dateStr.slice(0, 19).replace('T', ' ') + + // Green threshold varies: local <= 5min, distant <= 15min + const greenThreshold = (eqType === 'local') ? 5 : 15 + + if (diffMins <= greenThreshold) { + return `${formattedDate}` + } else if (diffMins <= 30) { + return `${formattedDate}` + } else { + return `${formattedDate}` } } catch (e) { return '-' @@ -254,9 +264,10 @@ const formatDate = (dateStr) => { /** * Get the most recent valueDate from all commands * @param {Object} commands - Commands object + * @param {string} eqType - Equipment type ('local' or 'distant') * @returns {string} Formatted most recent date */ -const getLastValueDate = (commands) => { +const getLastValueDate = (commands, eqType = null) => { if (!commands) { return '-' } @@ -279,7 +290,7 @@ const getLastValueDate = (commands) => { return '-' } - return formatDate(mostRecentDate.toISOString().slice(0, 19).replace('T', ' ')) + return formatDate(mostRecentDate.toISOString().slice(0, 19).replace('T', ' '), eqType) } // ======================================== From afe2f3c314690ef59eeae0a3c4056a88b8b0289e Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:14:02 +0100 Subject: [PATCH 24/84] update Health page --- core/ajax/Monitoring.ajax.php | 2 ++ desktop/js/health.monitoring.js | 6 ++++-- desktop/modal/health.monitoring.php | 28 +++++++++++++++------------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/core/ajax/Monitoring.ajax.php b/core/ajax/Monitoring.ajax.php index f5cbfa65..61c43ba8 100644 --- a/core/ajax/Monitoring.ajax.php +++ b/core/ajax/Monitoring.ajax.php @@ -82,6 +82,8 @@ 'cronCustom' => 'cron_status_custom', 'uptime' => 'uptime', 'loadAvg1' => 'load_avg_1mn', + 'loadAvg5' => 'load_avg_5mn', + 'loadAvg15' => 'load_avg_15mn', 'ip' => 'network_ip' ); diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 30e348e2..af6b6b23 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -49,7 +49,7 @@ const loadHealthData = () => { error: (error) => { const tbody = document.querySelector(SELECTORS.TABLE_BODY) if (tbody) { - tbody.innerHTML = ` ${error.message}` + tbody.innerHTML = ` ${error.message}` } }, success: (data) => { @@ -67,7 +67,7 @@ const displayHealthData = (healthData) => { if (!tbody) return if (!healthData || healthData.length === 0) { - tbody.innerHTML = '{{Aucun équipement trouvé}}' + tbody.innerHTML = '{{Aucun équipement trouvé}}' return } @@ -101,6 +101,8 @@ const displayHealthData = (healthData) => { ${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} ${formatCmdValue(eqLogic.commands?.uptime)} ${formatCmdValue(eqLogic.commands?.loadAvg1)} + ${formatCmdValue(eqLogic.commands?.loadAvg5)} + ${formatCmdValue(eqLogic.commands?.loadAvg15)} ${formatCmdValue(eqLogic.commands?.ip)} ${formatDate(eqLogic.lastRefresh, eqLogic.type)} ${getLastValueDate(eqLogic.commands, eqLogic.type)} diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index 6255f0f5..f4c65048 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -35,23 +35,25 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + - From a4477ee7df74ebcb2d49a41fe0cd9f4fc07c41da Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:37:43 +0100 Subject: [PATCH 25/84] update Health page --- desktop/js/health.monitoring.js | 40 +++++------------------------ desktop/modal/health.monitoring.php | 3 +-- 2 files changed, 7 insertions(+), 36 deletions(-) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index af6b6b23..f75f31e1 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -105,13 +105,17 @@ const displayHealthData = (healthData) => { - ` }).join('') tbody.innerHTML = html + // Initialize Bootstrap tooltips for dynamically inserted elements + document.querySelectorAll('#table_healthMonitoring .tooltips').forEach(element => { + new bootstrap.Tooltip(element, { html: true }) + }) + // Initialize Jeedom's automatic command update system for dynamically inserted elements const cmdElements = tbody.querySelectorAll('.cmd[data-cmd_id]') if (cmdElements.length > 0) { @@ -161,7 +165,7 @@ const formatTooltip = (label, cmdData) => { const valueDate = cmdData.valueDate || '-' const collectDate = cmdData.collectDate || '-' - return `${label}\nDate de valeur : ${valueDate}\nDate de collecte : ${collectDate}` + return `${label}
Date de valeur : ${valueDate}
Date de collecte : ${collectDate}
` } /** @@ -263,38 +267,6 @@ const formatDate = (dateStr, eqType = null) => { } } -/** - * Get the most recent valueDate from all commands - * @param {Object} commands - Commands object - * @param {string} eqType - Equipment type ('local' or 'distant') - * @returns {string} Formatted most recent date - */ -const getLastValueDate = (commands, eqType = null) => { - if (!commands) { - return '-' - } - - let mostRecentDate = null - - // Check all commands for the most recent valueDate - Object.values(commands).forEach(cmd => { - if (cmd && cmd.valueDate && cmd.valueDate !== '' && cmd.valueDate !== '0000-00-00 00:00:00') { - const cmdDate = new Date(cmd.valueDate) - if (!isNaN(cmdDate.getTime())) { - if (!mostRecentDate || cmdDate > mostRecentDate) { - mostRecentDate = cmdDate - } - } - } - }) - - if (!mostRecentDate) { - return '-' - } - - return formatDate(mostRecentDate.toISOString().slice(0, 19).replace('T', ' '), eqType) -} - // ======================================== // === GLOBAL EXPOSURE === // ======================================== diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index f4c65048..9f20eb7e 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -48,12 +48,11 @@ - - From 3a50f9d3513e728cbb69eedf03c7a36fad2a847e Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:39:25 +0100 Subject: [PATCH 26/84] Update health.monitoring.js --- desktop/js/health.monitoring.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index f75f31e1..25a751d2 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -111,11 +111,6 @@ const displayHealthData = (healthData) => { tbody.innerHTML = html - // Initialize Bootstrap tooltips for dynamically inserted elements - document.querySelectorAll('#table_healthMonitoring .tooltips').forEach(element => { - new bootstrap.Tooltip(element, { html: true }) - }) - // Initialize Jeedom's automatic command update system for dynamically inserted elements const cmdElements = tbody.querySelectorAll('.cmd[data-cmd_id]') if (cmdElements.length > 0) { From 9979798629113e857054c4b44c2bee614d97d198 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:40:56 +0100 Subject: [PATCH 27/84] Update health.monitoring.js --- desktop/js/health.monitoring.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 25a751d2..0645a08c 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -111,6 +111,9 @@ const displayHealthData = (healthData) => { tbody.innerHTML = html + // Initialize Jeedom tooltips with HTML support + initTooltips() + // Initialize Jeedom's automatic command update system for dynamically inserted elements const cmdElements = tbody.querySelectorAll('.cmd[data-cmd_id]') if (cmdElements.length > 0) { From ce3fe35bfd7d25567271cbe7df4aabad3470c72a Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 23:15:16 +0100 Subject: [PATCH 28/84] Update health.monitoring.php --- desktop/modal/health.monitoring.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index 9f20eb7e..0e2a2c21 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -40,8 +40,8 @@ - - + + From 76d435ca92cbbe9589cfe461c4a251d911d89279 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 23:16:48 +0100 Subject: [PATCH 29/84] Update health.monitoring.js --- desktop/js/health.monitoring.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 0645a08c..99fdb6af 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -97,8 +97,8 @@ const displayHealthData = (healthData) => { - - + + From 0558aad64eea96402e40836ac7dab55a3527b3d4 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 23:22:16 +0100 Subject: [PATCH 30/84] update Health page --- desktop/js/health.monitoring.js | 6 ++++++ desktop/modal/health.monitoring.php | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index 99fdb6af..63ee5ab7 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -139,6 +139,12 @@ const displayHealthData = (healthData) => { // Standard display for other commands element.innerHTML = formatCmdValue({ value: value }) } + + // Add visual feedback for update + element.classList.remove('cmd-updated') + // Force reflow to restart animation + void element.offsetWidth + element.classList.add('cmd-updated') } } }) diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index 0e2a2c21..aea8e872 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -22,6 +22,17 @@ ?> + +
From 118175b9e4236af80120ec52c94f73942861a2e5 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 23:24:36 +0100 Subject: [PATCH 31/84] Update health.monitoring.php --- desktop/modal/health.monitoring.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index aea8e872..b734c2af 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -31,6 +31,11 @@ .cmd-updated { animation: healthCmdUpdate 2s ease-out; } + +#table_healthMonitoring .cmd { + font-family: inherit; + font-size: inherit; +} From 61526748eed3792cca246f22ec3915c918adb09c Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Fri, 2 Jan 2026 23:26:03 +0100 Subject: [PATCH 32/84] Update health.monitoring.php --- desktop/modal/health.monitoring.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktop/modal/health.monitoring.php b/desktop/modal/health.monitoring.php index b734c2af..ba69295b 100644 --- a/desktop/modal/health.monitoring.php +++ b/desktop/modal/health.monitoring.php @@ -24,12 +24,12 @@ -
+
{{Résumé de l'état de santé de tous vos équipements Monitoring}}
-
- +
+
+ + + + +
+
{{Nom}}{{Actif}}{{Visible}}{{Type}}{{Hôte SSH}}{{SSH Status}}{{Cron Status}}{{Uptime}}{{Charge 1min}}{{Adresse IP}}{{Dernière Communication}}{{Dernière Valeur}}{{Nom}}{{Actif}}{{Visible}}{{Type}}{{Hôte SSH}}{{SSH Status}}{{Cron Status}}{{Uptime}}{{Charge 1min}}{{Charge 5min}}{{Charge 15min}}{{Adresse IP}}{{Dernière Communication}}{{Dernière Valeur}}
+ {{Chargement des données...}}
${formatCmdValue(eqLogic.commands?.loadAvg15)} ${formatCmdValue(eqLogic.commands?.ip)} ${formatDate(eqLogic.lastRefresh, eqLogic.type)}${getLastValueDate(eqLogic.commands, eqLogic.type)}
{{Charge 15min}} {{Adresse IP}} {{Dernière Communication}}{{Dernière Valeur}}
+ {{Chargement des données...}}
{{Visible}} {{Type}} {{Hôte SSH}}{{SSH Status}}{{Cron Status}}{{SSH Status}}{{Cron Status}} {{Uptime}} {{Charge 1min}} {{Charge 5min}}${isVisible ? '' : ''} ${typeLabel} ${eqLogic.sshHostName || '-'}${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')}${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)}${formatCmdValue(eqLogic.commands?.sshStatus, 'ssh')}${formatCmdValue(eqLogic.commands?.cronStatus, 'cron', eqLogic.type, eqLogic.commands?.cronCustom)} ${formatCmdValue(eqLogic.commands?.uptime)} ${formatCmdValue(eqLogic.commands?.loadAvg1)} ${formatCmdValue(eqLogic.commands?.loadAvg5)}
- + - + - + - - + + diff --git a/plugin_info/info.json b/plugin_info/info.json index 4aaeb7e4..cea69b69 100644 --- a/plugin_info/info.json +++ b/plugin_info/info.json @@ -1,7 +1,7 @@ { "id": "Monitoring", "name": "Monitoring", - "pluginVersion": "3.4.0", + "pluginVersion": "3.4.1", "description": { "fr_FR": "Plugin permettant le monitoring des équipements locaux et distants (via SSH). Le plugin affichera les informations systèmes d'équipements sous Linux ou Synology (Distribution, CPU, Mémoire, Disques, Swap).", "en_US": "Plugin to monitor local and remote equipments (through SSH). The plugin will display system informations from Linux or Synology (Distribution, CPU, Memory, Disks, Swap).", From e3b789932d4ea9c3a1e5b27ee3c41d5a0a821ce1 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Sat, 3 Jan 2026 14:51:42 +0100 Subject: [PATCH 48/84] Update Monitoring.js --- desktop/js/Monitoring.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index bf74d9de..c8f257d9 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -437,6 +437,18 @@ if (healthButton) { height: '90%', top: '5vh', contentUrl: 'index.php?v=d&plugin=Monitoring&modal=health.monitoring', + defaultButtons: {}, + buttons: { + close: { + label: ' {{Fermer}}', + className: 'success', + callback: { + click: function(event) { + event.target.closest('div.jeeDialog')._jeeDialog.close() + } + } + } + }, callback: function() { if (typeof initModalHealthMonitoring === 'function') { initModalHealthMonitoring() From bfd4aa635f930c6dc846233892230840bbbef0d0 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Sat, 3 Jan 2026 14:54:02 +0100 Subject: [PATCH 49/84] cleanup resources on modal close --- desktop/js/Monitoring.js | 6 ++++++ desktop/js/health.monitoring.js | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index c8f257d9..88b4f41b 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -453,6 +453,12 @@ if (healthButton) { if (typeof initModalHealthMonitoring === 'function') { initModalHealthMonitoring() } + }, + onClose: function() { + // Clean up resources when modal is closed + if (typeof cleanupHealthMonitoring === 'function') { + cleanupHealthMonitoring() + } } }) }) diff --git a/desktop/js/health.monitoring.js b/desktop/js/health.monitoring.js index d0ac1c02..125b6d83 100644 --- a/desktop/js/health.monitoring.js +++ b/desktop/js/health.monitoring.js @@ -40,6 +40,22 @@ const initModalHealthMonitoring = () => { loadHealthData() } +/** + * Clean up resources when modal is closed + * Removes event listeners to prevent memory leaks + */ +const cleanupHealthMonitoring = () => { + // Remove WebSocket event listener + if (healthCmdUpdateHandler) { + document.body.removeEventListener('cmd::update', healthCmdUpdateHandler) + healthCmdUpdateHandler = null + } + + // Clear search input event listeners (handled by DOM removal) + // Clear button event listeners (handled by DOM removal) + // Table elements are automatically cleaned when modal DOM is removed +} + /** * Load health data from backend */ @@ -452,8 +468,9 @@ const formatDate = (dateStr, eqType = null) => { // === GLOBAL EXPOSURE === // ======================================== -// Expose function globally for modal to call +// Expose functions globally for modal to call window.initModalHealthMonitoring = initModalHealthMonitoring +window.cleanupHealthMonitoring = cleanupHealthMonitoring })() // End of IIFE protection From b3f024ea63b1da333b41db069116c353be9a5f00 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:09:51 +0100 Subject: [PATCH 50/84] update cspell config --- .gitignore | 2 +- .vscode/cspell.json | 115 ++++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 119 +++--------------------------------------- 3 files changed, 124 insertions(+), 112 deletions(-) create mode 100644 .vscode/cspell.json diff --git a/.gitignore b/.gitignore index be7f335c..d11a94b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # IDE & Editors .vscode/* -!.vscode/settings.json !.vscode/extensions.json +!.vscode/cspell.json # OS Generated Files # Windows diff --git a/.vscode/cspell.json b/.vscode/cspell.json new file mode 100644 index 00000000..00eadc69 --- /dev/null +++ b/.vscode/cspell.json @@ -0,0 +1,115 @@ +{ + "version": "0.2", + "words": [ + "addressip", + "ajax", + "armv", + "asus", + "asuswrt", + "boottime", + "buffcache", + "buildno", + "buildnumber", + "CACHEDEV", + "cartereseau", + "cartereseauautre", + "cartesreseau", + "clientlist", + "colorhigh", + "colorlow", + "commandtab", + "coretemp", + "cpufreq", + "Cubie", + "dataresult", + "debian", + "dependancy", + "depinstall", + "deporte", + "distri", + "dnsmasq", + "ehthumbs", + "ELEC", + "Eqlogic", + "eqlogictab", + "equipement", + "Equipement", + "esata", + "Etat", + "firmver", + "Formated", + "freebsd", + "getcfg", + "getconf", + "getconfiguration", + "getsysinfo", + "gsub", + "hddesata", + "hddusb", + "hddv", + "Historized", + "htmlstate", + "hwmon", + "iface", + "ifname", + "ifnames", + "isset", + "jffs", + "loadavg", + "Localor", + "localorremote", + "localoudistant", + "maitreesclave", + "medion", + "mips", + "mmcblk", + "Monitoringcli", + "Namedashboard", + "Namemobile", + "ncpu", + "netauto", + "netautre", + "nvram", + "Odroid", + "paramaction", + "PCPVERS", + "pcpversion", + "phpunit", + "physmem", + "portssh", + "POSTSAVE", + "poweroffcmd", + "productid", + "productversion", + "PULLCUSTOM", + "PULLLOCAL", + "Rafraichir", + "realip", + "rebootcmd", + "RXTX", + "Ryzen", + "smallfixnumber", + "SSHM", + "sshmanager", + "sunxi", + "swapinfo", + "syno", + "synoinfo", + "synologyesata", + "synologyusb", + "synologyv", + "temppath", + "tempsense", + "Thresholdd", + "timeoutsrv", + "timeoutssh", + "totalsize", + "txrx", + "unconfigured", + "upnpmodelname", + "virt", + "wlan", + "Wyse" + ], + "ignoreWords": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index e6be91e0..b096e57e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,113 +1,10 @@ { - "cSpell.words": [ - "addressip", - "ajax", - "armv", - "asus", - "asuswrt", - "boottime", - "buffcache", - "buildno", - "buildnumber", - "CACHEDEV", - "cartereseau", - "cartereseauautre", - "cartesreseau", - "clientlist", - "colorhigh", - "colorlow", - "commandtab", - "coretemp", - "cpufreq", - "Cubie", - "dataresult", - "debian", - "dependancy", - "depinstall", - "deporte", - "distri", - "dnsmasq", - "ehthumbs", - "ELEC", - "Eqlogic", - "eqlogictab", - "equipement", - "Equipement", - "esata", - "Etat", - "firmver", - "Formated", - "freebsd", - "getcfg", - "getconf", - "getconfiguration", - "getsysinfo", - "gsub", - "hddesata", - "hddusb", - "hddv", - "Historized", - "htmlstate", - "hwmon", - "iface", - "ifname", - "ifnames", - "isset", - "jffs", - "loadavg", - "Localor", - "localorremote", - "localoudistant", - "maitreesclave", - "medion", - "mips", - "mmcblk", - "Monitoringcli", - "Namedashboard", - "Namemobile", - "ncpu", - "netauto", - "netautre", - "nvram", - "Odroid", - "paramaction", - "PCPVERS", - "pcpversion", - "phpunit", - "physmem", - "portssh", - "POSTSAVE", - "poweroffcmd", - "productid", - "productversion", - "PULLCUSTOM", - "PULLLOCAL", - "Rafraichir", - "realip", - "rebootcmd", - "RXTX", - "Ryzen", - "smallfixnumber", - "SSHM", - "sshmanager", - "sunxi", - "swapinfo", - "syno", - "synoinfo", - "synologyesata", - "synologyusb", - "synologyv", - "temppath", - "tempsense", - "Thresholdd", - "timeoutsrv", - "timeoutssh", - "totalsize", - "txrx", - "unconfigured", - "upnpmodelname", - "virt", - "wlan", - "Wyse" - ] + "cSpell.customDictionaries": { + "project-words": { + "name": "project-words", + "path": "${workspaceRoot}/.vscode/cspell.json", + "addWords": true, + "scope": "folder" + } + } } \ No newline at end of file From 92fa626ce9b8f804f98fc77b8790960bd3c39a45 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:22:47 +0100 Subject: [PATCH 51/84] update gitignore --- .gitignore | 1 + .vscode/settings.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d11a94b1..a22002a0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .vscode/* !.vscode/extensions.json !.vscode/cspell.json +!.vscode/settings.json # OS Generated Files # Windows diff --git a/.vscode/settings.json b/.vscode/settings.json index b096e57e..9366614d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,7 @@ "cSpell.customDictionaries": { "project-words": { "name": "project-words", - "path": "${workspaceRoot}/.vscode/cspell.json", + "path": "${workspaceFolder}/.vscode/cspell.json", "addWords": true, "scope": "folder" } From 45974ae2a13feefe0d70b30dedd782f09f439212 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:29:19 +0100 Subject: [PATCH 52/84] Update settings.json --- .vscode/settings.json | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9366614d..9e26dfee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1 @@ -{ - "cSpell.customDictionaries": { - "project-words": { - "name": "project-words", - "path": "${workspaceFolder}/.vscode/cspell.json", - "addWords": true, - "scope": "folder" - } - } -} \ No newline at end of file +{} \ No newline at end of file From 4cfeeb5a965bf3726af6bd82acc82d6e8d37e5dc Mon Sep 17 00:00:00 2001 From: TiTidom-RC <16240457+TiTidom-RC@users.noreply.github.com> Date: Sat, 3 Jan 2026 14:46:08 +0000 Subject: [PATCH 53/84] Auto update translation done by Mips2648/plugins-translations workflow --- core/i18n/de_DE.json | 36 +++++++++++++++++++++++++++++++++++- core/i18n/en_US.json | 36 +++++++++++++++++++++++++++++++++++- core/i18n/es_ES.json | 36 +++++++++++++++++++++++++++++++++++- core/i18n/it_IT.json | 36 +++++++++++++++++++++++++++++++++++- core/i18n/pt_PT.json | 36 +++++++++++++++++++++++++++++++++++- 5 files changed, 175 insertions(+), 5 deletions(-) diff --git a/core/i18n/de_DE.json b/core/i18n/de_DE.json index 40b84403..9126fed0 100644 --- a/core/i18n/de_DE.json +++ b/core/i18n/de_DE.json @@ -132,15 +132,47 @@ "Aucune": "Keine", "Choisir une icône": "Symbol auswählen", "Commande info liée": "Verwandte Info-Befehle", + "Fermer": "Schließen", "Historiser": "Historisieren", "Nom de la commande": "Name des Befehls", "Orange": "Orange", "Rouge": "Rot", + "Santé des équipements Monitoring": "Gesundheit der Anlagen Überwachung", "Supprimer la commande": "Befehl löschen", "Tester": "Testen", "Unité": "Einheit", "Vert": "Grün" }, + "plugins\/Monitoring\/desktop\/js\/health.monitoring.js": { + "Aucun équipement trouvé": "Keine Geräte gefunden", + "Non configuré": "Nicht konfiguriert" + }, + "plugins\/Monitoring\/desktop\/modal\/health.monitoring.php": { + "401 - Accès non autorisé": "401 - Unberechtigter Zugriff", + "Actif": "Aktiv", + "Adresse IP": "IP-Adresse", + "Autres termes : recherche par nom, IP, charge, etc.": "Weitere Begriffe: Suche nach Name, IP, Last usw.", + "Charge 15min": "Ladezeit 15 Min.", + "Charge 1min": "Ladezeit 1 Min.", + "Charge 5min": "Ladezeit 5 Min.", + "Chargement des données...": "Daten werden geladen...", + "Cron Status": "Cron Status", + "Dernière Communication": "Letzte Mitteilung", + "Effacer la recherche": "Suche löschen", + "Filtres de statut disponibles": "Verfügbare Statusfilter", + "Hôte SSH": "SSH-Host", + "Nom": "Name", + "Rechercher...": "Suchen...", + "Résumé de l'état de santé de tous vos équipements Monitoring": "Zusammenfassung des Zustands aller Ihrer Geräte Überwachung", + "SSH Status": "SSH-Status", + "Statut SSH": "SSH-Status", + "Statut du cron": "Cron-Status", + "Type": "Typ", + "Uptime": "Uptime", + "Visible": "Sichtbar", + "Équipement actif": "Aktive Geräte", + "Équipement visible": "Sichtbare Ausstattung" + }, "plugins\/Monitoring\/desktop\/php\/Monitoring.php": { "1er port Ethernet": "1. Ethernet-Anschluss", "1er port Wi-Fi": "1. Wi-Fi-Anschluss", @@ -214,6 +246,7 @@ "Rechercher": "Suche", "Saisir le nom de la carte": "Geben Sie den Namen der Karte ein", "Saisir le timeout SRV": "SRV-Timeout eingeben", + "Santé": "Gesundheit", "Sauvegarder": "Speichern", "Si cette option n'est pas cochée, le cron par défaut du plugin sera utilisé": "Wenn diese Option nicht angekreuzt ist, wird der Standard-Cron des Plugins verwendet", "Statistiques": "Statistiken", @@ -234,7 +267,8 @@ "[PLUGIN] Impossible de charger le fichier sshmanager.helper.js (Vérifiez les dépendances)": "[PLUGIN] Die Datei sshmanager.helper.js konnte nicht geladen werden (Überprüfen Sie die Abhängigkeiten)", "[Plugin :: Monitoring] Attention - Version Jeedom !": "[Plugin :: Monitoring] Achtung - Jeedom Version!", "eth1 : 2ème port Ethernet, wlan1 : 2ème port Wi-Fi...": "eth1: 2. Ethernet-Anschluss, wlan1: 2. Wi-Fi-Anschluss...", - "eth2, eth5, enp0s3": "eth2, eth5, enp0s3" + "eth2, eth5, enp0s3": "eth2, eth5, enp0s3", + "Éditer cet hôte SSH": "Diesen SSH-Host bearbeiten" }, "plugins\/Monitoring\/plugin_info\/configuration.php": { "Activer ou Désactiver l'affichage des statistiques mémoire de l'équipement local dans les logs": "Aktivieren oder Deaktivieren der Anzeige der Speicherstatistiken des lokalen Geräts in den Protokollen", diff --git a/core/i18n/en_US.json b/core/i18n/en_US.json index 632f41e5..2b29e59c 100644 --- a/core/i18n/en_US.json +++ b/core/i18n/en_US.json @@ -132,15 +132,47 @@ "Aucune": "No", "Choisir une icône": "Choose an icon", "Commande info liée": "Related info command", + "Fermer": "Close", "Historiser": "History", "Nom de la commande": "Command name", "Orange": "Orange", "Rouge": "Red", + "Santé des équipements Monitoring": "Equipment health monitoring", "Supprimer la commande": "Delete command", "Tester": "Test", "Unité": "Unit", "Vert": "Green" }, + "plugins\/Monitoring\/desktop\/js\/health.monitoring.js": { + "Aucun équipement trouvé": "No equipment found", + "Non configuré": "Not configured" + }, + "plugins\/Monitoring\/desktop\/modal\/health.monitoring.php": { + "401 - Accès non autorisé": "401 - Unauthorized access", + "Actif": "Active", + "Adresse IP": "IP address", + "Autres termes : recherche par nom, IP, charge, etc.": "Other terms: search by name, IP, load, etc.", + "Charge 15min": "Charge 15 min", + "Charge 1min": "Charge 1 min", + "Charge 5min": "Charge 5 min", + "Chargement des données...": "Loading data...", + "Cron Status": "Cron Status", + "Dernière Communication": "Latest Communication", + "Effacer la recherche": "Clear search", + "Filtres de statut disponibles": "Available status filters", + "Hôte SSH": "SSH host", + "Nom": "Name", + "Rechercher...": "Search...", + "Résumé de l'état de santé de tous vos équipements Monitoring": "Summary of the health status of all your equipment Monitoring", + "SSH Status": "SSH Status", + "Statut SSH": "SSH status", + "Statut du cron": "Cron status", + "Type": "Type", + "Uptime": "Uptime", + "Visible": "Visible", + "Équipement actif": "Active equipment", + "Équipement visible": "Visible equipment" + }, "plugins\/Monitoring\/desktop\/php\/Monitoring.php": { "1er port Ethernet": "1st Ethernet port", "1er port Wi-Fi": "1st Wi-Fi port", @@ -214,6 +246,7 @@ "Rechercher": "Search", "Saisir le nom de la carte": "Enter card name", "Saisir le timeout SRV": "Enter SRV timeout", + "Santé": "Health", "Sauvegarder": "Save", "Si cette option n'est pas cochée, le cron par défaut du plugin sera utilisé": "If this option is unchecked, the plugin's default cron will be used", "Statistiques": "Statistics", @@ -234,7 +267,8 @@ "[PLUGIN] Impossible de charger le fichier sshmanager.helper.js (Vérifiez les dépendances)": "[PLUGIN] Unable to load sshmanager.helper.js (Check dependencies)", "[Plugin :: Monitoring] Attention - Version Jeedom !": "[Plugin :: Monitoring] Warning - Jeedom version!", "eth1 : 2ème port Ethernet, wlan1 : 2ème port Wi-Fi...": "eth1: 2nd Ethernet port, wlan1: 2nd Wi-Fi port...", - "eth2, eth5, enp0s3": "eth2, eth5, enp0s3" + "eth2, eth5, enp0s3": "eth2, eth5, enp0s3", + "Éditer cet hôte SSH": "Edit this SSH host" }, "plugins\/Monitoring\/plugin_info\/configuration.php": { "Activer ou Désactiver l'affichage des statistiques mémoire de l'équipement local dans les logs": "Enable or disable the display of local device memory statistics in logs", diff --git a/core/i18n/es_ES.json b/core/i18n/es_ES.json index 7dc5c523..119a66e7 100644 --- a/core/i18n/es_ES.json +++ b/core/i18n/es_ES.json @@ -132,15 +132,47 @@ "Aucune": "No", "Choisir une icône": "Elija un icono", "Commande info liée": "Comando de información relacionado", + "Fermer": "Cerrar", "Historiser": "Historia", "Nom de la commande": "Nombre del comando", "Orange": "Naranja", "Rouge": "Red", + "Santé des équipements Monitoring": "Salud de los equipos Monitorización", "Supprimer la commande": "Eliminar comando", "Tester": "Pruebe", "Unité": "Unidad", "Vert": "Verde" }, + "plugins\/Monitoring\/desktop\/js\/health.monitoring.js": { + "Aucun équipement trouvé": "No se ha encontrado ningún equipo", + "Non configuré": "No configurado" + }, + "plugins\/Monitoring\/desktop\/modal\/health.monitoring.php": { + "401 - Accès non autorisé": "401 - Acceso no autorizado", + "Actif": "Activo", + "Adresse IP": "Dirección IP", + "Autres termes : recherche par nom, IP, charge, etc.": "Otros términos: búsqueda por nombre, IP, carga, etc.", + "Charge 15min": "Carga 15 min", + "Charge 1min": "Carga 1 min", + "Charge 5min": "Carga en 5 minutos", + "Chargement des données...": "Cargando datos...", + "Cron Status": "Estado de Cron", + "Dernière Communication": "Última comunicación", + "Effacer la recherche": "Borrar búsqueda", + "Filtres de statut disponibles": "Filtros de estado disponibles", + "Hôte SSH": "Host SSH", + "Nom": "Nombre", + "Rechercher...": "Buscar...", + "Résumé de l'état de santé de tous vos équipements Monitoring": "Resumen del estado de todos sus equipos Monitoring", + "SSH Status": "Estado de SSH", + "Statut SSH": "Estado SSH", + "Statut du cron": "Estado del cron", + "Type": "Tipo", + "Uptime": "Tiempo de actividad", + "Visible": "Visible", + "Équipement actif": "Equipos activos", + "Équipement visible": "Equipos visibles" + }, "plugins\/Monitoring\/desktop\/php\/Monitoring.php": { "1er port Ethernet": "1er puerto Ethernet", "1er port Wi-Fi": "1er puerto Wi-Fi", @@ -214,6 +246,7 @@ "Rechercher": "Buscar en", "Saisir le nom de la carte": "Introduzca el nombre de la tarjeta", "Saisir le timeout SRV": "Introducir tiempo de espera SRV", + "Santé": "Salud", "Sauvegarder": "Guardar", "Si cette option n'est pas cochée, le cron par défaut du plugin sera utilisé": "Si esta opción no está marcada, se utilizará el cron por defecto del plugin", "Statistiques": "Estadísticas", @@ -234,7 +267,8 @@ "[PLUGIN] Impossible de charger le fichier sshmanager.helper.js (Vérifiez les dépendances)": "[PLUGIN] No se puede cargar sshmanager.helper.js (Comprobar dependencias)", "[Plugin :: Monitoring] Attention - Version Jeedom !": "[Plugin :: Monitorización] Advertencia - ¡Versión Jeedom!", "eth1 : 2ème port Ethernet, wlan1 : 2ème port Wi-Fi...": "eth1: 2º puerto Ethernet, wlan1: 2º puerto Wi-Fi...", - "eth2, eth5, enp0s3": "eth2, eth5, enp0s3" + "eth2, eth5, enp0s3": "eth2, eth5, enp0s3", + "Éditer cet hôte SSH": "Editar este host SSH" }, "plugins\/Monitoring\/plugin_info\/configuration.php": { "Activer ou Désactiver l'affichage des statistiques mémoire de l'équipement local dans les logs": "Activar o desactivar la visualización de las estadísticas de memoria del equipo local en los registros.", diff --git a/core/i18n/it_IT.json b/core/i18n/it_IT.json index b999dbda..2449a783 100644 --- a/core/i18n/it_IT.json +++ b/core/i18n/it_IT.json @@ -132,15 +132,47 @@ "Aucune": "No", "Choisir une icône": "Scegliere un'icona", "Commande info liée": "Comando info correlato", + "Fermer": "Chiudi", "Historiser": "La storia", "Nom de la commande": "Nome del comando", "Orange": "Arancione", "Rouge": "Rosso", + "Santé des équipements Monitoring": "Salute delle apparecchiature Monitoraggio", "Supprimer la commande": "Comando di cancellazione", "Tester": "Test", "Unité": "Unità", "Vert": "Verde" }, + "plugins\/Monitoring\/desktop\/js\/health.monitoring.js": { + "Aucun équipement trouvé": "Nessuna apparecchiatura trovata", + "Non configuré": "Non configurato" + }, + "plugins\/Monitoring\/desktop\/modal\/health.monitoring.php": { + "401 - Accès non autorisé": "401 - Accesso non autorizzato", + "Actif": "Attivo", + "Adresse IP": "Indirizzo IP", + "Autres termes : recherche par nom, IP, charge, etc.": "Altri termini: ricerca per nome, IP, carico, ecc.", + "Charge 15min": "Ricarica 15 min", + "Charge 1min": "Carica 1 min", + "Charge 5min": "Ricarica in 5 minuti", + "Chargement des données...": "Caricamento dati in corso...", + "Cron Status": "Stato di Cron", + "Dernière Communication": "Ultima comunicazione", + "Effacer la recherche": "Cancella ricerca", + "Filtres de statut disponibles": "Filtri di stato disponibili", + "Hôte SSH": "Ospite SSH", + "Nom": "Nome", + "Rechercher...": "Cerca...", + "Résumé de l'état de santé de tous vos équipements Monitoring": "Riepilogo dello stato di salute di tutte le vostre apparecchiature Monitoraggio", + "SSH Status": "Stato SSH", + "Statut SSH": "Stato SSH", + "Statut du cron": "Stato del cron", + "Type": "Tipo", + "Uptime": "Tempo di attività", + "Visible": "Visibile", + "Équipement actif": "Apparecchiature attive", + "Équipement visible": "Apparecchiature visibili" + }, "plugins\/Monitoring\/desktop\/php\/Monitoring.php": { "1er port Ethernet": "1a porta Ethernet", "1er port Wi-Fi": "1a porta Wi-Fi", @@ -214,6 +246,7 @@ "Rechercher": "Ricerca", "Saisir le nom de la carte": "Inserire il nome della scheda", "Saisir le timeout SRV": "Inserire il timeout SRV", + "Santé": "Salute", "Sauvegarder": "Risparmiare", "Si cette option n'est pas cochée, le cron par défaut du plugin sera utilisé": "Se questa opzione non è selezionata, verrà utilizzato il cron predefinito del plugin", "Statistiques": "Statistiche", @@ -234,7 +267,8 @@ "[PLUGIN] Impossible de charger le fichier sshmanager.helper.js (Vérifiez les dépendances)": "[PLUGIN] Impossibile caricare sshmanager.helper.js (controllare le dipendenze)", "[Plugin :: Monitoring] Attention - Version Jeedom !": "[Plugin :: Monitoraggio] Attenzione - versione Jeedom!", "eth1 : 2ème port Ethernet, wlan1 : 2ème port Wi-Fi...": "eth1: seconda porta Ethernet, wlan1: seconda porta Wi-Fi...", - "eth2, eth5, enp0s3": "eth2, eth5, enp0s3" + "eth2, eth5, enp0s3": "eth2, eth5, enp0s3", + "Éditer cet hôte SSH": "Modifica questo host SSH" }, "plugins\/Monitoring\/plugin_info\/configuration.php": { "Activer ou Désactiver l'affichage des statistiques mémoire de l'équipement local dans les logs": "Attivare o disattivare la visualizzazione delle statistiche di memoria dell'apparecchiatura locale nei log", diff --git a/core/i18n/pt_PT.json b/core/i18n/pt_PT.json index e256fcfd..ef437f6a 100644 --- a/core/i18n/pt_PT.json +++ b/core/i18n/pt_PT.json @@ -132,15 +132,47 @@ "Aucune": "Não", "Choisir une icône": "Escolher um ícone", "Commande info liée": "Comando de informação relacionado", + "Fermer": "Fechar", "Historiser": "História", "Nom de la commande": "Nome do comando", "Orange": "Laranja", "Rouge": "Vermelho", + "Santé des équipements Monitoring": "Monitorização da saúde dos equipamentos", "Supprimer la commande": "Apagar comando", "Tester": "Teste", "Unité": "Unidade", "Vert": "Verde" }, + "plugins\/Monitoring\/desktop\/js\/health.monitoring.js": { + "Aucun équipement trouvé": "Nenhum equipamento encontrado", + "Non configuré": "Não configurado" + }, + "plugins\/Monitoring\/desktop\/modal\/health.monitoring.php": { + "401 - Accès non autorisé": "401 - Acesso não autorizado", + "Actif": "Ativo", + "Adresse IP": "Endereço IP", + "Autres termes : recherche par nom, IP, charge, etc.": "Outros termos: pesquisa por nome, IP, carga, etc.", + "Charge 15min": "Carregamento em 15 minutos", + "Charge 1min": "Carregamento em 1 minuto", + "Charge 5min": "Carregamento em 5 minutos", + "Chargement des données...": "Carregando dados...", + "Cron Status": "Estado Cron", + "Dernière Communication": "Última comunicação", + "Effacer la recherche": "Apagar pesquisa", + "Filtres de statut disponibles": "Filtros de estado disponíveis", + "Hôte SSH": "Anfitrião SSH", + "Nom": "Nome", + "Rechercher...": "Pesquisar...", + "Résumé de l'état de santé de tous vos équipements Monitoring": "Resumo do estado de saúde de todos os seus equipamentos Monitorização", + "SSH Status": "Estado do SSH", + "Statut SSH": "Estado SSH", + "Statut du cron": "Estado do cron", + "Type": "Tipo de produto", + "Uptime": "Tempo de funcionamento", + "Visible": "Visível", + "Équipement actif": "Equipamento ativo", + "Équipement visible": "Equipamento visível" + }, "plugins\/Monitoring\/desktop\/php\/Monitoring.php": { "1er port Ethernet": "1ª porta Ethernet", "1er port Wi-Fi": "1ª porta Wi-Fi", @@ -214,6 +246,7 @@ "Rechercher": "Pesquisar", "Saisir le nom de la carte": "Introduzir o nome do cartão", "Saisir le timeout SRV": "Introduzir o tempo limite de SRV", + "Santé": "Saúde", "Sauvegarder": "Guardar", "Si cette option n'est pas cochée, le cron par défaut du plugin sera utilisé": "Se esta opção não estiver selecionada, será utilizado o cron predefinido do plugin", "Statistiques": "Estatísticas", @@ -234,7 +267,8 @@ "[PLUGIN] Impossible de charger le fichier sshmanager.helper.js (Vérifiez les dépendances)": "[PLUGIN] Não foi possível carregar sshmanager.helper.js (Verificar dependências)", "[Plugin :: Monitoring] Attention - Version Jeedom !": "[Plugin :: Monitorização] Aviso - Versão do Jeedom!", "eth1 : 2ème port Ethernet, wlan1 : 2ème port Wi-Fi...": "eth1: 2ª porta Ethernet, wlan1: 2ª porta Wi-Fi...", - "eth2, eth5, enp0s3": "eth2, eth5, enp0s3" + "eth2, eth5, enp0s3": "eth2, eth5, enp0s3", + "Éditer cet hôte SSH": "Editar este host SSH" }, "plugins\/Monitoring\/plugin_info\/configuration.php": { "Activer ou Désactiver l'affichage des statistiques mémoire de l'équipement local dans les logs": "Ativar ou desativar a exibição das estatísticas de memória do equipamento local nos registos", From 6ae623ab2220520a8b055a75d8148e5de7151410 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:20:15 +0100 Subject: [PATCH 54/84] bugfix on templates --- .vscode/cspell.json | 2 + core/template/dashboard/AsusWRT.html | 364 ++++++++++------- core/template/dashboard/Monitoring.html | 509 ++++++++++++++---------- 3 files changed, 524 insertions(+), 351 deletions(-) diff --git a/.vscode/cspell.json b/.vscode/cspell.json index 00eadc69..4e41ac8a 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -36,6 +36,8 @@ "Equipement", "esata", "Etat", + "Eteindre", + "Etes", "firmver", "Formated", "freebsd", diff --git a/core/template/dashboard/AsusWRT.html b/core/template/dashboard/AsusWRT.html index 42cd756a..7e6931f4 100644 --- a/core/template/dashboard/AsusWRT.html +++ b/core/template/dashboard/AsusWRT.html @@ -197,6 +197,26 @@ (() => { 'use strict' + // Get reference to this specific widget container + const widgetRoot = document.querySelector('.eqLogic-widget[data-eqLogic_uid="#uid#"]') + if (!widgetRoot) return + + /** + * Safely parse JSON from data attribute + * @param {string} jsonString - JSON string to parse + * @param {object} fallback - Fallback value if parsing fails + * @returns {object} Parsed object or fallback + */ + const safeJSONParse = (jsonString, fallback = {min: '-', avg: '-', max: '-'}) => { + if (!jsonString || jsonString === 'undefined' || jsonString === '') return fallback + try { + return JSON.parse(jsonString) + } catch (e) { + console.warn('[Monitoring AsusWRT] JSON parse error:', e, 'Input:', jsonString) + return fallback + } + } + // ======================================== // === UTILITY FUNCTIONS === // ======================================== @@ -285,7 +305,8 @@ * Initialize SSH connection status icon */ const initIconSSH = () => { - const iconSSH = document.getElementById('iconSSH#id#') + try { + const iconSSH = widgetRoot.querySelector('#iconSSH#id#') if (!iconSSH) return if ('#cnx_ssh#' === 'OK') { @@ -293,13 +314,17 @@ } else if ('#cnx_ssh#' === 'KO') { iconSSH.innerHTML = '' } - } - - /** - * Initialize Cron status icon - */ - const initIconCron = () => { - const iconCron = document.getElementById('iconCron#id#') + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initIconSSH:', e) + } + } + + /** + * Initialize Cron status icon + */ + const initIconCron = () => { + try { + const iconCron = widgetRoot.querySelector('#iconCron#id#') if (!iconCron) return const isOn = '#cron_status#' === '1' @@ -312,13 +337,17 @@ const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') iconCron.innerHTML = `` - } - - /** - * Initialize Check Firmware icon - */ - const initIconCheckFirmware = () => { - const el = document.getElementById('iconCheckFirmware#id#') + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initIconCron:', e) + } + } + + /** + * Initialize firmware check icon + */ + const initIconCheckFirmware = () => { + try { + const el = widgetRoot.querySelector('#iconCheckFirmware#id#') if (!el) return if ('#asus_fw_check#' === '1') { @@ -326,17 +355,21 @@ } else if ('#asus_fw_check#' === '0') { el.innerHTML = '' } - } - - // ======================================== - // === BUTTON HANDLERS === - // ======================================== - - /** - * Initialize Reboot button with confirmation dialog - */ + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initIconCheckFirmware:', e) + } + } + + // ======================================== + // === BUTTON HANDLERS === + // ======================================== + + /** + * Initialize Reboot button with confirmation dialog + */ const initRebootButton = () => { - const rebootBtn = document.querySelector('.reboot[data-cmd_id="#cmd_reboot_id#"]') + try { + const rebootBtn = widgetRoot.querySelector('.reboot[data-cmd_id="#cmd_reboot_id#"]') rebootBtn?.addEventListener('click', () => { jeeDialog.confirm({ title: ' Redémarrer l\'équipement', @@ -348,13 +381,17 @@ callback: result => result && jeedom.cmd.execute({ id: '#cmd_reboot_id#' }) }) }) - } - - /** - * Initialize Refresh button - */ - const initRefreshButton = () => { - const refreshBtn = document.querySelector('.eqLogic[data-eqLogic_uid="#uid#"] .refresh') + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initRebootButton:', e) + } + } + + /** + * Initialize Refresh button + */ + const initRefreshButton = () => { + try { + const refreshBtn = widgetRoot.querySelector('.refresh') if (!refreshBtn) return if ('#refresh_id#' !== '') { @@ -362,84 +399,112 @@ } else { refreshBtn.remove() } - } - - // ======================================== - // === VALUE DISPLAYS - Simple === - // ======================================== - - /** - * Initialize Uptime display - */ - const initUptime = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initRefreshButton:', e) + } + } + + // ======================================== + // === VALUE DISPLAYS - Simple === + // ======================================== + + /** + * Initialize Uptime display + */ + const initUptime = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const uptimeEl = document.getElementById('uptime#id#') + const uptimeEl = widgetRoot.querySelector('#uptime#id#') if (uptimeEl) uptimeEl.innerHTML = '#uptime#' - } - - /** - * Initialize Network Infos display - */ - const initNetworkInfos = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initUptime:', e) + } + } + + /** + * Initialize Network Infos display + */ + const initNetworkInfos = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const networkInfosEl = document.getElementById('network_infos#id#') + const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') if (networkInfosEl) networkInfosEl.innerHTML = '#network_infos#' - } - - /** - * Initialize Network Traffic display - */ - const initNetwork = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initNetworkInfos:', e) + } + } + + /** + * Initialize Network display + */ + const initNetwork = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const networkEl = document.getElementById('network#id#') + const networkEl = widgetRoot.querySelector('#network#id#') if (networkEl) networkEl.innerHTML = '#network#' - } - - /** - * Initialize Asus Clients display - */ - const initAsusClients = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initNetwork:', e) + } + } + + /** + * Initialize Asus Clients display + */ + const initAsusClients = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = document.getElementById('asus_clients#id#') + const el = widgetRoot.querySelector('#asus_clients#id#') if (el) el.innerHTML = '#asus_clients#' - } - - /** - * Initialize Asus WAN IP display - */ - const initAsusWan0IP = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initAsusClients:', e) + } + } + + /** + * Initialize Asus WAN0 IP display + */ + const initAsusWan0IP = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = document.getElementById('asus_wan0_ip#id#') + const el = widgetRoot.querySelector('#asus_wan0_ip#id#') if (el) el.innerHTML = 'IP (WAN) : #asus_wan0_ip#' - } - - /** - * Initialize Asus WiFi Temperature display - */ - const initAsusWifiTemp = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initAsusWan0IP:', e) + } + } + + /** + * Initialize Asus WiFi Temperature display + */ + const initAsusWifiTemp = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = document.getElementById('asus_wifi_temp#id#') + const el = widgetRoot.querySelector('#asus_wifi_temp#id#') if (el) el.innerHTML = '#asus_wifi_temp#' - } - - // ======================================== - // === VALUE DISPLAYS - With Thresholds === - // ======================================== - - /** - * Initialize Load Average displays (1mn, 5mn, 15mn) - */ - const initLoadAverage = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initAsusWifiTemp:', e) + } + } + + // ======================================== + // === VALUE DISPLAYS - With Thresholds === + // ======================================== + + /** + * Initialize Load Average displays (1mn, 5mn, 15mn) + */ + const initLoadAverage = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return // Load avg 1mn - const loadAvg1mn = document.getElementById('load_avg_1mn#id#') + const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { const html = buildThresholdHTML( '#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', @@ -451,7 +516,7 @@ } // Load avg 5mn - const loadAvg5mn = document.getElementById('load_avg_5mn#id#') + const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') if (loadAvg5mn) { const html = buildThresholdHTML( '#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', @@ -463,7 +528,7 @@ } // Load avg 15mn - const loadAvg15mn = document.getElementById('load_avg_15mn#id#') + const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') if (loadAvg15mn) { const html = buildThresholdHTML( '#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', @@ -473,15 +538,19 @@ ) loadAvg15mn.innerHTML = html === '' ? html : ` - 15 min : ${html}` } - } - - /** - * Initialize Memory display with percentage - */ - const initMemory = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initLoadAverage:', e) + } + } + + /** + * Initialize Memory display with percentage + */ + const initMemory = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const memoryEl = document.getElementById('memory_available_percent#id#') + const memoryEl = widgetRoot.querySelector('#memory_available_percent#id#') if (!memoryEl) return const value = '#memory_available_percent#' @@ -496,15 +565,19 @@ { min: '#memory_available_percent_minHistory#', avg: '#memory_available_percent_averageHistory#', max: '#memory_available_percent_maxHistory#' }, '#memory_available_percent_tendance#', '#memory# (', '%', true ) - } - - /** - * Initialize Swap display with percentage - */ - const initSwap = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initMemory:', e) + } + } + + /** + * Initialize Swap display with percentage + */ + const initSwap = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const swapEl = document.getElementById('swap_free_percent#id#') + const swapEl = widgetRoot.querySelector('#swap_free_percent#id#') if (!swapEl) return const value = '#swap_free_percent#' @@ -519,15 +592,19 @@ { min: '#swap_free_percent_minHistory#', avg: '#swap_free_percent_averageHistory#', max: '#swap_free_percent_maxHistory#' }, '#swap_free_percent_tendance#', '#swap# (', '%', true ) - } - - /** - * Initialize HDD display with percentage - */ - const initHDD = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initSwap:', e) + } + } + + /** + * Initialize HDD display with percentage + */ + const initHDD = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const hddEl = document.getElementById('hdd#id#') + const hddEl = widgetRoot.querySelector('#hdd#id#') if (!hddEl) return const value = '#hdd_free_percent#' @@ -542,21 +619,25 @@ { min: '#hdd_free_percent_minHistory#', avg: '#hdd_free_percent_averageHistory#', max: '#hdd_free_percent_maxHistory#' }, '#hdd_free_percent_tendance#', '#hdd# (', '%', true ) - } - - /** - * Initialize CPU display with optional temperature - */ - const initCPU = () => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initHDD:', e) + } + } + + /** + * Initialize CPU display with optional temperature + */ + const initCPU = () => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const cpuEl = document.getElementById('cpu#id#') + const cpuEl = widgetRoot.querySelector('#cpu#id#') if (!cpuEl) return if ('#cpu_temp#' !== '' && '#cpu_temp_display#' === 'block') { cpuEl.innerHTML = '#cpu# ' - const tempEl = document.getElementById('cpu_temp#id#') + const tempEl = widgetRoot.querySelector('#cpu_temp#id#') if (!tempEl) return const temp = parseFloat('#cpu_temp#') @@ -569,18 +650,22 @@ } else { cpuEl.innerHTML = '#cpu#' } - } - - /** - * Initialize custom command display (perso1-4) using data attributes - * @param {HTMLElement} container - The container div with data-perso-* attributes - */ - const initPerso = (container) => { + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initCPU:', e) + } + } + + /** + * Initialize custom command display (perso1-4) using data attributes + * @param {HTMLElement} container - The container div with data-perso-* attributes + */ + const initPerso = (container) => { + try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const dataset = container.dataset const persoId = dataset.persoId - const el = document.getElementById(`${persoId}_unite#id#`) + const el = widgetRoot.querySelector(`#${persoId}_unite#id#`) if (!el) return const value = dataset.persoValue @@ -588,15 +673,18 @@ el.innerHTML = '' return } - - const val = parseFloat(value) - const low = parseFloat(dataset.persoLow) - const high = parseFloat(dataset.persoHigh) - const history = JSON.parse(dataset.persoHistory) - const title = `Stats : ${dataset.persoName}
Min: ${history.min} | Moy : ${history.avg} | Max : ${history.max}` - const color = getColorStyle(val, low, high, false) - - el.innerHTML = `${value}${dataset.persoUnite}${dataset.persoTendance}` + + const val = parseFloat(value) + const low = parseFloat(dataset.persoLow) + const high = parseFloat(dataset.persoHigh) + const history = safeJSONParse(dataset.persoHistory) + const title = `Stats : ${dataset.persoName}
Min: ${history.min} | Moy : ${history.avg} | Max : ${history.max}` + const color = getColorStyle(val, low, high, false) + + el.innerHTML = `${value}${dataset.persoUnite}${dataset.persoTendance}` + } catch (e) { + console.error('[Monitoring AsusWRT] Error in initPerso for', container.dataset?.persoId || 'unknown', ':', e) + } } // ======================================== @@ -632,7 +720,7 @@ initCPU() // Custom commands - generic initialization using data attributes - document.querySelectorAll('[data-perso-id]').forEach(initPerso) + widgetRoot.querySelectorAll('[data-perso-id]').forEach(initPerso) } })() diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index 2e715e2a..6519d202 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -259,10 +259,30 @@ (() => { 'use strict' + // Get reference to this specific widget container + const widgetRoot = document.querySelector('.eqLogic-widget[data-eqLogic_uid="#uid#"]') + if (!widgetRoot) return + // ======================================== // === UTILITY FUNCTIONS === // ======================================== + /** + * Safely parse JSON from data attribute + * @param {string} jsonString - JSON string to parse + * @param {object} fallback - Fallback value if parsing fails + * @returns {object} Parsed object or fallback + */ + const safeJSONParse = (jsonString, fallback = {min: '-', avg: '-', max: '-'}) => { + if (!jsonString || jsonString === 'undefined' || jsonString === '') return fallback + try { + return JSON.parse(jsonString) + } catch (e) { + console.warn('[Monitoring] JSON parse error:', e, 'Input:', jsonString) + return fallback + } + } + /** * Calculate color style based on thresholds * @param {number} val - Current value @@ -347,13 +367,17 @@ * Initialize SSH connection status icon */ const initIconSSH = () => { - const iconSSH = document.getElementById('iconSSH#id#') - if (!iconSSH) return - - if ('#cnx_ssh#' === 'OK') { - iconSSH.innerHTML = '' - } else if ('#cnx_ssh#' === 'KO') { - iconSSH.innerHTML = '' + try { + const iconSSH = widgetRoot.querySelector('#iconSSH#id#') + if (!iconSSH) return + + if ('#cnx_ssh#' === 'OK') { + iconSSH.innerHTML = '' + } else if ('#cnx_ssh#' === 'KO') { + iconSSH.innerHTML = '' + } + } catch (e) { + console.error('[Monitoring] Error in initIconSSH:', e) } } @@ -361,19 +385,23 @@ * Initialize Cron status icon */ const initIconCron = () => { - const iconCron = document.getElementById('iconCron#id#') - if (!iconCron) return - - const isOn = '#cron_status#' === '1' - const isCustom = '#cron_status_custom#' === '1' - const display = '#cron_status_display#' - - const icon = isOn ? 'play-circle' : 'pause-circle' - const label = isOn ? 'ON' : 'OFF' - const customLabel = isCustom ? 'Custom' : 'Default' - const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') - - iconCron.innerHTML = `` + try { + const iconCron = widgetRoot.querySelector('#iconCron#id#') + if (!iconCron) return + + const isOn = '#cron_status#' === '1' + const isCustom = '#cron_status_custom#' === '1' + const display = '#cron_status_display#' + + const icon = isOn ? 'play-circle' : 'pause-circle' + const label = isOn ? 'ON' : 'OFF' + const customLabel = isCustom ? 'Custom' : 'Default' + const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') + + iconCron.innerHTML = `` + } catch (e) { + console.error('[Monitoring] Error in initIconCron:', e) + } } // ======================================== @@ -384,53 +412,65 @@ * Initialize Reboot button with confirmation dialog */ const initRebootButton = () => { - const rebootBtn = document.querySelector('.reboot[data-cmd_id="#cmd_reboot_id#"]') - rebootBtn?.addEventListener('click', () => { - jeeDialog.confirm({ + try { + const rebootBtn = widgetRoot.querySelector('.reboot[data-cmd_id="#cmd_reboot_id#"]') + rebootBtn?.addEventListener('click', () => { + jeeDialog.confirm({ title: ' Redémarrer l\'équipement', message: 'Etes-vous sûr de vouloir redémarrer l\'équipement #name# ?', - buttons: { - confirm: { label: 'Redémarrer', className: 'warning' }, - cancel: { label: 'Annuler', className: 'info' } - }, - callback: (result) => { - if (result) jeedom.cmd.execute({ id: '#cmd_reboot_id#' }) - } + buttons: { + confirm: { label: 'Redémarrer', className: 'warning' }, + cancel: { label: 'Annuler', className: 'info' } + }, + callback: (result) => { + if (result) jeedom.cmd.execute({ id: '#cmd_reboot_id#' }) + } + }) }) - }) + } catch (e) { + console.error('[Monitoring] Error in initRebootButton:', e) + } } /** * Initialize Poweroff button with confirmation dialog */ const initPoweroffButton = () => { - const poweroffBtn = document.querySelector('.poweroff[data-cmd_id="#cmd_poweroff_id#"]') - poweroffBtn?.addEventListener('click', () => { - jeeDialog.confirm({ + try { + const poweroffBtn = widgetRoot.querySelector('.poweroff[data-cmd_id="#cmd_poweroff_id#"]') + poweroffBtn?.addEventListener('click', () => { + jeeDialog.confirm({ title: ' Eteindre l\'équipement', message: 'Etes-vous sûr de vouloir éteindre l\'équipement #name# ?', - buttons: { - confirm: { label: 'Eteindre', className: 'danger' }, - cancel: { label: 'Annuler', className: 'info' } - }, - callback: (result) => { - if (result) jeedom.cmd.execute({ id: '#cmd_poweroff_id#' }) - } + buttons: { + confirm: { label: 'Eteindre', className: 'danger' }, + cancel: { label: 'Annuler', className: 'info' } + }, + callback: (result) => { + if (result) jeedom.cmd.execute({ id: '#cmd_poweroff_id#' }) + } + }) }) - }) + } catch (e) { + console.error('[Monitoring] Error in initPoweroffButton:', e) + } } /** * Initialize Refresh button */ const initRefreshButton = () => { - const refreshBtn = document.querySelector('.eqLogic[data-eqLogic_uid="#uid#"] .refresh') - if (!refreshBtn) return - - if ('#refresh_id#' !== '') { - refreshBtn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) - } else { - refreshBtn.remove() + try { + const refreshBtn = widgetRoot.querySelector('.refresh') + if (!refreshBtn) return + + if ('#refresh_id#' !== '') { + refreshBtn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) + } else { + refreshBtn.remove() + } + } catch (e) { + console.error('[Monitoring] Error in initRefreshButton:', e) } } @@ -442,30 +482,45 @@ * Initialize Uptime display */ const initUptime = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const uptimeEl = document.getElementById('uptime#id#') - if (uptimeEl) uptimeEl.innerHTML = '#uptime#' + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const uptimeEl = widgetRoot.querySelector('#uptime#id#') + if (uptimeEl) uptimeEl.innerHTML = '#uptime#' + } catch (e) { + console.error('[Monitoring] Error in initUptime:', e) + } } /** * Initialize Network Infos display */ const initNetworkInfos = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const networkInfosEl = document.getElementById('network_infos#id#') - if (networkInfosEl) networkInfosEl.innerHTML = '#network_infos#' + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') + if (networkInfosEl) networkInfosEl.innerHTML = '#network_infos#' + } catch (e) { + console.error('[Monitoring] Error in initNetworkInfos:', e) + } } /** * Initialize Network Traffic display */ const initNetwork = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const networkEl = document.getElementById('network#id#') - if (networkEl) networkEl.innerHTML = '#network#' + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const networkEl = widgetRoot.querySelector('#network#id#') + if (networkEl) { + const history = {min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#'} + networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) + } + } catch (e) { + console.error('[Monitoring] Error in initNetwork:', e) + } } // ======================================== @@ -476,42 +531,46 @@ * Initialize Load Average displays (1mn, 5mn, 15mn) */ const initLoadAverage = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - // Load avg 1mn - const loadAvg1mn = document.getElementById('load_avg_1mn#id#') - if (loadAvg1mn) { - const html = buildThresholdHTML( - '#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', - 'Charge Système (1min)', '#load_avg_1mn_id#', - { min: '#load_avg_1mn_minHistory#', avg: '#load_avg_1mn_averageHistory#', max: '#load_avg_1mn_maxHistory#' }, - '#load_avg_1mn_tendance#' - ) - loadAvg1mn.innerHTML = html === '' ? html : `1 min : ${html}` - } - - // Load avg 5mn - const loadAvg5mn = document.getElementById('load_avg_5mn#id#') - if (loadAvg5mn) { - const html = buildThresholdHTML( - '#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', - 'Charge Système (5min)', '#load_avg_5mn_id#', - { min: '#load_avg_5mn_minHistory#', avg: '#load_avg_5mn_averageHistory#', max: '#load_avg_5mn_maxHistory#' }, - '#load_avg_5mn_tendance#' - ) - loadAvg5mn.innerHTML = html === '' ? html : ` - 5 min : ${html}` - } - - // Load avg 15mn - const loadAvg15mn = document.getElementById('load_avg_15mn#id#') - if (loadAvg15mn) { - const html = buildThresholdHTML( - '#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', - 'Charge Système (15min)', '#load_avg_15mn_id#', - { min: '#load_avg_15mn_minHistory#', avg: '#load_avg_15mn_averageHistory#', max: '#load_avg_15mn_maxHistory#' }, - '#load_avg_15mn_tendance#' - ) - loadAvg15mn.innerHTML = html === '' ? html : ` - 15 min : ${html}` + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + // Load avg 1mn + const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') + if (loadAvg1mn) { + const html = buildThresholdHTML( + '#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', + 'Charge Système (1min)', '#load_avg_1mn_id#', + { min: '#load_avg_1mn_minHistory#', avg: '#load_avg_1mn_averageHistory#', max: '#load_avg_1mn_maxHistory#' }, + '#load_avg_1mn_tendance#' + ) + loadAvg1mn.innerHTML = html === '' ? html : `1 min : ${html}` + } + + // Load avg 5mn + const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') + if (loadAvg5mn) { + const html = buildThresholdHTML( + '#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', + 'Charge Système (5min)', '#load_avg_5mn_id#', + { min: '#load_avg_5mn_minHistory#', avg: '#load_avg_5mn_averageHistory#', max: '#load_avg_5mn_maxHistory#' }, + '#load_avg_5mn_tendance#' + ) + loadAvg5mn.innerHTML = html === '' ? html : ` - 5 min : ${html}` + } + + // Load avg 15mn + const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') + if (loadAvg15mn) { + const html = buildThresholdHTML( + '#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', + 'Charge Système (15min)', '#load_avg_15mn_id#', + { min: '#load_avg_15mn_minHistory#', avg: '#load_avg_15mn_averageHistory#', max: '#load_avg_15mn_maxHistory#' }, + '#load_avg_15mn_tendance#' + ) + loadAvg15mn.innerHTML = html === '' ? html : ` - 15 min : ${html}` + } + } catch (e) { + console.error('[Monitoring] Error in initLoadAverage:', e) } } @@ -519,69 +578,81 @@ * Initialize Memory display with percentage */ const initMemory = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const memoryEl = document.getElementById('memory_available_percent#id#') - if (!memoryEl) return - - const value = '#memory_available_percent#' - if (value === '') { - memoryEl.innerHTML = '#memory#' - return + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const memoryEl = widgetRoot.querySelector('#memory_available_percent#id#') + if (!memoryEl) return + + const value = '#memory_available_percent#' + if (value === '') { + memoryEl.innerHTML = '#memory#' + return + } + + memoryEl.innerHTML = buildPercentageHTML( + value, '#memory_available_percent_colorlow#', '#memory_available_percent_colorhigh#', + 'Mémoire Vive (% Disponible)', '#memory_available_percent_id#', + { min: '#memory_available_percent_minHistory#', avg: '#memory_available_percent_averageHistory#', max: '#memory_available_percent_maxHistory#' }, + '#memory_available_percent_tendance#', '#memory# (', '%', true + ) + } catch (e) { + console.error('[Monitoring] Error in initMemory:', e) } - - memoryEl.innerHTML = buildPercentageHTML( - value, '#memory_available_percent_colorlow#', '#memory_available_percent_colorhigh#', - 'Mémoire Vive (% Disponible)', '#memory_available_percent_id#', - { min: '#memory_available_percent_minHistory#', avg: '#memory_available_percent_averageHistory#', max: '#memory_available_percent_maxHistory#' }, - '#memory_available_percent_tendance#', '#memory# (', '%', true - ) } /** * Initialize Swap display with percentage */ const initSwap = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const swapEl = document.getElementById('swap_free_percent#id#') - if (!swapEl) return - - const value = '#swap_free_percent#' - if (value === '') { - swapEl.innerHTML = '' - return + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const swapEl = widgetRoot.querySelector('#swap_free_percent#id#') + if (!swapEl) return + + const value = '#swap_free_percent#' + if (value === '') { + swapEl.innerHTML = '' + return + } + + swapEl.innerHTML = buildPercentageHTML( + value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', + 'Mémoire Swap (% Libre)', '#swap_free_percent_id#', + { min: '#swap_free_percent_minHistory#', avg: '#swap_free_percent_averageHistory#', max: '#swap_free_percent_maxHistory#' }, + '#swap_free_percent_tendance#', '#swap# (', '%', true + ) + } catch (e) { + console.error('[Monitoring] Error in initSwap:', e) } - - swapEl.innerHTML = buildPercentageHTML( - value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', - 'Mémoire Swap (% Libre)', '#swap_free_percent_id#', - { min: '#swap_free_percent_minHistory#', avg: '#swap_free_percent_averageHistory#', max: '#swap_free_percent_maxHistory#' }, - '#swap_free_percent_tendance#', '#swap# (', '%', true - ) } /** * Initialize HDD display with percentage */ const initHDD = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const hddEl = document.getElementById('hdd#id#') - if (!hddEl) return - - const value = '#hdd_free_percent#' - if (value === '') { - hddEl.innerHTML = '' - return + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const hddEl = widgetRoot.querySelector('#hdd#id#') + if (!hddEl) return + + const value = '#hdd_free_percent#' + if (value === '') { + hddEl.innerHTML = '' + return + } + + hddEl.innerHTML = buildPercentageHTML( + value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', + 'Espace Disque (% Libre)', '#hdd_free_percent_id#', + { min: '#hdd_free_percent_minHistory#', avg: '#hdd_free_percent_averageHistory#', max: '#hdd_free_percent_maxHistory#' }, + '#hdd_free_percent_tendance#', '#hdd# (', '%', true + ) + } catch (e) { + console.error('[Monitoring] Error in initHDD:', e) } - - hddEl.innerHTML = buildPercentageHTML( - value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', - 'Espace Disque (% Libre)', '#hdd_free_percent_id#', - { min: '#hdd_free_percent_minHistory#', avg: '#hdd_free_percent_averageHistory#', max: '#hdd_free_percent_maxHistory#' }, - '#hdd_free_percent_tendance#', '#hdd# (', '%', true - ) } /** @@ -589,61 +660,69 @@ * @param {HTMLElement} synoContainer - The container div with data-syno-* attributes */ const initSynoVolume = (synoContainer) => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const dataset = synoContainer.dataset - if (dataset.synoDisplay !== 'block') return - - const synoId = dataset.synoId - const container = document.getElementById(`${synoId}#id#`) - if (!container) return - - container.className = 'tooltips' - container.style.display = dataset.synoDisplay - container.innerHTML = `${dataset.synoIcon}` - - const percentEl = document.getElementById(`${synoId}_free_percent#id#`) - if (!percentEl) return - - const value = dataset.synoPercent - if (value === '') { - percentEl.innerHTML = '' - return + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const dataset = synoContainer.dataset + if (dataset.synoDisplay !== 'block') return + + const synoId = dataset.synoId + const container = widgetRoot.querySelector(`#${synoId}#id#`) + if (!container) return + + container.className = 'tooltips' + container.style.display = dataset.synoDisplay + container.innerHTML = `${dataset.synoIcon}` + + const percentEl = widgetRoot.querySelector(`#${synoId}_free_percent#id#`) + if (!percentEl) return + + const value = dataset.synoPercent + if (value === '') { + percentEl.innerHTML = '' + return + } + + const history = safeJSONParse(dataset.synoHistory) + percentEl.innerHTML = buildPercentageHTML( + value, dataset.synoLow, dataset.synoHigh, + `${dataset.synoName} (% Libre)`, dataset.synoCmdId, + history, + dataset.synoTendance, `${dataset.synoValue} (`, '%', true + ) + } catch (e) { + console.error('[Monitoring] Error in initSynoVolume for', synoContainer.dataset?.synoId || 'unknown', ':', e) } - - const history = JSON.parse(dataset.synoHistory) - percentEl.innerHTML = buildPercentageHTML( - value, dataset.synoLow, dataset.synoHigh, - `${dataset.synoName} (% Libre)`, dataset.synoCmdId, - history, - dataset.synoTendance, `${dataset.synoValue} (`, '%', true - ) } /** * Initialize CPU display with optional temperature */ const initCPU = () => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const cpuEl = document.getElementById('cpu#id#') - if (!cpuEl) return - - if ('#cpu_temp#' !== '' && '#cpu_temp_display#' === 'block') { - cpuEl.innerHTML = '#cpu# ' - - const tempEl = document.getElementById('cpu_temp#id#') - if (!tempEl) return + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const temp = parseFloat('#cpu_temp#') - const low = parseFloat('#cpu_temp_colorlow#') - const high = parseFloat('#cpu_temp_colorhigh#') - const title = 'Stats : Température CPU
Min: #cpu_temp_minHistory# | Moy : #cpu_temp_averageHistory# | Max : #cpu_temp_maxHistory#' - const color = getColorStyle(temp, low, high, false) + const cpuEl = widgetRoot.querySelector('#cpu#id#') + if (!cpuEl) return - tempEl.innerHTML = `(#cpu_temp#°C#cpu_temp_tendance#)` - } else { - cpuEl.innerHTML = '#cpu#' + if ('#cpu_temp#' !== '' && '#cpu_temp_display#' === 'block') { + cpuEl.innerHTML = '#cpu# ' + + const tempEl = widgetRoot.querySelector('#cpu_temp#id#') + if (!tempEl) return + + const temp = parseFloat('#cpu_temp#') + const low = parseFloat('#cpu_temp_colorlow#') + const high = parseFloat('#cpu_temp_colorhigh#') + const title = 'Stats : Température CPU
Min: #cpu_temp_minHistory# | Moy : #cpu_temp_averageHistory# | Max : #cpu_temp_maxHistory#' + const color = getColorStyle(temp, low, high, false) + + tempEl.innerHTML = `(#cpu_temp#°C#cpu_temp_tendance#)` + } else { + cpuEl.innerHTML = '#cpu#' + } + } catch (e) { + console.error('[Monitoring] Error in initCPU:', e) } } @@ -652,27 +731,31 @@ * @param {HTMLElement} container - The container div with data-perso-* attributes */ const initPerso = (container) => { - if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - - const dataset = container.dataset - const persoId = dataset.persoId - const el = document.getElementById(`${persoId}_unite#id#`) - if (!el) return - - const value = dataset.persoValue - if (value === '') { - el.innerHTML = '' - return + try { + if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return + + const dataset = container.dataset + const persoId = dataset.persoId + const el = widgetRoot.querySelector(`#${persoId}_unite#id#`) + if (!el) return + + const value = dataset.persoValue + if (value === '') { + el.innerHTML = '' + return + } + + const val = parseFloat(value) + const low = parseFloat(dataset.persoLow) + const high = parseFloat(dataset.persoHigh) + const history = safeJSONParse(dataset.persoHistory) + const title = `Stats : ${dataset.persoName}
Min: ${history.min} | Moy : ${history.avg} | Max : ${history.max}` + const color = getColorStyle(val, low, high, false) + + el.innerHTML = `${value}${dataset.persoUnite}${dataset.persoTendance}` + } catch (e) { + console.error('[Monitoring] Error in initPerso for', container.dataset?.persoId || 'unknown', ':', e) } - - const val = parseFloat(value) - const low = parseFloat(dataset.persoLow) - const high = parseFloat(dataset.persoHigh) - const history = JSON.parse(dataset.persoHistory) - const title = `Stats : ${dataset.persoName}
Min: ${history.min} | Moy : ${history.avg} | Max : ${history.max}` - const color = getColorStyle(val, low, high, false) - - el.innerHTML = `${value}${dataset.persoUnite}${dataset.persoTendance}` } // ======================================== @@ -702,13 +785,13 @@ initHDD() // Synology volumes - generic initialization using data attributes - document.querySelectorAll('[data-syno-id]').forEach(initSynoVolume) + widgetRoot.querySelectorAll('[data-syno-id]').forEach(initSynoVolume) // CPU with temperature initCPU() // Custom commands - generic initialization using data attributes - document.querySelectorAll('[data-perso-id]').forEach(initPerso) + widgetRoot.querySelectorAll('[data-perso-id]').forEach(initPerso) } })() From cca06594b8a351e1cd0d7df886f3cb40daff7e56 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:31:16 +0100 Subject: [PATCH 55/84] update templates --- core/template/dashboard/AsusWRT.html | 1142 ++++++++++----------- core/template/dashboard/Monitoring.html | 1244 +++++++++++------------ 2 files changed, 1179 insertions(+), 1207 deletions(-) diff --git a/core/template/dashboard/AsusWRT.html b/core/template/dashboard/AsusWRT.html index 7e6931f4..331847a0 100644 --- a/core/template/dashboard/AsusWRT.html +++ b/core/template/dashboard/AsusWRT.html @@ -3,6 +3,7 @@ div.eqLogic-widget[data-eqLogic_uid="#uid#"] .cmd.monitor-btn { font-size: 12px !important; } + div.eqLogic-widget[data-eqLogic_uid="#uid#"].editingMode .cmd.monitor-btn { display: none !important; } @@ -21,6 +22,7 @@ align-items: center; box-sizing: border-box; } + div.eqLogic-widget[data-eqLogic_uid="#uid#"] div.monitor-name-left span:not(:empty) { padding-right: 3px; } @@ -38,7 +40,7 @@ padding-right: 5px; box-sizing: border-box; } - + div.eqLogic-widget[data-eqLogic_uid="#uid#"] div.widget-name.monitor-name-center a { overflow: hidden !important; text-overflow: ellipsis; @@ -59,7 +61,7 @@ padding-right: 5px; color: inherit !important; } - + div.eqLogic-widget[data-eqLogic_uid="#uid#"] div.monitor-cmds { display: block; text-align: left; @@ -92,636 +94,636 @@
- #distri_name_icon# + #distri_name_icon# #distri_name#
- #uptime_icon# + #uptime_icon#
- #load_avg_icon# + #load_avg_icon#
- #memory_icon# + #memory_icon#
- #swap_icon# + #swap_icon#
- #network_infos_icon# + #network_infos_icon#
- #network_icon# + #network_icon#
- #asus_clients_icon# + #asus_clients_icon#
- #asus_wan0_ip_icon# + #asus_wan0_ip_icon#
- #asus_wifi_temp_icon# + #asus_wifi_temp_icon#
- #hdd_icon# + #hdd_icon#
- #cpu_icon# + #cpu_icon#
-
+
#perso1_icon#
-
+
#perso2_icon#
-
+
#perso3_icon#
-
+
#perso4_icon#
#divGraphInfo# -
+
\ No newline at end of file diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index 6519d202..5f003c41 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -3,6 +3,7 @@ div.eqLogic-widget[data-eqLogic_uid="#uid#"] .cmd.monitor-btn { font-size: 12px !important; } + div.eqLogic-widget[data-eqLogic_uid="#uid#"].editingMode .cmd.monitor-btn { display: none !important; } @@ -21,6 +22,7 @@ align-items: center; box-sizing: border-box; } + div.eqLogic-widget[data-eqLogic_uid="#uid#"] div.monitor-name-left span:not(:empty) { padding-right: 3px; } @@ -38,7 +40,7 @@ padding-right: 5px; box-sizing: border-box; } - + div.eqLogic-widget[data-eqLogic_uid="#uid#"] div.widget-name.monitor-name-center a { overflow: hidden !important; text-overflow: ellipsis; @@ -59,7 +61,7 @@ padding-right: 5px; color: inherit !important; } - + div.eqLogic-widget[data-eqLogic_uid="#uid#"] div.monitor-cmds { display: block; text-align: left; @@ -75,10 +77,10 @@
- + - +
@@ -86,7 +88,7 @@ #name_display# #object_name# #name_display# #object_name#
-
+
@@ -94,705 +96,673 @@
- #distri_name_icon# + #distri_name_icon# #distri_name#
- #uptime_icon# + #uptime_icon#
- #load_avg_icon# + #load_avg_icon#
- #memory_icon# + #memory_icon#
- #swap_icon# + #swap_icon#
- #network_infos_icon# + #network_infos_icon#
- #network_icon# + #network_icon#
#multi_network_cards#
- #hdd_icon# + #hdd_icon#
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
- #cpu_icon# + #cpu_icon#
-
- #perso1_icon# +
+ #perso1_icon#
-
- #perso2_icon# +
+ #perso2_icon#
-
- #perso3_icon# +
+ #perso3_icon#
-
- #perso4_icon# +
+ #perso4_icon#
#divGraphInfo# -
+
\ No newline at end of file From 6cd67144f9c6cc805350e1c0c234f3eea678042e Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:34:06 +0100 Subject: [PATCH 56/84] Update info.json --- plugin_info/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_info/info.json b/plugin_info/info.json index cea69b69..f68d7c2d 100644 --- a/plugin_info/info.json +++ b/plugin_info/info.json @@ -1,7 +1,7 @@ { "id": "Monitoring", "name": "Monitoring", - "pluginVersion": "3.4.1", + "pluginVersion": "3.4.2", "description": { "fr_FR": "Plugin permettant le monitoring des équipements locaux et distants (via SSH). Le plugin affichera les informations systèmes d'équipements sous Linux ou Synology (Distribution, CPU, Mémoire, Disques, Swap).", "en_US": "Plugin to monitor local and remote equipments (through SSH). The plugin will display system informations from Linux or Synology (Distribution, CPU, Memory, Disks, Swap).", From 32de8bc2b3796509127ae1b042b3d2a5a8ba30f4 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:47:55 +0100 Subject: [PATCH 57/84] update templates --- core/template/dashboard/AsusWRT.html | 31 +++++++++------ core/template/dashboard/Monitoring.html | 51 +++++++++++++++---------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/core/template/dashboard/AsusWRT.html b/core/template/dashboard/AsusWRT.html index 331847a0..5c9d25a4 100644 --- a/core/template/dashboard/AsusWRT.html +++ b/core/template/dashboard/AsusWRT.html @@ -1,4 +1,7 @@ -
+
+
+
+ + + + + + + + +
+
+ #name_display# #object_name# + #name_display# #object_name# +
+
+ + + +
+
+
+
+ #distri_name_icon# + #distri_name# +
+
+ #uptime_icon# + +
+
+ #load_avg_icon# + +
+
+ #memory_icon# + +
+
+ #swap_icon# + +
+
+ #network_infos_icon# + +
+
+ #network_icon# + +
+ + #multi_network_cards# +
+ #hdd_icon# + +
+
+ #syno_hddv2_icon# + +
+
+ #syno_hddv3_icon# + +
+
+ #syno_hddv4_icon# + +
+
+ #syno_hddusb_icon# + +
+
+ #syno_hddesata_icon# + +
+
+ #cpu_icon# + +
+
+ #perso1_icon# + +
+
+ #perso2_icon# + +
+
+ #perso3_icon# + +
+
+ #perso4_icon# + +
+
+ #divGraphInfo# + +
From 4896dcbf326b339504f9fa7eb62d36febf0dd8c3 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 08:22:33 +0100 Subject: [PATCH 68/84] Update Monitoring.html --- core/template/dashboard/Monitoring.html | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index 23b3ee0f..de680525 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -685,12 +685,10 @@ initSwap() initHDD() - // Synology volumes - widgetRoot.querySelectorAll('[data-syno-id]').forEach(initSynoVolume) - // CPU with temperature - initCPU() + // CPU with temperature + initCPU() - // Custom commands - generic initialization using data attributes + // Custom commands - generic initialization using data attributes widgetRoot.querySelectorAll('[data-perso-id]').forEach(initPerso) } })() From 1b7d16dcf13f54da47f3ea29316b21620bc50369 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 08:42:25 +0100 Subject: [PATCH 69/84] update templates --- core/template/dashboard/Monitoring.html | 2 +- core/template/dashboard/Synology.html | 1632 +++++++++++------------ 2 files changed, 803 insertions(+), 831 deletions(-) diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index de680525..ecc06866 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -298,7 +298,7 @@ // Only add prefix if it exists and is not a placeholder if (prefix && !prefix.startsWith('#')) { - return `${prefix}${valueSpan}${unitSpan})` + return `${prefix}${valueSpan}${unitSpan})` } return `${valueSpan}${unitSpan}` } diff --git a/core/template/dashboard/Synology.html b/core/template/dashboard/Synology.html index 4952fed7..43a3c70a 100644 --- a/core/template/dashboard/Synology.html +++ b/core/template/dashboard/Synology.html @@ -1,831 +1,803 @@
- -
-
- - - - - - - - -
-
- #name_display# #object_name# - #name_display# #object_name# -
-
- - - -
-
-
-
- #distri_name_icon# - #distri_name# -
-
- #uptime_icon# - -
-
- #load_avg_icon# - -
-
- #memory_icon# - -
-
- #swap_icon# - -
-
- #network_infos_icon# - -
-
- #network_icon# - -
- - #multi_network_cards# -
- #hdd_icon# - -
-
- #syno_hddv2_icon# - -
-
- #syno_hddv3_icon# - -
-
- #syno_hddv4_icon# - -
-
- #syno_hddusb_icon# - -
-
- #syno_hddesata_icon# - -
-
- #cpu_icon# - -
-
- #perso1_icon# - -
-
- #perso2_icon# - -
-
- #perso3_icon# - -
-
- #perso4_icon# - -
-
- #divGraphInfo# - -
+ data-eqType="#eqType#" data-eqLogic_id="#id#" data-eqLogic_uid="#uid#" data-version="#version#" + data-translate-category="#translate_category#" data-category="#category#" data-tags="#tags#" + style="width: #width#;height: #height#;#style#;"> + +
+
+ + + + + + + + +
+
+ #name_display# #object_name# + #name_display# #object_name# +
+
+ + + +
+
+
+
+ #distri_name_icon# + #distri_name# +
+
+ #uptime_icon# + +
+
+ #load_avg_icon# + +
+
+ #memory_icon# + +
+
+ #swap_icon# + +
+
+ #network_infos_icon# + +
+
+ #network_icon# + +
+ + #multi_network_cards# +
+ #hdd_icon# + +
+
+ #syno_hddv2_icon# + +
+
+ #syno_hddv3_icon# + +
+
+ #syno_hddv4_icon# + +
+
+ #syno_hddusb_icon# + +
+
+ #syno_hddesata_icon# + +
+
+ #cpu_icon# + +
+
+ #perso1_icon# + +
+
+ #perso2_icon# + +
+
+ #perso3_icon# + +
+
+ #perso4_icon# + +
+
+ #divGraphInfo# + +
\ No newline at end of file From 7f443beb7f7c7270d0c8fc9d1fcba7f8228e62cb Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 09:38:14 +0100 Subject: [PATCH 70/84] Update mobile templates --- core/template/mobile/AsusWRT.html | 953 ++++++++++++++------------ core/template/mobile/Monitoring.html | 954 +++++++++++++-------------- core/template/mobile/Synology.html | 687 +++++++++++++++++++ 3 files changed, 1664 insertions(+), 930 deletions(-) create mode 100644 core/template/mobile/Synology.html diff --git a/core/template/mobile/AsusWRT.html b/core/template/mobile/AsusWRT.html index 1a89e011..7c87de37 100644 --- a/core/template/mobile/AsusWRT.html +++ b/core/template/mobile/AsusWRT.html @@ -1,4 +1,6 @@ -
+
+ + + + + + + + + + + + + + #name_display# + + + + + + + + +
+
+ #distri_name_icon# + #distri_name# +
+
+ #uptime_icon# + +
+
+ #load_avg_icon# + +
+
+ #memory_icon# + +
+
+ #swap_icon# + +
+
+ #network_infos_icon# + +
+
+ #network_icon# + +
+ + #multi_network_cards# +
+ #hdd_icon# + +
+
+ #syno_v2_icon# + +
+
+ #syno_v3_icon# + +
+
+ #syno_v4_icon# + +
+
+ #syno_usb_icon# + +
+
+ #syno_esata_icon# + +
+
+ #cpu_icon# + +
+
+ #perso1_icon# + +
+
+ #perso2_icon# + +
+
+ #perso3_icon# + +
+
+ #perso4_icon# + +
+
+ +
\ No newline at end of file From 21318566c1b40483d72d4c41b8324f1a9d23db79 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:01:10 +0100 Subject: [PATCH 71/84] update templates --- core/template/dashboard/AsusWRT.html | 30 ++++++++++++++---------- core/template/dashboard/Monitoring.html | 26 +++++++++++---------- core/template/dashboard/Synology.html | 31 +++++++++++++------------ core/template/mobile/AsusWRT.html | 28 +++++++++++----------- core/template/mobile/Monitoring.html | 28 +++++++++++----------- core/template/mobile/Synology.html | 12 +++++----- 6 files changed, 82 insertions(+), 73 deletions(-) diff --git a/core/template/dashboard/AsusWRT.html b/core/template/dashboard/AsusWRT.html index da435c5c..39ad65ab 100644 --- a/core/template/dashboard/AsusWRT.html +++ b/core/template/dashboard/AsusWRT.html @@ -433,7 +433,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const uptimeEl = widgetRoot.querySelector('#uptime#id#') - if (uptimeEl) uptimeEl.innerHTML = '#uptime#' + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initUptime:', e) } @@ -447,7 +448,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') - if (networkInfosEl) networkInfosEl.innerHTML = '#network_infos#' + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initNetworkInfos:', e) } @@ -461,7 +463,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkEl = widgetRoot.querySelector('#network#id#') - if (networkEl) networkEl.innerHTML = '#network#' + if (!networkEl) return + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initNetwork:', e) } @@ -475,7 +478,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const el = widgetRoot.querySelector('#asus_clients#id#') - if (el) el.innerHTML = '#asus_clients#' + if (!el) return + el.innerHTML = '#asus_clients#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initAsusClients:', e) } @@ -489,7 +493,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const el = widgetRoot.querySelector('#asus_wan0_ip#id#') - if (el) el.innerHTML = 'IP (WAN) : #asus_wan0_ip#' + if (!el) return + el.innerHTML = 'IP (WAN) : #asus_wan0_ip#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initAsusWan0IP:', e) } @@ -503,7 +508,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const el = widgetRoot.querySelector('#asus_wifi_temp#id#') - if (el) el.innerHTML = '#asus_wifi_temp#' + if (!el) return + el.innerHTML = '#asus_wifi_temp#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initAsusWifiTemp:', e) } @@ -523,37 +529,37 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html = buildThresholdHTML( + const html1mn = buildThresholdHTML( '#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', 'Charge Système (1min)', '#load_avg_1mn_id#', { min: '#load_avg_1mn_minHistory#', avg: '#load_avg_1mn_averageHistory#', max: '#load_avg_1mn_maxHistory#' }, '#load_avg_1mn_tendance#' ) - loadAvg1mn.innerHTML = html === '' ? html : `1 min : ${html}` + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` } // Load avg 5mn const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') if (loadAvg5mn) { - const html = buildThresholdHTML( + const html5mn = buildThresholdHTML( '#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', 'Charge Système (5min)', '#load_avg_5mn_id#', { min: '#load_avg_5mn_minHistory#', avg: '#load_avg_5mn_averageHistory#', max: '#load_avg_5mn_maxHistory#' }, '#load_avg_5mn_tendance#' ) - loadAvg5mn.innerHTML = html === '' ? html : ` - 5 min : ${html}` + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` } // Load avg 15mn const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') if (loadAvg15mn) { - const html = buildThresholdHTML( + const html15mn = buildThresholdHTML( '#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', 'Charge Système (15min)', '#load_avg_15mn_id#', { min: '#load_avg_15mn_minHistory#', avg: '#load_avg_15mn_averageHistory#', max: '#load_avg_15mn_maxHistory#' }, '#load_avg_15mn_tendance#' ) - loadAvg15mn.innerHTML = html === '' ? html : ` - 15 min : ${html}` + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring AsusWRT] Error in initLoadAverage:', e) diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index ecc06866..94ccc2d7 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -430,7 +430,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const uptimeEl = widgetRoot.querySelector('#uptime#id#') - if (uptimeEl) uptimeEl.innerHTML = '#uptime#' + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring] Error in initUptime:', e) } @@ -444,7 +445,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') - if (networkInfosEl) networkInfosEl.innerHTML = '#network_infos#' + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring] Error in initNetworkInfos:', e) } @@ -458,10 +460,10 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkEl = widgetRoot.querySelector('#network#id#') - if (networkEl) { - const history = { min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#' } - networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) - } + if (!networkEl) return + + const history = { min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#' } + networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) } catch (e) { console.error('[Monitoring] Error in initNetwork:', e) } @@ -481,37 +483,37 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html = buildThresholdHTML( + const html1mn = buildThresholdHTML( '#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', 'Charge Système (1min)', '#load_avg_1mn_id#', { min: '#load_avg_1mn_minHistory#', avg: '#load_avg_1mn_averageHistory#', max: '#load_avg_1mn_maxHistory#' }, '#load_avg_1mn_tendance#' ) - loadAvg1mn.innerHTML = html === '' ? html : `1 min : ${html}` + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` } // Load avg 5mn const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') if (loadAvg5mn) { - const html = buildThresholdHTML( + const html5mn = buildThresholdHTML( '#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', 'Charge Système (5min)', '#load_avg_5mn_id#', { min: '#load_avg_5mn_minHistory#', avg: '#load_avg_5mn_averageHistory#', max: '#load_avg_5mn_maxHistory#' }, '#load_avg_5mn_tendance#' ) - loadAvg5mn.innerHTML = html === '' ? html : ` - 5 min : ${html}` + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` } // Load avg 15mn const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') if (loadAvg15mn) { - const html = buildThresholdHTML( + const html15mn = buildThresholdHTML( '#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', 'Charge Système (15min)', '#load_avg_15mn_id#', { min: '#load_avg_15mn_minHistory#', avg: '#load_avg_15mn_averageHistory#', max: '#load_avg_15mn_maxHistory#' }, '#load_avg_15mn_tendance#' ) - loadAvg15mn.innerHTML = html === '' ? html : ` - 15 min : ${html}` + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring] Error in initLoadAverage:', e) diff --git a/core/template/dashboard/Synology.html b/core/template/dashboard/Synology.html index 43a3c70a..739936f6 100644 --- a/core/template/dashboard/Synology.html +++ b/core/template/dashboard/Synology.html @@ -491,7 +491,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const uptimeEl = widgetRoot.querySelector('#uptime#id#') - if (uptimeEl) uptimeEl.innerHTML = '#uptime#' + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring] Error in initUptime:', e) } @@ -505,7 +506,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') - if (networkInfosEl) networkInfosEl.innerHTML = '#network_infos#' + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring] Error in initNetworkInfos:', e) } @@ -519,10 +521,10 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkEl = widgetRoot.querySelector('#network#id#') - if (networkEl) { - const history = { min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#' } - networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) - } + if (!networkEl) return + + const history = { min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#' } + networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) } catch (e) { console.error('[Monitoring] Error in initNetwork:', e) } @@ -542,37 +544,37 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html = buildThresholdHTML( + const html1mn = buildThresholdHTML( '#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', 'Charge Système (1min)', '#load_avg_1mn_id#', { min: '#load_avg_1mn_minHistory#', avg: '#load_avg_1mn_averageHistory#', max: '#load_avg_1mn_maxHistory#' }, '#load_avg_1mn_tendance#' ) - loadAvg1mn.innerHTML = html === '' ? html : `1 min : ${html}` + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` } // Load avg 5mn const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') if (loadAvg5mn) { - const html = buildThresholdHTML( + const html5mn = buildThresholdHTML( '#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', 'Charge Système (5min)', '#load_avg_5mn_id#', { min: '#load_avg_5mn_minHistory#', avg: '#load_avg_5mn_averageHistory#', max: '#load_avg_5mn_maxHistory#' }, '#load_avg_5mn_tendance#' ) - loadAvg5mn.innerHTML = html === '' ? html : ` - 5 min : ${html}` + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` } // Load avg 15mn const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') if (loadAvg15mn) { - const html = buildThresholdHTML( + const html15mn = buildThresholdHTML( '#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', 'Charge Système (15min)', '#load_avg_15mn_id#', { min: '#load_avg_15mn_minHistory#', avg: '#load_avg_15mn_averageHistory#', max: '#load_avg_15mn_maxHistory#' }, '#load_avg_15mn_tendance#' ) - loadAvg15mn.innerHTML = html === '' ? html : ` - 15 min : ${html}` + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring] Error in initLoadAverage:', e) @@ -697,9 +699,8 @@ // Ajouter le pourcentage dans le deuxième span const percentSpan = volumeEl.querySelector('.syno-percent') - if (percentSpan) { - percentSpan.innerHTML = percentageHTML - } + if (!percentSpan) return + percentSpan.innerHTML = percentageHTML } catch (e) { console.error('[Monitoring] Error in initSynoVolume for', volumeEl.dataset?.synoId || 'unknown', ':', e) } diff --git a/core/template/mobile/AsusWRT.html b/core/template/mobile/AsusWRT.html index 7c87de37..ce4b47a0 100644 --- a/core/template/mobile/AsusWRT.html +++ b/core/template/mobile/AsusWRT.html @@ -473,22 +473,22 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') - loadAvg1mn.innerHTML = html - } + const html1mn = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` + } - // Load avg 5mn - const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') - if (loadAvg5mn) { - const html = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') - loadAvg5mn.innerHTML = html - } + // Load avg 5mn + const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') + if (loadAvg5mn) { + const html5mn = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` + } - // Load avg 15mn - const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') - if (loadAvg15mn) { - const html = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') - loadAvg15mn.innerHTML = html + // Load avg 15mn + const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') + if (loadAvg15mn) { + const html15mn = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring AsusWRT] Error in initLoadAverage:', e) diff --git a/core/template/mobile/Monitoring.html b/core/template/mobile/Monitoring.html index 0787ed63..2fd2b786 100644 --- a/core/template/mobile/Monitoring.html +++ b/core/template/mobile/Monitoring.html @@ -416,22 +416,22 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') - loadAvg1mn.innerHTML = html - } + const html1mn = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` + } - // Load avg 5mn - const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') - if (loadAvg5mn) { - const html = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') - loadAvg5mn.innerHTML = html - } + // Load avg 5mn + const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') + if (loadAvg5mn) { + const html5mn = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` + } - // Load avg 15mn - const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') - if (loadAvg15mn) { - const html = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') - loadAvg15mn.innerHTML = html + // Load avg 15mn + const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') + if (loadAvg15mn) { + const html15mn = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring] Error in initLoadAverage:', e) diff --git a/core/template/mobile/Synology.html b/core/template/mobile/Synology.html index d655db08..32cbc321 100644 --- a/core/template/mobile/Synology.html +++ b/core/template/mobile/Synology.html @@ -458,22 +458,22 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') - loadAvg1mn.innerHTML = html + const html1mn = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` } // Load avg 5mn const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') if (loadAvg5mn) { - const html = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') - loadAvg5mn.innerHTML = html + const html5mn = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` } // Load avg 15mn const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') if (loadAvg15mn) { - const html = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') - loadAvg15mn.innerHTML = html + const html15mn = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring Syno] Error in initLoadAverage:', e) From d2ddcfa2e43ec21ea267498e69da29936a72b01f Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:08:44 +0100 Subject: [PATCH 72/84] update templates --- core/template/dashboard/Monitoring.html | 5 ++--- core/template/dashboard/Synology.html | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index 94ccc2d7..e25a0c04 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -460,10 +460,9 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkEl = widgetRoot.querySelector('#network#id#') - if (!networkEl) return + if (!networkEl) return - const history = { min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#' } - networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring] Error in initNetwork:', e) } diff --git a/core/template/dashboard/Synology.html b/core/template/dashboard/Synology.html index 739936f6..a38cf0f7 100644 --- a/core/template/dashboard/Synology.html +++ b/core/template/dashboard/Synology.html @@ -523,8 +523,7 @@ const networkEl = widgetRoot.querySelector('#network#id#') if (!networkEl) return - const history = { min: '#network_minHistory#', avg: '#network_averageHistory#', max: '#network_maxHistory#' } - networkEl.innerHTML = buildThresholdHTML('#network#', '#network_colorlow#', '#network_colorhigh#', 'Vitesse du réseau', '#network_id#', history, '#network_tendance#', false) + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring] Error in initNetwork:', e) } From 9df2979d04edbd546388063223de839f8af3f521 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:16:52 +0100 Subject: [PATCH 73/84] Update Monitoring.class.php --- core/class/Monitoring.class.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/class/Monitoring.class.php b/core/class/Monitoring.class.php index ddd10f75..8d86f89b 100644 --- a/core/class/Monitoring.class.php +++ b/core/class/Monitoring.class.php @@ -241,12 +241,14 @@ public static function pullCustom($_options) { $mem_stats = config::byKey('configStatsMemCustom', 'Monitoring', '0') == '1' ? true : false; if ($mem_stats) { $mem_start_usage = memory_get_usage(); - log::add('Monitoring', 'info', '[PULLCUSTOM] Memory Usage Start :: ' . round($mem_start_usage / 1024, 2) . ' Ko'); } /** @var Monitoring $Monitoring */ $Monitoring = Monitoring::byId($_options['Monitoring_Id']); if (is_object($Monitoring)) { + if ($mem_stats) { + log::add('Monitoring', 'info', '[' . $Monitoring->getName() .'][PULLCUSTOM] Memory Usage Start :: ' . round($mem_start_usage / 1024, 2) . ' Ko'); + } $cronState = $Monitoring->getCmd(null, 'cron_status'); if (is_object($cronState) && $cronState->execCmd() === 0) { log::add('Monitoring', 'debug', '[' . $Monitoring->getName() .'][PULLCUSTOM] Pull (Custom) :: En Pause'); @@ -270,10 +272,10 @@ public static function pullCustom($_options) { } $Monitoring->refreshWidget(); } - } - if ($mem_stats) { - $mem_end_usage = memory_get_usage(); - log::add('Monitoring', 'info', '[PULLCUSTOM] Memory Usage End :: ' . round($mem_end_usage / 1024, 2) . ' Ko | Conso :: ' . round(($mem_end_usage - $mem_start_usage) / 1024, 2) . ' Ko'); + if ($mem_stats) { + $mem_end_usage = memory_get_usage(); + log::add('Monitoring', 'info', '[' . $Monitoring->getName() .'][PULLCUSTOM] Memory Usage End :: ' . round($mem_end_usage / 1024, 2) . ' Ko | Conso :: ' . round(($mem_end_usage - $mem_start_usage) / 1024, 2) . ' Ko'); + } } } From fa63fecd6a9676bbe19ebe3a81a3bf78cae3ab27 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:37:26 +0100 Subject: [PATCH 74/84] Update Monitoring class --- core/class/Monitoring.class.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/class/Monitoring.class.php b/core/class/Monitoring.class.php index 8d86f89b..9909f35e 100644 --- a/core/class/Monitoring.class.php +++ b/core/class/Monitoring.class.php @@ -279,13 +279,13 @@ public static function pullCustom($_options) { } } - public static function postConfig_configPullLocal($value) { - log::add('Monitoring', 'debug', '[CONFIG-SAVE] Configuration PullLocal :: '. $value); - } - + public static function postConfig_configPullLocal($value) { + log::add('Monitoring', 'debug', '[CONFIG-SAVE] Configuration PullLocal :: ' . $value); + } + public static function postConfig_configPull($value) { - log::add('Monitoring', 'debug', '[CONFIG-SAVE] Configuration Pull :: '. $value); - } + log::add('Monitoring', 'debug', '[CONFIG-SAVE] Configuration Pull :: ' . $value); + } // Fonction exécutée automatiquement avant la suppression de l'équipement public function preRemove() { @@ -2118,10 +2118,10 @@ public function postSave() { $cron->save(); } else { $cron = cron::byClassAndFunction('Monitoring', 'pullCustom', array('Monitoring_Id' => intval($this->getId()))); - if (is_object($cron)) { - log::add('Monitoring', 'debug', '['. $this->getName() .'][POSTSAVE] Remove CustomPull'); - $cron->remove(); - } + if (is_object($cron)) { + log::add('Monitoring', 'debug', '[' . $this->getName() . '][POSTSAVE] Remove CustomPull'); + $cron->remove(); + } } $this->getInformations(); From 8e4b044e1eb0324540ccf08ce190766b98fda6c6 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:37:36 +0100 Subject: [PATCH 75/84] Update templates --- core/template/dashboard/Monitoring.html | 10 +++--- core/template/mobile/Monitoring.html | 42 ++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/core/template/dashboard/Monitoring.html b/core/template/dashboard/Monitoring.html index e25a0c04..0a974be4 100644 --- a/core/template/dashboard/Monitoring.html +++ b/core/template/dashboard/Monitoring.html @@ -430,8 +430,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const uptimeEl = widgetRoot.querySelector('#uptime#id#') - if (!uptimeEl) return - uptimeEl.innerHTML = '#uptime#' + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring] Error in initUptime:', e) } @@ -445,8 +445,8 @@ if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') - if (!networkInfosEl) return - networkInfosEl.innerHTML = '#network_infos#' + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring] Error in initNetworkInfos:', e) } @@ -462,7 +462,7 @@ const networkEl = widgetRoot.querySelector('#network#id#') if (!networkEl) return - networkEl.innerHTML = '#network#' + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring] Error in initNetwork:', e) } diff --git a/core/template/mobile/Monitoring.html b/core/template/mobile/Monitoring.html index 2fd2b786..ef70d3b4 100644 --- a/core/template/mobile/Monitoring.html +++ b/core/template/mobile/Monitoring.html @@ -259,13 +259,13 @@ */ const initIconSSH = () => { try { - const el = widgetRoot.querySelector('#iconSSH#id#') - if (!el) return + const iconSSH = widgetRoot.querySelector('#iconSSH#id#') + if (!iconSSH) return if ('#cnx_ssh#' === 'OK') { - el.innerHTML = '' + iconSSH.innerHTML = '' } else if ('#cnx_ssh#' === 'KO') { - el.innerHTML = '' + iconSSH.innerHTML = '' } } catch (e) { console.error('[Monitoring] Error in initIconSSH:', e) @@ -277,8 +277,8 @@ */ const initIconCron = () => { try { - const el = widgetRoot.querySelector('#iconCron#id#') - if (!el) return + const iconCron = widgetRoot.querySelector('#iconCron#id#') + if (!iconCron) return const isOn = '#cron_status#' === '1' const isCustom = '#cron_status_custom#' === '1' @@ -289,7 +289,7 @@ const customLabel = isCustom ? ' (Custom)' : ' (Default)' const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') - el.innerHTML = '' + iconCron.innerHTML = '' } catch (e) { console.error('[Monitoring] Error in initIconCron:', e) } @@ -416,22 +416,22 @@ // Load avg 1mn const loadAvg1mn = widgetRoot.querySelector('#load_avg_1mn#id#') if (loadAvg1mn) { - const html1mn = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') - loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` - } + const html1mn = buildThresholdHTML('#load_avg_1mn#', '#load_avg_1mn_colorlow#', '#load_avg_1mn_colorhigh#', '1 min : ') + loadAvg1mn.innerHTML = html1mn === '' ? html1mn : `1 min : ${html1mn}` + } - // Load avg 5mn - const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') - if (loadAvg5mn) { - const html5mn = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') - loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` - } + // Load avg 5mn + const loadAvg5mn = widgetRoot.querySelector('#load_avg_5mn#id#') + if (loadAvg5mn) { + const html5mn = buildThresholdHTML('#load_avg_5mn#', '#load_avg_5mn_colorlow#', '#load_avg_5mn_colorhigh#', ' - 5 min : ') + loadAvg5mn.innerHTML = html5mn === '' ? html5mn : ` - 5 min : ${html5mn}` + } - // Load avg 15mn - const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') - if (loadAvg15mn) { - const html15mn = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') - loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` + // Load avg 15mn + const loadAvg15mn = widgetRoot.querySelector('#load_avg_15mn#id#') + if (loadAvg15mn) { + const html15mn = buildThresholdHTML('#load_avg_15mn#', '#load_avg_15mn_colorlow#', '#load_avg_15mn_colorhigh#', ' - 15 min : ') + loadAvg15mn.innerHTML = html15mn === '' ? html15mn : ` - 15 min : ${html15mn}` } } catch (e) { console.error('[Monitoring] Error in initLoadAverage:', e) From afb4366442600ba65c095d26d31341d96e335fe6 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:54:45 +0100 Subject: [PATCH 76/84] Update templates --- core/template/mobile/AsusWRT.html | 106 +++++++++++++-------------- core/template/mobile/Monitoring.html | 72 +++++++++--------- core/template/mobile/Synology.html | 92 +++++++++++------------ 3 files changed, 135 insertions(+), 135 deletions(-) diff --git a/core/template/mobile/AsusWRT.html b/core/template/mobile/AsusWRT.html index ce4b47a0..4c3b425c 100644 --- a/core/template/mobile/AsusWRT.html +++ b/core/template/mobile/AsusWRT.html @@ -271,13 +271,13 @@ */ const initIconSSH = () => { try { - const el = widgetRoot.querySelector('#iconSSH#id#') - if (!el) return + const iconSSH = widgetRoot.querySelector('#iconSSH#id#') + if (!iconSSH) return if ('#cnx_ssh#' === 'OK') { - el.innerHTML = '' + iconSSH.innerHTML = '' } else if ('#cnx_ssh#' === 'KO') { - el.innerHTML = '' + iconSSH.innerHTML = '' } } catch (e) { console.error('[Monitoring AsusWRT] Error in initIconSSH:', e) @@ -289,8 +289,8 @@ */ const initIconCron = () => { try { - const el = widgetRoot.querySelector('#iconCron#id#') - if (!el) return + const iconCron = widgetRoot.querySelector('#iconCron#id#') + if (!iconCron) return const isOn = '#cron_status#' === '1' const isCustom = '#cron_status_custom#' === '1' @@ -301,7 +301,7 @@ const customLabel = isCustom ? ' (Custom)' : ' (Default)' const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') - el.innerHTML = '' + iconCron.innerHTML = '' } catch (e) { console.error('[Monitoring AsusWRT] Error in initIconCron:', e) } @@ -312,13 +312,13 @@ */ const initIconCheckFirmware = () => { try { - const el = widgetRoot.querySelector('#iconCheckFirmware#id#') - if (!el) return + const iconCheckFirmware = widgetRoot.querySelector('#iconCheckFirmware#id#') + if (!iconCheckFirmware) return if ('#asus_fw_check#' === '1') { - el.innerHTML = '' + iconCheckFirmware.innerHTML = '' } else if ('#asus_fw_check#' === '0') { - el.innerHTML = '' + iconCheckFirmware.innerHTML = '' } } catch (e) { console.error('[Monitoring AsusWRT] Error in initIconCheckFirmware:', e) @@ -334,10 +334,10 @@ */ const initRebootButton = () => { try { - const btn = widgetRoot.querySelector('.reboot') - if (!btn) return + const rebootBtn = widgetRoot.querySelector('.reboot') + if (!rebootBtn) return - btn.addEventListener('click', () => { + rebootBtn.addEventListener('click', () => { if (confirm("Etes-vous sûr de vouloir redémarrer l'équipement #name# ?")) { jeedom.cmd.execute({ id: '#cmd_reboot_id#' }) } @@ -352,13 +352,13 @@ */ const initRefreshButton = () => { try { - const btn = widgetRoot.querySelector('.eqLogic[data-eqLogic_uid="#uid#"] .refresh') - if (!btn) return + const refreshBtn = widgetRoot.querySelector('.eqLogic[data-eqLogic_uid="#uid#"] .refresh') + if (!refreshBtn) return if ('#refresh_id#' !== '') { - btn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) + refreshBtn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) } else { - btn.remove() + refreshBtn.remove() } } catch (e) { console.error('[Monitoring AsusWRT] Error in initRefreshButton:', e) @@ -376,9 +376,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#uptime#id#') - if (!el) return - el.innerHTML = '#uptime#' + const uptimeEl = widgetRoot.querySelector('#uptime#id#') + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initUptime:', e) } @@ -391,9 +391,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#network_infos#id#') - if (!el) return - el.innerHTML = '#network_infos#' + const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initNetworkInfos:', e) } @@ -406,9 +406,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#network#id#') - if (!el) return - el.innerHTML = '#network#' + const networkEl = widgetRoot.querySelector('#network#id#') + if (!networkEl) return + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initNetwork:', e) } @@ -421,9 +421,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#asus_clients#id#') - if (!el) return - el.innerHTML = '#asus_clients#' + const asusClientsEl = widgetRoot.querySelector('#asus_clients#id#') + if (!asusClientsEl) return + asusClientsEl.innerHTML = '#asus_clients#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initAsusClients:', e) } @@ -436,9 +436,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#asus_wan0_ip#id#') - if (!el) return - el.innerHTML = '#asus_wan0_ip#' + const asusWanIpEl = widgetRoot.querySelector('#asus_wan0_ip#id#') + if (!asusWanIpEl) return + asusWanIpEl.innerHTML = '#asus_wan0_ip#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initAsusWanIP:', e) } @@ -451,9 +451,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#asus_wifi_temp#id#') - if (!el) return - el.innerHTML = '#asus_wifi_temp#' + const asusWiFiTempEl = widgetRoot.querySelector('#asus_wifi_temp#id#') + if (!asusWiFiTempEl) return + asusWiFiTempEl.innerHTML = '#asus_wifi_temp#' } catch (e) { console.error('[Monitoring AsusWRT] Error in initAsusWiFiTemp:', e) } @@ -502,16 +502,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#memory_available_percent#id#') - if (!el) return + const memoryEl = widgetRoot.querySelector('#memory_available_percent#id#') + if (!memoryEl) return const value = '#memory_available_percent#' if (value === '') { - el.innerHTML = '#memory#' + memoryEl.innerHTML = '#memory#' return } - el.innerHTML = buildPercentageHTML(value, '#memory_available_percent_colorlow#', '#memory_available_percent_colorhigh#', '#memory# (', '%', true) + memoryEl.innerHTML = buildPercentageHTML(value, '#memory_available_percent_colorlow#', '#memory_available_percent_colorhigh#', '#memory# (', '%', true) } catch (e) { console.error('[Monitoring AsusWRT] Error in initMemory:', e) } @@ -524,16 +524,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#swap_free_percent#id#') - if (!el) return + const swapEl = widgetRoot.querySelector('#swap_free_percent#id#') + if (!swapEl) return const value = '#swap_free_percent#' if (value === '') { - el.innerHTML = '#swap#' + swapEl.innerHTML = '#swap#' return } - el.innerHTML = buildPercentageHTML(value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', '#swap# (', '%', true) + swapEl.innerHTML = buildPercentageHTML(value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', '#swap# (', '%', true) } catch (e) { console.error('[Monitoring AsusWRT] Error in initSwap:', e) } @@ -546,16 +546,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#hdd#id#') - if (!el) return + const hddEl = widgetRoot.querySelector('#hdd#id#') + if (!hddEl) return const value = '#hdd_free_percent#' if (value === '') { - el.innerHTML = '' + hddEl.innerHTML = '' return } - el.innerHTML = buildPercentageHTML(value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', '#hdd# (', '%', true) + hddEl.innerHTML = buildPercentageHTML(value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', '#hdd# (', '%', true) } catch (e) { console.error('[Monitoring AsusWRT] Error in initHDD:', e) } @@ -600,12 +600,12 @@ const dataset = container.dataset const persoId = dataset.persoId - const el = widgetRoot.querySelector('#' + persoId + '_unite#id#') - if (!el) return + const persoEl = widgetRoot.querySelector('#' + persoId + '_unite#id#') + if (!persoEl) return const value = dataset.persoValue if (value === '') { - el.innerHTML = '' + persoEl.innerHTML = '' return } @@ -615,9 +615,9 @@ const color = getColorStyle(val, low, high, false) if (color) { - el.innerHTML = '' + value + '' + dataset.persoUnite + '' + persoEl.innerHTML = '' + value + '' + dataset.persoUnite + '' } else { - el.innerHTML = '' + value + '' + dataset.persoUnite + '' + persoEl.innerHTML = '' + value + '' + dataset.persoUnite + '' } } catch (e) { console.error('[Monitoring AsusWRT] Error in initPerso for', container.dataset?.persoId || 'unknown', ':', e) diff --git a/core/template/mobile/Monitoring.html b/core/template/mobile/Monitoring.html index ef70d3b4..9880a585 100644 --- a/core/template/mobile/Monitoring.html +++ b/core/template/mobile/Monitoring.html @@ -304,10 +304,10 @@ */ const initRebootButton = () => { try { - const btn = widgetRoot.querySelector('.reboot') - if (!btn) return + const rebootBtn = widgetRoot.querySelector('.reboot') + if (!rebootBtn) return - btn.addEventListener('click', () => { + rebootBtn.addEventListener('click', () => { if (confirm("Etes-vous sûr de vouloir redémarrer l'équipement #name# ?")) { jeedom.cmd.execute({ id: '#cmd_reboot_id#' }) } @@ -322,10 +322,10 @@ */ const initPoweroffButton = () => { try { - const btn = widgetRoot.querySelector('.poweroff') - if (!btn) return + const poweroffBtn = widgetRoot.querySelector('.poweroff') + if (!poweroffBtn) return - btn.addEventListener('click', () => { + poweroffBtn.addEventListener('click', () => { if (confirm("Etes-vous sûr de vouloir éteindre l'équipement #name# ?")) { jeedom.cmd.execute({ id: '#cmd_poweroff_id#' }) } @@ -340,13 +340,13 @@ */ const initRefreshButton = () => { try { - const btn = widgetRoot.querySelector('.refresh') - if (!btn) return + const refreshBtn = widgetRoot.querySelector('.refresh') + if (!refreshBtn) return if ('#refresh_id#' !== '') { - btn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) + refreshBtn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) } else { - btn.remove() + refreshBtn.remove() } } catch (e) { console.error('[Monitoring] Error in initRefreshButton:', e) @@ -364,9 +364,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#uptime#id#') - if (!el) return - el.innerHTML = '#uptime#' + const uptimeEl = widgetRoot.querySelector('#uptime#id#') + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring] Error in initUptime:', e) } @@ -379,9 +379,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#network_infos#id#') - if (!el) return - el.innerHTML = '#network_infos#' + const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring] Error in initNetworkInfos:', e) } @@ -394,9 +394,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#network#id#') - if (!el) return - el.innerHTML = '#network#' + const networkEl = widgetRoot.querySelector('#network#id#') + if (!networkEl) return + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring] Error in initNetwork:', e) } @@ -445,16 +445,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#memory_available_percent#id#') - if (!el) return + const memoryEl = widgetRoot.querySelector('#memory_available_percent#id#') + if (!memoryEl) return const value = '#memory_available_percent#' if (value === '') { - el.innerHTML = '#memory#' + memoryEl.innerHTML = '#memory#' return } - el.innerHTML = buildPercentageHTML(value, '#memory_available_percent_colorlow#', '#memory_available_percent_colorhigh#', '#memory# (', '%', true) + memoryEl.innerHTML = buildPercentageHTML(value, '#memory_available_percent_colorlow#', '#memory_available_percent_colorhigh#', '#memory# (', '%', true) } catch (e) { console.error('[Monitoring] Error in initMemory:', e) } @@ -467,16 +467,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#swap_free_percent#id#') - if (!el) return + const swapEl = widgetRoot.querySelector('#swap_free_percent#id#') + if (!swapEl) return const value = '#swap_free_percent#' if (value === '') { - el.innerHTML = '#swap#' + swapEl.innerHTML = '#swap#' return } - el.innerHTML = buildPercentageHTML(value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', '#swap# (', '%', true) + swapEl.innerHTML = buildPercentageHTML(value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', '#swap# (', '%', true) } catch (e) { console.error('[Monitoring] Error in initSwap:', e) } @@ -489,16 +489,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#hdd#id#') - if (!el) return + const hddEl = widgetRoot.querySelector('#hdd#id#') + if (!hddEl) return const value = '#hdd_free_percent#' if (value === '') { - el.innerHTML = '' + hddEl.innerHTML = '' return } - el.innerHTML = buildPercentageHTML(value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', '#hdd# (', '%', true) + hddEl.innerHTML = buildPercentageHTML(value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', '#hdd# (', '%', true) } catch (e) { console.error('[Monitoring] Error in initHDD:', e) } @@ -543,12 +543,12 @@ const dataset = container.dataset const persoId = dataset.persoId - const el = widgetRoot.querySelector('#' + persoId + '_unite#id#') - if (!el) return + const persoEl = widgetRoot.querySelector('#' + persoId + '_unite#id#') + if (!persoEl) return const value = dataset.persoValue if (value === '') { - el.innerHTML = '' + persoEl.innerHTML = '' return } @@ -558,9 +558,9 @@ const color = getColorStyle(val, low, high, false) if (color) { - el.innerHTML = '' + value + '' + dataset.persoUnite + '' + persoEl.innerHTML = '' + value + '' + dataset.persoUnite + '' } else { - el.innerHTML = '' + value + '' + dataset.persoUnite + '' + persoEl.innerHTML = '' + value + '' + dataset.persoUnite + '' } } catch (e) { console.error('[Monitoring] Error in initPerso for', container.dataset?.persoId || 'unknown', ':', e) diff --git a/core/template/mobile/Synology.html b/core/template/mobile/Synology.html index 32cbc321..53f76b98 100644 --- a/core/template/mobile/Synology.html +++ b/core/template/mobile/Synology.html @@ -301,13 +301,13 @@ */ const initIconSSH = () => { try { - const el = widgetRoot.querySelector('#iconSSH#id#') - if (!el) return + const iconSSH = widgetRoot.querySelector('#iconSSH#id#') + if (!iconSSH) return if ('#cnx_ssh#' === 'OK') { - el.innerHTML = '' + iconSSH.innerHTML = '' } else if ('#cnx_ssh#' === 'KO') { - el.innerHTML = '' + iconSSH.innerHTML = '' } } catch (e) { console.error('[Monitoring Syno] Error in initIconSSH:', e) @@ -319,8 +319,8 @@ */ const initIconCron = () => { try { - const el = widgetRoot.querySelector('#iconCron#id#') - if (!el) return + const iconCron = widgetRoot.querySelector('#iconCron#id#') + if (!iconCron) return const isOn = '#cron_status#' === '1' const isCustom = '#cron_status_custom#' === '1' @@ -331,7 +331,7 @@ const customLabel = isCustom ? ' (Custom)' : ' (Default)' const color = isCustom ? '--al-warning-color' : (isOn ? '--al-success-color' : '--al-danger-color') - el.innerHTML = '' + iconCron.innerHTML = '' } catch (e) { console.error('[Monitoring Syno] Error in initIconCron:', e) } @@ -346,10 +346,10 @@ */ const initRebootButton = () => { try { - const btn = widgetRoot.querySelector('.reboot') - if (!btn) return + const rebootBtn = widgetRoot.querySelector('.reboot') + if (!rebootBtn) return - btn.addEventListener('click', () => { + rebootBtn.addEventListener('click', () => { if (confirm("Etes-vous sûr de vouloir redémarrer l'équipement #name# ?")) { jeedom.cmd.execute({ id: '#cmd_reboot_id#' }) } @@ -364,10 +364,10 @@ */ const initPoweroffButton = () => { try { - const btn = widgetRoot.querySelector('.poweroff') - if (!btn) return + const poweroffBtn = widgetRoot.querySelector('.poweroff') + if (!poweroffBtn) return - btn.addEventListener('click', () => { + poweroffBtn.addEventListener('click', () => { if (confirm("Etes-vous sûr de vouloir éteindre l'équipement #name# ?")) { jeedom.cmd.execute({ id: '#cmd_poweroff_id#' }) } @@ -382,13 +382,13 @@ */ const initRefreshButton = () => { try { - const btn = widgetRoot.querySelector('.refresh') - if (!btn) return + const refreshBtn = widgetRoot.querySelector('.refresh') + if (!refreshBtn) return if ('#refresh_id#' !== '') { - btn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) + refreshBtn.addEventListener('click', () => jeedom.cmd.execute({ id: '#refresh_id#' })) } else { - btn.remove() + refreshBtn.remove() } } catch (e) { console.error('[Monitoring Syno] Error in initRefreshButton:', e) @@ -406,9 +406,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#uptime#id#') - if (!el) return - el.innerHTML = '#uptime#' + const uptimeEl = widgetRoot.querySelector('#uptime#id#') + if (!uptimeEl) return + uptimeEl.innerHTML = '#uptime#' } catch (e) { console.error('[Monitoring Syno] Error in initUptime:', e) } @@ -421,9 +421,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#network_infos#id#') - if (!el) return - el.innerHTML = '#network_infos#' + const networkInfosEl = widgetRoot.querySelector('#network_infos#id#') + if (!networkInfosEl) return + networkInfosEl.innerHTML = '#network_infos#' } catch (e) { console.error('[Monitoring Syno] Error in initNetworkInfos:', e) } @@ -436,9 +436,9 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#network#id#') - if (!el) return - el.innerHTML = '#network#' + const networkEl = widgetRoot.querySelector('#network#id#') + if (!networkEl) return + networkEl.innerHTML = '#network#' } catch (e) { console.error('[Monitoring Syno] Error in initNetwork:', e) } @@ -487,12 +487,12 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#memory_available_percent#id#') - if (!el) return + const memoryEl = widgetRoot.querySelector('#memory_available_percent#id#') + if (!memoryEl) return const value = '#memory_available_percent#' if (value === '') { - el.innerHTML = '#memory#' + memoryEl.innerHTML = '#memory#' return } @@ -509,16 +509,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#swap_free_percent#id#') - if (!el) return + const swapEl = widgetRoot.querySelector('#swap_free_percent#id#') + if (!swapEl) return const value = '#swap_free_percent#' if (value === '') { - el.innerHTML = '#swap#' + swapEl.innerHTML = '#swap#' return } - el.innerHTML = buildPercentageHTML(value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', '#swap# (', '%', true) + swapEl.innerHTML = buildPercentageHTML(value, '#swap_free_percent_colorlow#', '#swap_free_percent_colorhigh#', '#swap# (', '%', true) } catch (e) { console.error('[Monitoring Syno] Error in initSwap:', e) } @@ -531,16 +531,16 @@ try { if ('#cnx_ssh#' !== 'OK' && '#cnx_ssh#' !== 'No') return - const el = widgetRoot.querySelector('#hdd#id#') - if (!el) return + const hddEl = widgetRoot.querySelector('#hdd#id#') + if (!hddEl) return const value = '#hdd_free_percent#' if (value === '') { - el.innerHTML = '' + hddEl.innerHTML = '' return } - el.innerHTML = buildPercentageHTML(value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', '#hdd# (', '%', true) + hddEl.innerHTML = buildPercentageHTML(value, '#hdd_free_percent_colorlow#', '#hdd_free_percent_colorhigh#', '#hdd# (', '%', true) } catch (e) { console.error('[Monitoring Syno] Error in initHDD:', e) } @@ -585,8 +585,8 @@ const dataset = container.dataset const synoId = dataset.synoId - const el = widgetRoot.querySelector('#' + synoId + '_unit#id#') - if (!el) return + const synoVolumeEl = widgetRoot.querySelector('#' + synoId + '_unit#id#') + if (!synoVolumeEl) return const value = dataset.synoValue const valuePercent = dataset.synoValuePercent @@ -598,7 +598,7 @@ } if (!valuePercent || valuePercent === '' || valuePercent.startsWith('#')) { - el.innerHTML = '' + value + '' + synoVolumeEl.innerHTML = '' + value + '' return } @@ -607,7 +607,7 @@ const high = parseFloat(dataset.synoHigh) const color = getColorStyle(val, low, high, true) - el.innerHTML = value + ' (' + valuePercent + '%)' + synoVolumeEl.innerHTML = value + ' (' + valuePercent + '%)' } catch (e) { console.error('[Monitoring Syno] Error in initSynoVolume for', container.dataset?.synoId || 'unknown', ':', e) } @@ -623,12 +623,12 @@ const dataset = container.dataset const persoId = dataset.persoId - const el = widgetRoot.querySelector('#' + persoId + '_unite#id#') - if (!el) return + const persoEl = widgetRoot.querySelector('#' + persoId + '_unite#id#') + if (!persoEl) return const value = dataset.persoValue if (value === '') { - el.innerHTML = '' + persoEl.innerHTML = '' return } @@ -638,9 +638,9 @@ const color = getColorStyle(val, low, high, false) if (color) { - el.innerHTML = '' + value + '' + dataset.persoUnite + '' + persoEl.innerHTML = '' + value + '' + dataset.persoUnite + '' } else { - el.innerHTML = '' + value + '' + dataset.persoUnite + '' + persoEl.innerHTML = '' + value + '' + dataset.persoUnite + '' } } catch (e) { console.error('[Monitoring Syno] Error in initPerso for', container.dataset?.persoId || 'unknown', ':', e) From a6ce8e58fbb908a1bc29a17eb7f3b6f6c79a487e Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:57:23 +0100 Subject: [PATCH 77/84] update Syno templates --- core/template/dashboard/Synology.html | 1602 ++++++++++++------------- core/template/mobile/Synology.html | 1370 ++++++++++----------- 2 files changed, 1486 insertions(+), 1486 deletions(-) diff --git a/core/template/dashboard/Synology.html b/core/template/dashboard/Synology.html index a38cf0f7..d2b6bfb9 100644 --- a/core/template/dashboard/Synology.html +++ b/core/template/dashboard/Synology.html @@ -1,803 +1,803 @@
- -
-
- - - - - - - - -
-
- #name_display# #object_name# - #name_display# #object_name# -
-
- - - -
-
-
-
- #distri_name_icon# - #distri_name# -
-
- #uptime_icon# - -
-
- #load_avg_icon# - -
-
- #memory_icon# - -
-
- #swap_icon# - -
-
- #network_infos_icon# - -
-
- #network_icon# - -
- - #multi_network_cards# -
- #hdd_icon# - -
-
- #syno_hddv2_icon# - -
-
- #syno_hddv3_icon# - -
-
- #syno_hddv4_icon# - -
-
- #syno_hddusb_icon# - -
-
- #syno_hddesata_icon# - -
-
- #cpu_icon# - -
-
- #perso1_icon# - -
-
- #perso2_icon# - -
-
- #perso3_icon# - -
-
- #perso4_icon# - -
-
- #divGraphInfo# - + data-eqType="#eqType#" data-eqLogic_id="#id#" data-eqLogic_uid="#uid#" data-version="#version#" + data-translate-category="#translate_category#" data-category="#category#" data-tags="#tags#" + style="width: #width#;height: #height#;#style#;"> + +
+
+ + + + + + + + +
+
+ #name_display# #object_name# + #name_display# #object_name# +
+
+ + + +
+
+
+
+ #distri_name_icon# + #distri_name# +
+
+ #uptime_icon# + +
+
+ #load_avg_icon# + +
+
+ #memory_icon# + +
+
+ #swap_icon# + +
+
+ #network_infos_icon# + +
+
+ #network_icon# + +
+ + #multi_network_cards# +
+ #hdd_icon# + +
+
+ #syno_hddv2_icon# + +
+
+ #syno_hddv3_icon# + +
+
+ #syno_hddv4_icon# + +
+
+ #syno_hddusb_icon# + +
+
+ #syno_hddesata_icon# + +
+
+ #cpu_icon# + +
+
+ #perso1_icon# + +
+
+ #perso2_icon# + +
+
+ #perso3_icon# + +
+
+ #perso4_icon# + +
+
+ #divGraphInfo# +
\ No newline at end of file diff --git a/core/template/mobile/Synology.html b/core/template/mobile/Synology.html index 53f76b98..8e9cc980 100644 --- a/core/template/mobile/Synology.html +++ b/core/template/mobile/Synology.html @@ -1,687 +1,687 @@
- - - - - - - - - - - - - - - #name_display# - - - - - - - - -
-
- #distri_name_icon# - #distri_name# -
-
- #uptime_icon# - -
-
- #load_avg_icon# - -
-
- #memory_icon# - -
-
- #swap_icon# - -
-
- #network_infos_icon# - -
-
- #network_icon# - -
- - #multi_network_cards# -
- #hdd_icon# - -
-
- #syno_v2_icon# - -
-
- #syno_v3_icon# - -
-
- #syno_v4_icon# - -
-
- #syno_usb_icon# - -
-
- #syno_esata_icon# - -
-
- #cpu_icon# - -
-
- #perso1_icon# - -
-
- #perso2_icon# - -
-
- #perso3_icon# - -
-
- #perso4_icon# - -
-
- + data-eqLogic_uid="#uid#" data-translate-category="#translate_category#" data-category="#category#" + data-tags="#tags#" style="#style#"> + + + + + + + + + + + + + + + #name_display# + + + + + + + + +
+
+ #distri_name_icon# + #distri_name# +
+
+ #uptime_icon# + +
+
+ #load_avg_icon# + +
+
+ #memory_icon# + +
+
+ #swap_icon# + +
+
+ #network_infos_icon# + +
+
+ #network_icon# + +
+ + #multi_network_cards# +
+ #hdd_icon# + +
+
+ #syno_v2_icon# + +
+
+ #syno_v3_icon# + +
+
+ #syno_v4_icon# + +
+
+ #syno_usb_icon# + +
+
+ #syno_esata_icon# + +
+
+ #cpu_icon# + +
+
+ #perso1_icon# + +
+
+ #perso2_icon# + +
+
+ #perso3_icon# + +
+
+ #perso4_icon# + +
+
+
\ No newline at end of file From 7019bb0241b7ba30eb32aa0b188140a2113eeb52 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:23:50 +0100 Subject: [PATCH 78/84] Fix SSH host select initialization timing Updated the SSH host select initialization in Monitoring.js to ensure event listeners are attached only after options are loaded asynchronously. Bumped plugin version to 3.4.3. --- desktop/js/Monitoring.js | 19 +++++++++++-------- plugin_info/info.json | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 88b4f41b..46d0186f 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -396,14 +396,17 @@ function printEqLogic(_eqLogic) { } } - buildSelectHost(_eqLogic.configuration.SSHHostId) - - // Toggle add/edit button based on SSH host selection - const sshHostSelect = document.querySelector('.sshmanagerHelper[data-helper="list"]') - if (sshHostSelect) { - sshHostSelect.addEventListener('change', toggleSSHButtons) - // Initialize button display - toggleSSHButtons({ currentTarget: sshHostSelect }) + // Build SSH host select and attach listener after options are loaded + const buildPromise = buildSelectHost(_eqLogic.configuration.SSHHostId) + if (buildPromise && buildPromise.then) { + buildPromise.then(() => { + const sshHostSelect = document.querySelector('.sshmanagerHelper[data-helper="list"]') + if (sshHostSelect) { + sshHostSelect.addEventListener('change', toggleSSHButtons) + // Initialize button display + toggleSSHButtons({ currentTarget: sshHostSelect }) + } + }) } } diff --git a/plugin_info/info.json b/plugin_info/info.json index f68d7c2d..202af5de 100644 --- a/plugin_info/info.json +++ b/plugin_info/info.json @@ -1,7 +1,7 @@ { "id": "Monitoring", "name": "Monitoring", - "pluginVersion": "3.4.2", + "pluginVersion": "3.4.3", "description": { "fr_FR": "Plugin permettant le monitoring des équipements locaux et distants (via SSH). Le plugin affichera les informations systèmes d'équipements sous Linux ou Synology (Distribution, CPU, Mémoire, Disques, Swap).", "en_US": "Plugin to monitor local and remote equipments (through SSH). The plugin will display system informations from Linux or Synology (Distribution, CPU, Memory, Disks, Swap).", From e271727114fe5c6de54acec99df9a769bfcec6e8 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:29:20 +0100 Subject: [PATCH 79/84] Refactor SSH host select event handling in Monitoring.js Improved the logic for attaching the change event listener to the SSH host select element by ensuring any existing listener is removed before adding a new one. Also, ensured the toggleSSHButtons function is called after the select is populated, handling both promise and non-promise cases from buildSelectHost. --- desktop/js/Monitoring.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 46d0186f..354fb74c 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -396,17 +396,26 @@ function printEqLogic(_eqLogic) { } } - // Build SSH host select and attach listener after options are loaded + // Build SSH host select const buildPromise = buildSelectHost(_eqLogic.configuration.SSHHostId) - if (buildPromise && buildPromise.then) { - buildPromise.then(() => { - const sshHostSelect = document.querySelector('.sshmanagerHelper[data-helper="list"]') - if (sshHostSelect) { - sshHostSelect.addEventListener('change', toggleSSHButtons) - // Initialize button display + + // Toggle add/edit button based on SSH host selection + const sshHostSelect = document.querySelector('.sshmanagerHelper[data-helper="list"]') + if (sshHostSelect) { + // Remove existing listener to avoid duplicates + sshHostSelect.removeEventListener('change', toggleSSHButtons) + // Attach listener + sshHostSelect.addEventListener('change', toggleSSHButtons) + + // Initialize button display after select is populated + if (buildPromise && buildPromise.then) { + buildPromise.then(() => { toggleSSHButtons({ currentTarget: sshHostSelect }) - } - }) + }) + } else { + // Fallback if buildSelectHost didn't return a promise + toggleSSHButtons({ currentTarget: sshHostSelect }) + } } } From 607fe51a23db03e0cec3194ceac9384f6a2607e5 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:35:36 +0100 Subject: [PATCH 80/84] Replace unseen/seen with style.display for SSH buttons Refactored toggleSSHButtons to use direct style.display assignments instead of unseen/seen methods for showing and hiding the add and edit buttons. --- desktop/js/Monitoring.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index 354fb74c..e137312f 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -429,12 +429,12 @@ function toggleSSHButtons(event) { if (selectedValue && selectedValue !== '') { // Host selected → show edit, hide add - addBtn?.unseen() - editBtn?.seen() + if (addBtn) addBtn.style.display = 'none' + if (editBtn) editBtn.style.display = 'block' } else { // No host selected → show add, hide edit - addBtn?.seen() - editBtn?.unseen() + if (addBtn) addBtn.style.display = 'block' + if (editBtn) editBtn.style.display = 'none' } } From a0f1035354d82200605447fda761706100fa16ec Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:38:11 +0100 Subject: [PATCH 81/84] Improve robustness of toggleSSHButtons event handling Updated the toggleSSHButtons function to more reliably extract the selected value from the event object, improving compatibility with different event sources. --- desktop/js/Monitoring.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index e137312f..fa605892 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -423,7 +423,7 @@ function printEqLogic(_eqLogic) { * Toggle between add and edit SSH buttons based on selection */ function toggleSSHButtons(event) { - const selectedValue = event.currentTarget.value + const selectedValue = event.target?.value ?? event.currentTarget?.value ?? event.value const addBtn = document.querySelector('.sshmanagerHelper[data-helper="add"]') const editBtn = document.querySelector('.sshmanagerHelper[data-helper="edit"]') From 94bf678b1ea487b70417abf1afc5989efa970e80 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:55:22 +0100 Subject: [PATCH 82/84] Improve SSH button toggle logic in Monitoring.js Refactored the toggleSSHButtons function to accept either an event or a direct SSHHostId value, improving initialization and event handling. This ensures correct button display when the SSH host select is populated asynchronously or synchronously. --- desktop/js/Monitoring.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/desktop/js/Monitoring.js b/desktop/js/Monitoring.js index fa605892..0e64252e 100644 --- a/desktop/js/Monitoring.js +++ b/desktop/js/Monitoring.js @@ -407,23 +407,39 @@ function printEqLogic(_eqLogic) { // Attach listener sshHostSelect.addEventListener('change', toggleSSHButtons) - // Initialize button display after select is populated + // Initialize button display - pass the value directly instead of waiting if (buildPromise && buildPromise.then) { buildPromise.then(() => { - toggleSSHButtons({ currentTarget: sshHostSelect }) + toggleSSHButtons(_eqLogic.configuration.SSHHostId) }) } else { // Fallback if buildSelectHost didn't return a promise - toggleSSHButtons({ currentTarget: sshHostSelect }) + toggleSSHButtons(_eqLogic.configuration.SSHHostId) } } } /** * Toggle between add and edit SSH buttons based on selection + * @param {Event|string|number} eventOrValue - Either a change event or a direct value (SSHHostId) */ -function toggleSSHButtons(event) { - const selectedValue = event.target?.value ?? event.currentTarget?.value ?? event.value +function toggleSSHButtons(eventOrValue) { + let selectedValue + + // Check if it's a direct value (string/number) or an event object + if (typeof eventOrValue === 'string' || typeof eventOrValue === 'number') { + selectedValue = eventOrValue + } else if (eventOrValue?.target || eventOrValue?.currentTarget) { + // It's an event, extract value from it + selectedValue = eventOrValue.target?.value ?? eventOrValue.currentTarget?.value ?? eventOrValue.value + } + + // If still no value, read directly from the select element as fallback + if (!selectedValue) { + const sshHostSelect = document.querySelector('.sshmanagerHelper[data-helper="list"]') + selectedValue = sshHostSelect?.value + } + const addBtn = document.querySelector('.sshmanagerHelper[data-helper="add"]') const editBtn = document.querySelector('.sshmanagerHelper[data-helper="edit"]') From 3c1bc7d9ff0c0525a2d83f5c2ba63c6cc2b7f017 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 22:15:23 +0100 Subject: [PATCH 83/84] Use single quotes in tendance icon HTML output Replaces double quotes with single quotes in the HTML string for the tendance icon to ensure consistency and avoid potential conflicts in attribute quoting. --- core/class/Monitoring.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/class/Monitoring.class.php b/core/class/Monitoring.class.php index 9909f35e..9eadd93a 100644 --- a/core/class/Monitoring.class.php +++ b/core/class/Monitoring.class.php @@ -2627,7 +2627,7 @@ public function getCmdReplace(string $cmdName, array $cmdOptions, &$replace) { $replace[$cmdNamePrefix . '_averageHistory#'] = $isCmdObject ? $cmd->getConfiguration($cmdName . '_averageHistory') : '-'; $replace[$cmdNamePrefix . '_minHistory#'] = $isCmdObject ? $cmd->getConfiguration($cmdName . '_minHistory') : '-'; $replace[$cmdNamePrefix . '_maxHistory#'] = $isCmdObject ? $cmd->getConfiguration($cmdName . '_maxHistory') : '-'; - $replace[$cmdNamePrefix . '_tendance#'] = ($isCmdObject && $cmd->getConfiguration($cmdName . '_tendance', '') !== '') ? ' ' : ''; + $replace[$cmdNamePrefix . '_tendance#'] = ($isCmdObject && $cmd->getConfiguration($cmdName . '_tendance', '') !== '') ? ' getConfiguration($cmdName . '_tendance') . '\'>' : ''; } ]; From 822b538d73b2e2492af6644dab5320c3592d0e64 Mon Sep 17 00:00:00 2001 From: Olivier <16240457+TiTidom-RC@users.noreply.github.com> Date: Thu, 8 Jan 2026 22:29:44 +0100 Subject: [PATCH 84/84] Escape HTML attributes in tendance icon output Updated the tendance icon HTML generation to use escaped double quotes for attribute values, preventing conflicts with surrounding quotes and improving HTML safety. --- core/class/Monitoring.class.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/class/Monitoring.class.php b/core/class/Monitoring.class.php index 9eadd93a..3d3f2ef7 100644 --- a/core/class/Monitoring.class.php +++ b/core/class/Monitoring.class.php @@ -2627,7 +2627,11 @@ public function getCmdReplace(string $cmdName, array $cmdOptions, &$replace) { $replace[$cmdNamePrefix . '_averageHistory#'] = $isCmdObject ? $cmd->getConfiguration($cmdName . '_averageHistory') : '-'; $replace[$cmdNamePrefix . '_minHistory#'] = $isCmdObject ? $cmd->getConfiguration($cmdName . '_minHistory') : '-'; $replace[$cmdNamePrefix . '_maxHistory#'] = $isCmdObject ? $cmd->getConfiguration($cmdName . '_maxHistory') : '-'; - $replace[$cmdNamePrefix . '_tendance#'] = ($isCmdObject && $cmd->getConfiguration($cmdName . '_tendance', '') !== '') ? ' getConfiguration($cmdName . '_tendance') . '\'>' : ''; + // Utiliser htmlspecialchars pour échapper les attributs HTML afin d'éviter les conflits avec les guillemets + $tendanceIcon = ($isCmdObject && $cmd->getConfiguration($cmdName . '_tendance', '') !== '') + ? ' getConfiguration($cmdName . '_tendance') . '">' + : ''; + $replace[$cmdNamePrefix . '_tendance#'] = $tendanceIcon; } ];
{{Nom}}{{Nom}} {{Actif}} {{Visible}} {{Type}}{{Hôte SSH}}{{Hôte SSH}} {{SSH Status}} {{Cron Status}}{{Uptime}}{{Uptime}} {{Charge 1min}} {{Charge 5min}} {{Charge 15min}}{{Adresse IP}}{{Dernière Communication}}{{Adresse IP}}{{Dernière Communication}}