diff --git a/pve-mod-gui-sensors.sh b/pve-mod-gui-sensors.sh index 7c012be..28427cb 100644 --- a/pve-mod-gui-sensors.sh +++ b/pve-mod-gui-sensors.sh @@ -664,66 +664,18 @@ Ext.define('PVE.mod.TempHelper', {\n\ fi if [ $ENABLE_NVME_TEMP = true ]; then + local TEMP_JS_FILE="/tmp/nvme_widget.js" + generate_nvme_widget $TEMP_JS_FILE + sed -i "/^Ext.define('PVE.node.StatusView',/ { - :a; + :a /items:/!{N;ba;} - :b; + :b /'thermal.*},/!{N;bb;} - a\ - \\ - {\n\ - itemId: 'thermalNvme',\n\ - colspan: 2,\n\ - printBar: false,\n\ - title: gettext('NVMe Thermal State'),\n\ - iconCls: 'fa fa-fw fa-thermometer-half',\n\ - textField: 'sensorsOutput',\n\ - renderer: function(value) {\n\ - // sensors configuration\n\ - const addressPrefix = \"nvme-pci-\";\n\ - const sensorName = \"Composite\";\n\ - const tempHelper = Ext.create('PVE.mod.TempHelper', $tempHelperCtorParams);\n\ - // display configuration\n\ - const itemsPerRow = ${NVME_ITEMS_PER_ROW};\n\ - // ---\n\ - let objValue;\n\ - try {\n\ - objValue = JSON.parse(value) || {};\n\ - } catch(e) {\n\ - objValue = {};\n\ - }\n\ - const nvmeKeys = Object.keys(objValue).filter(item => String(item).startsWith(addressPrefix)).sort();\n\ - let temps = [];\n\ - nvmeKeys.forEach((nvmeKey, index) => {\n\ - try {\n\ - let tempVal = NaN, tempMax = NaN, tempCrit = NaN;\n\ - Object.keys(objValue[nvmeKey][sensorName]).forEach((secondLevelKey) => {\n\ - if (secondLevelKey.endsWith('_input')) {\n\ - tempVal = tempHelper.getTemp(parseFloat(objValue[nvmeKey][sensorName][secondLevelKey]));\n\ - } else if (secondLevelKey.endsWith('_max')) {\n\ - tempMax = tempHelper.getTemp(parseFloat(objValue[nvmeKey][sensorName][secondLevelKey]));\n\ - } else if (secondLevelKey.endsWith('_crit')) {\n\ - tempCrit = tempHelper.getTemp(parseFloat(objValue[nvmeKey][sensorName][secondLevelKey]));\n\ - }\n\ - });\n\ - if (!isNaN(tempVal)) {\n\ - let tempStyle = '';\n\ - if (!isNaN(tempMax) && tempVal >= tempMax) {\n\ - tempStyle = 'color: #FFC300; font-weight: bold;';\n\ - }\n\ - if (!isNaN(tempCrit) && tempVal >= tempCrit) {\n\ - tempStyle = 'color: red; font-weight: bold;';\n\ - }\n\ - const tempStr = \`Drive \${index + 1}: \${Ext.util.Format.number(tempVal, '0.0')}\${tempHelper.getUnit()}\`;\n\ - temps.push(tempStr);\n\ - }\n\ - } catch(e) { /*_*/ }\n\ - });\n\ - const result = temps.map((strTemp, index, arr) => { return strTemp + (index + 1 < arr.length ? ((index + 1) % itemsPerRow === 0 ? '
' : ' | ') : ''); });\n\ - return '
' + (result.length > 0 ? result.join('') : 'N/A') + '
';\n\ - }\n\ - }, - }" "$PVE_MANAGER_LIB_JS_FILE" + r $TEMP_JS_FILE + }" "$PVE_MANAGER_LIB_JS_FILE" + + rm $TEMP_JS_FILE fi if [ $ENABLE_NVME_TEMP = true -o $ENABLE_HDD_TEMP = true ]; then @@ -845,6 +797,69 @@ Ext.define('PVE.mod.TempHelper', {\n\ fi } +generate_nvme_widget() { + #region nvme widget heredoc + cat > "$1" <<'EOF' + { + itemId: 'thermalNvme', + colspan: 2, + printBar: false, + title: gettext('NVMe Thermal State'), + iconCls: 'fa fa-fw fa-thermometer-half', + textField: 'sensorsOutput', + renderer: function(value) { + // sensors configuration + const addressPrefix = "nvme-pci-"; + const sensorName = "Composite"; + const tempHelper = Ext.create('PVE.mod.TempHelper', $tempHelperCtorParams); + // display configuration + const itemsPerRow = ${NVME_ITEMS_PER_ROW}; + // --- + let objValue; + try { + objValue = JSON.parse(value) || {}; + } catch(e) { + objValue = {}; + } + const nvmeKeys = Object.keys(objValue).filter(item => String(item).startsWith(addressPrefix)).sort(); + let temps = []; + nvmeKeys.forEach((nvmeKey, index) => { + try { + let tempVal = NaN, tempMax = NaN, tempCrit = NaN; + Object.keys(objValue[nvmeKey][sensorName]).forEach((secondLevelKey) => { + if (secondLevelKey.endsWith('_input')) { + tempVal = tempHelper.getTemp(parseFloat(objValue[nvmeKey][sensorName][secondLevelKey])); + } else if (secondLevelKey.endsWith('_max')) { + tempMax = tempHelper.getTemp(parseFloat(objValue[nvmeKey][sensorName][secondLevelKey])); + } else if (secondLevelKey.endsWith('_crit')) { + tempCrit = tempHelper.getTemp(parseFloat(objValue[nvmeKey][sensorName][secondLevelKey])); + } + }); + if (!isNaN(tempVal)) { + let tempStyle = ''; + if (!isNaN(tempMax) && tempVal >= tempMax) { + tempStyle = 'color: #FFC300; font-weight: bold;'; + } + if (!isNaN(tempCrit) && tempVal >= tempCrit) { + tempStyle = 'color: red; font-weight: bold;'; + } + const tempStr = `Drive ${index + 1}: ${Ext.util.Format.number(tempVal, '0.0')}${tempHelper.getUnit()}`; + temps.push(tempStr); + } + } catch(e) { /*_*/ } + }); + const result = temps.map((strTemp, index, arr) => { return strTemp + (index + 1 < arr.length ? ((index + 1) % itemsPerRow === 0 ? '
' : ' | ') : ''); }); + return '
' + (result.length > 0 ? result.join('') : 'N/A') + '
'; + } + }, +EOF + #endregion nvme widget heredoc + if [[ $? -ne 0 ]]; then + echo "Error: Failed to generate nvme widget code" >&2 + exit 1 + fi +} + generate_fan_widget() { #region fan widget heredoc cat > "$1" <<'EOF'