diff --git a/Makefile b/Makefile index 09e4e8a..21b41c4 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_VERSION:=0.3 -PKG_RELEASE:=5 +PKG_RELEASE:=6 LUCI_TITLE:=Information about connected disk devices (partitions, filesystems, SMART). LUCI_DEPENDS:=+fdisk +smartmontools +smartmontools-drivedb LUCI_PKGARCH:=all diff --git a/README.md b/README.md index 7ee982b..01a3353 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,16 @@ OpenWrt >= 19.07. **Installation notes:** - wget --no-check-certificate -O /tmp/luci-app-disks-info_0.3-5_all.ipk https://github.com/gSpotx2f/luci-app-disks-info/raw/master/packages/19.07/luci-app-disks-info_0.3-5_all.ipk - opkg install /tmp/luci-app-disks-info_0.3-5_all.ipk - rm /tmp/luci-app-disks-info_0.3-5_all.ipk + wget --no-check-certificate -O /tmp/luci-app-disks-info_0.3-6_all.ipk https://github.com/gSpotx2f/luci-app-disks-info/raw/master/packages/19.07/luci-app-disks-info_0.3-6_all.ipk + opkg install /tmp/luci-app-disks-info_0.3-6_all.ipk + rm /tmp/luci-app-disks-info_0.3-6_all.ipk /etc/init.d/rpcd restart **i18n-ru:** - wget --no-check-certificate -O /tmp/luci-i18n-disks-info-ru_0.3-5_all.ipk https://github.com/gSpotx2f/luci-app-disks-info/raw/master/packages/19.07/luci-i18n-disks-info-ru_0.3-5_all.ipk - opkg install /tmp/luci-i18n-disks-info-ru_0.3-5_all.ipk - rm /tmp/luci-i18n-disks-info-ru_0.3-5_all.ipk + wget --no-check-certificate -O /tmp/luci-i18n-disks-info-ru_0.3-6_all.ipk https://github.com/gSpotx2f/luci-app-disks-info/raw/master/packages/19.07/luci-i18n-disks-info-ru_0.3-6_all.ipk + opkg install /tmp/luci-i18n-disks-info-ru_0.3-6_all.ipk + rm /tmp/luci-i18n-disks-info-ru_0.3-6_all.ipk **Screenshots:** diff --git a/htdocs/luci-static/resources/view/disks-info.js b/htdocs/luci-static/resources/view/disks-info.js index 4018ca3..b978008 100644 --- a/htdocs/luci-static/resources/view/disks-info.js +++ b/htdocs/luci-static/resources/view/disks-info.js @@ -4,7 +4,11 @@ document.head.append(E('style', {'type': 'text/css'}, ` -.label-status { +:root { + --app-disks-info-dark-font-color: #2e2e2e; + --app-disks-info-light-font-color: #fff; +} +.disks-info-label-status { display: inline; margin: 0 4px !important; padding: 1px 4px; @@ -14,23 +18,30 @@ document.head.append(E('style', {'type': 'text/css'}, text-transform: uppercase; font-weight: bold; line-height: 1.6em; - color: #fff !important; } -.ok { +.disks-info-ok { background-color: #2ea256 !important; + color: var(--app-disks-info-light-font-color) !important; } -.warn { +.disks-info-warn { background-color: #fff7e2 !important; + color: var(--app-disks-info-dark-font-color) !important; } -.err { +.disks-info-warn .td { + color: var(--app-disks-info-dark-font-color) !important; +} +.disks-info-warn td { + color: var(--app-disks-info-dark-font-color) !important; +} +.disks-info-err { background-color: #ff4e54 !important; - color: #fff !important; + color: var(--app-disks-info-light-font-color) !important; } -.err .td { - color: #fff !important; +.disks-info-err .td { + color: var(--app-disks-info-light-font-color) !important; } -.err td { - color: #fff !important; +.disks-info-err td { + color: var(--app-disks-info-light-font-color) !important; } `)); @@ -61,9 +72,15 @@ return L.view.extend({ let num = document.getElementById('logging_interval_value' + deviceNormalized).value; let pSave = document.getElementById('logging_interval_type' + deviceNormalized).checked; + if(/^[0-9]{1,2}$/.test(num) && Number(num) > 0) { + num = String(Number(num)); + } else { + return; + }; + return fs.exec('/usr/sbin/smartctl', [ '-l', 'scttempint,' + (pSave ? num + ',p' : num), device ] - ).then((res) => { + ).then(res => { window.location.reload(); }).catch(e => ui.addNotification(null, E('p', {}, e.message))); }, @@ -175,7 +192,7 @@ return L.view.extend({ tr.append( E('div', { 'class': (i === 5 && parseInt(fields[i]) >= this.fsSpaceWarning) ? - 'td left warn' : 'td left', + 'td left disks-info-warn' : 'td left', 'data-title': dfTableTitles[i], }, (i === 5) ? E('div', { @@ -218,8 +235,8 @@ return L.view.extend({ createSmartTable: function(smartObject) { let smartStatusLabel = (smartObject.smart_status.passed) ? - E('span', { 'class': 'label-status ok' }, _('passed')) : - E('span', { 'class': 'label-status err' }, _('failed')); + E('span', { 'class': 'disks-info-label-status disks-info-ok' }, _('passed')) : + E('span', { 'class': 'disks-info-label-status disks-info-err' }, _('failed')); let smartStatus = E('h5', { 'style': 'width:100% !important; text-align:center !important' }, [ _('SMART overall-health self-assessment test result:'), @@ -240,10 +257,10 @@ return L.view.extend({ for(let attr of smartObject.ata_smart_attributes.table) { let tempValue; - let lineStyle = (attr.value <= attr.thresh) ? 'tr err' : - (this.smartCriticalAttrs.includes(attr.id) && attr.raw.value > 0) ? 'tr warn' : + let lineStyle = (attr.value <= attr.thresh) ? 'tr disks-info-err' : + (this.smartCriticalAttrs.includes(attr.id) && attr.raw.value > 0) ? 'tr disks-info-warn' : (this.smartTempAttrs.includes(attr.id) && +(attr.raw.string.split(' ')[0]) >= this.diskTempWarning) ? - 'tr warn' : 'tr'; + 'tr disks-info-warn' : 'tr'; smartAttrsTable.append( E('div', { @@ -285,13 +302,15 @@ return L.view.extend({ createErrorLog: function(table) { let errorLogTable = E('div', { 'class': 'table' }, E('div', { 'class': 'tr table-titles' }, [ - E('div', { 'class': 'th left', 'style':'min-width:33%' }, _('Lifetime hours')), + E('div', { 'class': 'th left', 'style':'min-width:16%' }, _('Error number')), + E('div', { 'class': 'th left', 'style':'min-width:17%' }, _('Lifetime hours')), E('div', { 'class': 'th left' }, _('Description')), ]) ); for(let errObj of table) { errorLogTable.append( E('div', { 'class': 'tr' }, [ + E('div', { 'class': 'td left' }, errObj.error_number), E('div', { 'class': 'td left' }, errObj.lifetime_hours), E('div', { 'class': 'td left' }, errObj.error_description), ]) @@ -311,8 +330,8 @@ return L.view.extend({ E('div', { 'class': 'table' }, [ E('div', { 'class': (smartObject.temperature.current >= smartObject.temperature.op_limit_max) ? - 'tr err' : (smartObject.temperature.current >= this.diskTempWarning) ? - 'tr warn' : 'tr', + 'tr disks-info-err' : (smartObject.temperature.current >= this.diskTempWarning) ? + 'tr disks-info-warn' : 'tr', }, [ E('div', { 'class': 'td left', 'style':'min-width:33%' }, _('Current') + ':'), E('div', { 'class': 'td left' }, ('current' in smartObject.temperature) ? @@ -360,6 +379,13 @@ return L.view.extend({ let dataSize = smartObject.ata_sct_temperature_history.size; let tempData = smartObject.ata_sct_temperature_history.table; let dataUnits = []; + let tempMin = tempData.reduce( + (min, current) => (current < min && current !== null) ? current : min, + Infinity); + let tempMax = tempData.reduce( + (max, current) => (current > max && current !== null) ? current : max, + -Infinity); + let tempDiff = tempMax - tempMin; let i = dataSize - 1; while(i >= 0) { @@ -375,12 +401,11 @@ return L.view.extend({ let svgWidth = 900; let svgHeight = 300; - let tempValueMul = 3; // 1C == 3px - let tempOffset = 0; // lowest temp value: 0C - let tempStep = 5; // 5C step - let timeStep = svgWidth / dataSize; - let timeLineInterval = Math.ceil(dataSize / 32); // 4 intervals (5 x 4 = 20 min) - + let tempValueMul = (tempDiff >= 60) ? 3 : Math.round(svgHeight / (tempDiff + 20)); // 1°C = "tempValueMul"px + let tempMinimalValue = (tempMin > 10) ? tempMin - 10 : 0; + let tempAxisStep = (tempDiff >= 60) ? 6 : (tempDiff >= 30) ? 4 : 2; + let timeAxisStep = svgWidth / dataSize; + let timeAxisInterval = Math.ceil(dataSize / 32); let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); @@ -394,9 +419,9 @@ return L.view.extend({ for(let i = 0; i < dataSize; i++) { tempPoints.push([ - i * timeStep, + i * timeAxisStep, (dataUnits[i][1] != null) ? - (svgHeight - (dataUnits[i][1] - tempOffset) * tempValueMul) : + (svgHeight - (dataUnits[i][1] - tempMinimalValue) * tempValueMul) : svgHeight * 2 ]); }; @@ -407,36 +432,36 @@ return L.view.extend({ // temperature warning let lineW = document.createElementNS('http://www.w3.org/2000/svg', 'line'); lineW.setAttribute('x1', 0); - lineW.setAttribute('y1', svgHeight - (this.diskTempWarning - tempOffset) * tempValueMul); + lineW.setAttribute('y1', svgHeight - (this.diskTempWarning - tempMinimalValue) * tempValueMul); lineW.setAttribute('x2', '100%'); - lineW.setAttribute('y2', svgHeight - (this.diskTempWarning - tempOffset) * tempValueMul); + lineW.setAttribute('y2', svgHeight - (this.diskTempWarning - tempMinimalValue) * tempValueMul); lineW.setAttribute('style', 'stroke:orange; stroke-width:0.8'); svg.appendChild(lineW); // temperature critical let lineC = document.createElementNS('http://www.w3.org/2000/svg', 'line'); lineC.setAttribute('x1', 0); - lineC.setAttribute('y1', svgHeight - (this.diskTempCritical - tempOffset) * tempValueMul); + lineC.setAttribute('y1', svgHeight - (this.diskTempCritical - tempMinimalValue) * tempValueMul); lineC.setAttribute('x2', '100%'); - lineC.setAttribute('y2', svgHeight - (this.diskTempCritical - tempOffset) * tempValueMul); + lineC.setAttribute('y2', svgHeight - (this.diskTempCritical - tempMinimalValue) * tempValueMul); lineC.setAttribute('style', 'stroke:red; stroke-width:0.7'); svg.appendChild(lineC); // time labels let j = 0; - for(let i = 0; i < svgWidth; i += timeStep * timeLineInterval) { + for(let i = 0; i < svgWidth; i += timeAxisStep * timeAxisInterval) { let line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', i); line.setAttribute('y1', 0); line.setAttribute('x2', i); line.setAttribute('y2', '100%'); - line.setAttribute('style', 'stroke:black; stroke-width:1; opacity:0.1'); + line.setAttribute('style', 'stroke:rgba(122,122,122,0.2); stroke-width:1'); svg.appendChild(line); let text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', i + 6); text.setAttribute('y', 0); text.setAttribute('style', 'fill:rgba(122,122,122,0.5); font-family:monospace; font-size:12px; font-weight:bold; writing-mode:vertical-rl'); - if(i >= 2 * timeStep * timeLineInterval) { + if(i >= 2 * timeAxisStep * timeAxisInterval) { text.appendChild(document.createTextNode('%02d.%02d %02d:%02d'.format( dataUnits[j][2].getDate(), dataUnits[j][2].getMonth() + 1, @@ -444,7 +469,7 @@ return L.view.extend({ dataUnits[j][2].getMinutes() ))); }; - j += timeLineInterval; + j += timeAxisInterval; svg.appendChild(text); if(j >= dataSize) { break; @@ -453,25 +478,33 @@ return L.view.extend({ // temperature labels let c = 0; - for(let i = svgHeight; i > 0; i -= tempValueMul * tempStep) { + for(let i = svgHeight; i > 0; i -= tempValueMul * tempAxisStep) { let line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', 0); line.setAttribute('y1', i); line.setAttribute('x2', '100%'); line.setAttribute('y2', i); - line.setAttribute('style', 'stroke:black; stroke-width:1; opacity:0.1'); + line.setAttribute('style', 'stroke:rgba(122,122,122,0.2); stroke-width:1'); svg.appendChild(line); let text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', 0); text.setAttribute('y', i - 3); text.setAttribute('style', 'fill:#eee; font-family:monospace; font-size:14px; text-shadow:1px 1px 1px #000'); if(c % 2 === 0) { - text.appendChild(document.createTextNode(((svgHeight - i) / tempValueMul) + tempOffset + ' °C')); + text.appendChild(document.createTextNode(((svgHeight - i) / tempValueMul) + tempMinimalValue + ' °C')); }; svg.appendChild(text); c++; }; + // temperature min/max, log interval + let text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); + text.setAttribute('x', svgWidth / 3); + text.setAttribute('y', svgHeight - 10); + text.setAttribute('style', 'fill:#eee; font-family:monospace; font-size:12px; text-shadow:1px 1px 1px #000'); + text.appendChild(document.createTextNode(`Interval:${intervalMin}m Tmin:${tempMin}°C Tmax:${tempMax}°C`)); + svg.appendChild(text); + // TABLE dataUnits = dataUnits.filter((e, i, a) => { @@ -487,13 +520,11 @@ return L.view.extend({ ); for(let [num, temp, date] of dataUnits) { - if(temp === null) { - continue; - }; + if(temp === null) continue; sctTempTable.append( E('div', { - 'class': (temp >= this.diskTempCritical) ? 'tr err' : - (temp >= this.diskTempWarning) ? 'tr warn' : 'tr', + 'class': (temp >= this.diskTempCritical) ? 'tr disks-info-err' : + (temp >= this.diskTempWarning) ? 'tr disks-info-warn' : 'tr', }, [ E('div', { 'class': 'td left', 'data-title': _('Index') }, num), @@ -512,13 +543,15 @@ return L.view.extend({ }; let deviceNormalized = device.replace(/\//g, '-'); - let loggingIntervalValue = E('select', { + let loggingIntervalValue = E('input', { 'id': 'logging_interval_value' + deviceNormalized, + 'type': 'text', + 'class': 'cbi-input-text', 'style': 'width:4em !important; min-width:4em !important', + 'maxlength': 2, + 'value': 1, }, E('option', { 'value': '1' }, 1)); - for(let i = 5; i <= 60 ; i += 5) { - loggingIntervalValue.append(E('option', { 'value': String(i) }, i)); - }; + ui.addValidator(loggingIntervalValue, 'range(1,99)', false) return E([ E('div', { 'class': 'cbi-value' }, [ @@ -533,6 +566,7 @@ return L.view.extend({ sctTempTable ), ]), + E('div', { 'class': 'cbi-value' }, [ E('label', { 'class': 'cbi-value-title', 'for': 'logging_interval_value' + deviceNormalized }, _('Set logging interval') + ' (' + _('min') + ')'), @@ -552,42 +586,16 @@ return L.view.extend({ E('label', { 'class': 'cbi-value-title' }, _('Write to device memory') ), - E('div', { 'class': 'cbi-value-field' }, + E('div', { 'class': 'cbi-value-field' }, [ E('button', { 'class': 'btn cbi-button-apply important', 'click': ui.createHandlerFn(this, this.setSctTempLogInterval, device), - }, _('Apply')) - ), + }, _('Apply')), + ]), E('hr'), ]), - ]); - }, - createSsdArea: function(ssdStatObject) { - let ssdPercEndurObj = ssdStatObject.table.find(e => e.offset == 8); - if(ssdPercEndurObj) { - return E('div', { 'class': 'cbi-value' }, [ - E('h3', {}, _('SSD') + ':'), - E('div', { 'class': 'table' }, [ - E('div', { 'class': 'tr' }, [ - E('div', { 'class': 'td left', 'style':'min-width:33%' }, - _('Percentage used endurance indicator') + ':'), - E('div', { - 'class': (ssdPercEndurObj.value >= this.ssdEnduranceWarning) ? - 'td left warn' : 'td left', - }, - E('div', { - 'class': 'cbi-progressbar', - 'title': ssdPercEndurObj.value + '%', - 'data-tooltip': _('May not be supported by some devices...'), - }, - E('div', { 'style': 'width:' + ssdPercEndurObj.value + '%' }) - ) - ), - ]), - ]), - ]); - }; + ]); }, createDeviceStatistics: function(statObject) { @@ -595,14 +603,28 @@ return L.view.extend({ E('h3', {}, _('Device statistics') + ':') ); for(let page of statObject.pages) { - if(page.number == 5 || page.number == 7) continue; + if(!Array.isArray(page.table) || page.table.length === 0) continue; let pageTableTitle = E('h5', { 'style': 'width:100% !important; text-align:left !important' }, _(page.name)); let pageTable = E('div', { 'class': 'table' }); for(let entry of page.table) { pageTable.append( E('div', { 'class': 'tr' }, [ E('div', { 'class': 'td left', 'style':'min-width:33%' }, _(entry.name) + ':'), - E('div', { 'class': 'td left' }, entry.value), + (page.number === 7 && entry.offset === 8) ? + E('div', { + 'class': (entry.value >= this.ssdEnduranceWarning) ? + 'td left disks-info-warn' : 'td left', + }, + E('div', { + 'class': 'cbi-progressbar', + 'title': entry.value + '%', + 'data-tooltip': _('May not be supported by some devices...'), + }, + E('div', { 'style': 'width:' + entry.value + '%' }) + ) + ) + : + E('div', { 'class': 'td left' }, entry.value), ]) ); }; @@ -760,7 +782,9 @@ return L.view.extend({ this.diskTempWarning = smartObject.temperature && smartObject.temperature.op_limit_max || 60; this.diskTempCritical = smartObject.temperature && smartObject.temperature.limit_max || 80; - if('smart_status' in smartObject && 'ata_smart_attributes' in smartObject) { + if('smart_status' in smartObject && 'ata_smart_attributes' in smartObject && + Array.isArray(smartObject.ata_smart_attributes.table) && + smartObject.ata_smart_attributes.table.length > 0) { deviceTab.append(this.createSmartTable(smartObject)); }; if('ata_smart_error_log' in smartObject) { @@ -771,18 +795,14 @@ return L.view.extend({ if('temperature' in smartObject) { deviceTab.append(this.createTempTable(smartObject)); }; - if('ata_sct_temperature_history' in smartObject) { + if('ata_sct_temperature_history' in smartObject && + Array.isArray(smartObject.ata_sct_temperature_history.table) && + smartObject.ata_sct_temperature_history.table.length > 0) { deviceTab.append(this.createSctTempArea(smartObject)); }; - if('ata_device_statistics' in smartObject) { - let ssdStatObject = smartObject.ata_device_statistics.pages.find(e => e.number == 7); - - if(ssdStatObject) { - let ssdArea = this.createSsdArea(ssdStatObject); - if(ssdArea) { - deviceTab.append(ssdArea); - }; - }; + if('ata_device_statistics' in smartObject && + Array.isArray(smartObject.ata_device_statistics.pages) && + smartObject.ata_device_statistics.pages.length > 0) { deviceTab.append(this.createDeviceStatistics(smartObject.ata_device_statistics)); }; if('device' in smartObject) { @@ -797,8 +817,9 @@ return L.view.extend({ }; return E([ - E('h2', { 'class': 'fade-in' }, _('Disks info')), - E('div', { 'class': 'cbi-section-descr fade-in' }), + E('h2', { 'class': 'fade-in' }, _('Disk devices')), + E('div', { 'class': 'cbi-section-descr fade-in' }, + _("Information about the connected disk devices.")), devicesNode, ]); }, diff --git a/luasrc/controller/disks-info.lua b/luasrc/controller/disks-info.lua index 3d1730a..5fde98f 100644 --- a/luasrc/controller/disks-info.lua +++ b/luasrc/controller/disks-info.lua @@ -3,6 +3,6 @@ module('luci.controller.disks-info', package.seeall) function index() if nixio.fs.access('/bin/df') and nixio.fs.access('/usr/sbin/fdisk') and nixio.fs.access('/usr/sbin/smartctl') then - entry({'admin', 'services', 'disks-info'}, view('disks-info'), _('Disks info'), 10).acl_depends = { 'luci-app-disks-info' } + entry({'admin', 'services', 'disks-info'}, view('disks-info'), _('Disk devices'), 10).acl_depends = { 'luci-app-disks-info' } end end diff --git a/packages/19.07/luci-app-disks-info_0.3-5_all.ipk b/packages/19.07/luci-app-disks-info_0.3-5_all.ipk deleted file mode 100644 index 12762c7..0000000 Binary files a/packages/19.07/luci-app-disks-info_0.3-5_all.ipk and /dev/null differ diff --git a/packages/19.07/luci-app-disks-info_0.3-6_all.ipk b/packages/19.07/luci-app-disks-info_0.3-6_all.ipk new file mode 100644 index 0000000..3d3f199 Binary files /dev/null and b/packages/19.07/luci-app-disks-info_0.3-6_all.ipk differ diff --git a/packages/19.07/luci-i18n-disks-info-ru_0.3-5_all.ipk b/packages/19.07/luci-i18n-disks-info-ru_0.3-5_all.ipk deleted file mode 100644 index c25f36e..0000000 Binary files a/packages/19.07/luci-i18n-disks-info-ru_0.3-5_all.ipk and /dev/null differ diff --git a/packages/19.07/luci-i18n-disks-info-ru_0.3-6_all.ipk b/packages/19.07/luci-i18n-disks-info-ru_0.3-6_all.ipk new file mode 100644 index 0000000..3a63e0f Binary files /dev/null and b/packages/19.07/luci-i18n-disks-info-ru_0.3-6_all.ipk differ diff --git a/po/ru/disks-info.po b/po/ru/disks-info.po index 00ecf62..77f835c 100644 --- a/po/ru/disks-info.po +++ b/po/ru/disks-info.po @@ -56,12 +56,15 @@ msgstr "Идентификатор диска" msgid "Disklabel type" msgstr "Тип разметки диска" -msgid "Disks info" -msgstr "Информация о дисках" +msgid "Disk devices" +msgstr "Дисковые устройства" msgid "End" msgstr "Конец" +msgid "Error number" +msgstr "Номер ошибки" + msgid "Estimated time" msgstr "Расчётное время" @@ -95,6 +98,9 @@ msgstr "Находится в базе smartctl [подробно: -P show]" msgid "Index" msgstr "Индекс" +msgid "Information about the connected disk devices." +msgstr "Информация о подключенных дисковых устройствах." + msgid "LU WWN Device Id" msgstr "" @@ -140,8 +146,8 @@ msgstr "Отсутствует в базе smartctl [подробно: -P showal msgid "Partitions" msgstr "Разделы" -msgid "Percentage used endurance indicator" -msgstr "Процентный индикатор износа" +msgid "Percentage Used Endurance Indicator" +msgstr "Процентный Индикатор Износа" msgid "Preserve across power cycles" msgstr "Сохранить при выключении питания" @@ -159,7 +165,7 @@ msgid "Refresh devices" msgstr "Обновить устройства" msgid "Rotating Media Statistics" -msgstr "Статистика механической части" +msgstr "Статистика Механической Части" msgid "Rotation Rate" msgstr "Скорость вращения" @@ -197,8 +203,8 @@ msgstr "Серийный номер" msgid "Size" msgstr "Размер" -msgid "SSD" -msgstr "" +msgid "Solid State Device Statistics" +msgstr "Статистика SSD" msgid "Start" msgstr "Начало" @@ -206,6 +212,9 @@ msgstr "Начало" msgid "Temperature" msgstr "Температура" +msgid "Temperature Statistics" +msgstr "Статистика Температуры" + msgid "THRESH" msgstr "" diff --git a/po/templates/disks-info.pot b/po/templates/disks-info.pot index 1e80d57..20b09ee 100644 --- a/po/templates/disks-info.pot +++ b/po/templates/disks-info.pot @@ -46,12 +46,15 @@ msgstr "" msgid "Disklabel type" msgstr "" -msgid "Disks info" +msgid "Disk devices" msgstr "" msgid "End" msgstr "" +msgid "Error number" +msgstr "" + msgid "Estimated time" msgstr "" @@ -85,6 +88,9 @@ msgstr "" msgid "Index" msgstr "" +msgid "Information about the connected disk devices." +msgstr "" + msgid "LU WWN Device Id" msgstr "" @@ -130,7 +136,7 @@ msgstr "" msgid "Partitions" msgstr "" -msgid "Percentage used endurance indicator" +msgid "Percentage Used Endurance Indicator" msgstr "" msgid "Preserve across power cycles" @@ -187,7 +193,7 @@ msgstr "" msgid "Size" msgstr "" -msgid "SSD" +msgid "Solid State Device Statistics" msgstr "" msgid "Start" @@ -196,6 +202,9 @@ msgstr "" msgid "Temperature" msgstr "" +msgid "Temperature Statistics" +msgstr "" + msgid "THRESH" msgstr "" diff --git a/root/usr/share/luci/menu.d/luci-app-disks-info.json b/root/usr/share/luci/menu.d/luci-app-disks-info.json index f7d0a67..0984ec4 100644 --- a/root/usr/share/luci/menu.d/luci-app-disks-info.json +++ b/root/usr/share/luci/menu.d/luci-app-disks-info.json @@ -1,6 +1,6 @@ { "admin/services/disks-info": { - "title": "Disks info", + "title": "Disk devices", "order": 10, "action": { "type": "view", diff --git a/screenshots/01.jpg b/screenshots/01.jpg index fca860d..e5f7650 100644 Binary files a/screenshots/01.jpg and b/screenshots/01.jpg differ