Merge remote-tracking branch 'upstream/master' into File-System-Snapshots

This commit is contained in:
SimonFair
2023-12-30 15:55:46 +00:00
36 changed files with 553 additions and 270 deletions
+5 -2
View File
@@ -83,6 +83,8 @@ function print_error($error) {
?>
<script>
var ctrl = '<span class="status <?=$tabbed?"":"vhshift"?>"><a style="cursor:pointer" class="tooltip_diskio" title="_(Toggle reads/writes display)_" onclick="toggle_diskio();return false"><i class="toggle fa"></i></a></span>';
var recall = null;
var recover = null;
function base64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
@@ -310,6 +312,7 @@ devices.on('message', function(msg,meta) {
// array + pool + ua + flash devices
var get = JSON.parse(msg);
for (var name in get) $('#'+name).html(get[name]);
if (recall !== null) recall.html('&nbsp;');
display_diskio();
// stop updating when array is stopped
if (get.stop==1) {
@@ -322,8 +325,8 @@ devices.on('message', function(msg,meta) {
} else {
// make truncated descriptions fully visible when hovering over them
$('td.desc').hover(
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {devices.stop();$(this).next().html('');}},
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {devices.start();}}
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall=$(this).next(); recover=recall.html(); recall.html('&nbsp;');}},
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall.html(recover); recall=null;}}
);
}
break;
+66 -47
View File
@@ -209,7 +209,7 @@ switch ($theme) {
</td></tr>
<tr><td>
<div class='leftside'>
<a href="/Settings/DateTime" class="hand none" title="_(Go to date and time settings)_"><span id="current_time"></span></a><br><span id="current_date"></span><br><br>
<a href="/Settings/DateTime" class="hand none"><span id="current_time"></span></a><br><span id="current_date"></span><br><br>
<span class='header'><i class='indent fa fa-file-text-o'></i>_(Model)_</span><br><i class='indent'></i><?=_var($var,'SYS_MODEL')?:'---'?><br><br>
<span class='header'><i class='indent fa fa-id-badge'></i>_(Registration)_</span><br><i class='indent'></i>Unraid OS <b><em><?=_var($var,'regTy')?></em></b><br><br>
<span class='header'><i class='indent fa fa-clock-o'></i>_(Uptime)_</span><br><i class='indent'></i><span class='uptime'></span>
@@ -273,18 +273,18 @@ foreach ($cpus as $pair) {
<span class="head_info"><span><i class='ups fa fa-line-chart'></i>_(Memory)_: <?="$memory_installed $unit $memory_type $ecc"?></span></span>
<span class="switch">_(RAM)_:<span class="head_bar"><span class='sys0_ load'>0%</span><div class='usage-disk sys'><span id='sys0_'></span><span></span></div></span></span><br></div>
<a href='/Dashboard/Tools/Processes' title="_(View Running Processes)_"><i class='fa fa-fw fa-info-circle control'></i></a>
</td></tr>
<tr><td>
<span class='w26'><div class='more'>
<i class='ups fa fa-compress'></i>_(Usable size)_: <?=$ramsize?><br>
<i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $unit"?><?=$low?'*':''?>
<legend>_(Legend)_</legend>
<span id='dynamic'></span>
</div></span>
<span class='w18 center'><span class='center'><a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a></span><div class='pie' id='sys0'><span class='sys0'></span><span class='var0'></span></div></span>
<span class='w18 center'><span class='center'><a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a></span><div class='pie' id='sys1'><span class='sys1'></span><span class='var1'></span></div></span>
<span class='w18 center'><span class='center'><a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a></span><div class='pie' id='sys2'><span class='sys2'></span><span class='var2'></span></div></span>
<span class='w18 center'><span class='center'><a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a></span><div class='pie' id='sys3'><span class='sys3'></span><span class='var3'></span></div></span>
</td></tr><tr><td>
<span class='w26'><i class='ups fa fa-compress'></i>_(Usable size)_: <?=$ramsize?><br><i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $unit"?><?=$low?'*':''?></span>
<span class='w18 center'><a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a></span>
<span class='w18 center'><a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a></span>
<span class='w18 center'><a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a></span>
<span class='w18 center'><a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a></span>
</td></tr><tr><td>
<span class='w26'><legend>_(Legend)_</legend><span id='dynamic'></span></span>
<span class='w18 center'><div class='pie' id='sys0'><span class='sys0'></span><span class='var0'></span></div></span>
<span class='w18 center'><div class='pie' id='sys1'><span class='sys1'></span><span class='var1'></span></div></span>
<span class='w18 center'><div class='pie' id='sys2'><span class='sys2'></span><span class='var2'></span></div></span>
<span class='w18 center'><div class='pie' id='sys3'><span class='sys3'></span><span class='var3'></span></div></span>
</td></tr>
</tbody>
@@ -800,6 +800,8 @@ var update2 = true;
var box = null;
var startup = true;
var stopgap = '<thead class="stopgap"><tr><td class="stopgap"></td></tr></thead>';
var recall = null;
var recover = null;
var options_cpu = {
series:[{name:'load', data:cpu.slice()}],
@@ -1030,10 +1032,10 @@ function portSelect(name) {
}
function moreInfo(data,table) {
var info = [];
if (data[1]>0) info.push(data[1]+" _(failed device)_"+(data[1]==1?'':'s'));
if (data[2]>0) info.push(data[2]+" _(heat warning)_"+(data[2]==1?'':'s'));
if (data[3]>0) info.push(data[3]+" _(SMART error)_"+(data[3]==1?'':'s'));
if (data[4]>0) info.push(data[4]+" _(utilization warning)_"+(data[4]==1?'':'s'));
if (data[1]>0) info.push(data[1]+' '+(data[1]==1 ? "_(failed device)_" : "_(failed devices)_"));
if (data[2]>0) info.push(data[2]+' '+(data[2]==1 ? "_(heat warning)_" : "_(heat warnings)_"));
if (data[3]>0) info.push(data[3]+' '+(data[3]==1 ? "_(SMART error)_" : "_(SMART errors)_"));
if (data[4]>0) info.push(data[4]+' '+(data[4]==1 ? "_(utilization warning)_" : "_(utilization warnings)_"));
return info.length ? "<div class='last'><i class='icon-u-triangle failed'></i><span class='failed'>"+table+" _(has)_ "+info.join('. ')+".</span></div>" : "";
}
function autoscale(value,text,size,kilo) {
@@ -1118,7 +1120,7 @@ function StopArray() {
}
function StopArrayNow() {
$('span.hand').prop('onclick',null).off('click').addClass('busy').css({'cursor':'default'});
$.post('/update.htm',{startState:'<?=_var($var,'mdState')?>',cmdStop:'Stop',csrf_token:'<?=_var($var,'csrf_token')?>'},function(){refresh();});
$.post('/update.htm',{cmdStop:'Stop'},function(){refresh();});
}
function StartArray() {
<?if ($confirm['stop']):?>
@@ -1129,7 +1131,7 @@ function StartArray() {
}
function StartArrayNow() {
$('span.hand').prop('onclick',null).off('click').addClass('busy').css({'cursor':'default'});
$.post('/update.htm',{startState:'<?=_var($var,'mdState')?>',cmdStart:'Start',csrf_token:'<?=_var($var,'csrf_token')?>'},function(){refresh();});
$.post('/update.htm',{cmdStart:'Start'},function(){refresh();});
}
function Reboot() {
<?if ($confirm['down']):?>
@@ -1204,6 +1206,12 @@ function addProperties() {
$('div#sys1').hover(function(){$('.sys1').hide();$('.var1').show();},function(){$('.sys1').show();$('.var1').hide();});
$('div#sys2').hover(function(){$('.sys2').hide();$('.var2').show();},function(){$('.sys2').show();$('.var2').hide();});
$('div#sys3').hover(function(){$('.sys3').hide();$('.var3').show();},function(){$('.sys3').show();$('.var3').hide();});
$('#current_time').hover(function(){$.post('/webGui/include/DashboardApps.php',{ntp:'ntp'},function(ntp){$('#current_time').prop('title',ntp+"\n_(Go to date and time settings)_");});});
// make truncated descriptions fully visible when hovering over them
$('span.w18').hover(
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall = $(this).next(); recover=recall.html(); recall.html('&nbsp;');}},
function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall.html(recover); recall=null;}}
);
}
function showContent() {
var count = {'db-box1':$('table#db-box1 tbody').length, 'db-box2':$('table#db-box2 tbody').length, 'db-box3':$('table#db-box3 tbody').length}
@@ -1381,7 +1389,7 @@ function selectsnapshot(uuid, name ,snaps, opt, getlist){
box.find('#targetsnapl').html(snaps);
if (getlist) {
var only = (opt == "remove") ? 0 : 1;
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-images", uuid:uuid, snapshotname:snaps, only:only}, function(data){if (data.html) box.find('#targetsnapimages').html(data.html);},'json');
$.post("/plugins/dynamix.vm.manager/include/VMajax.php",{action:"snap-images",uuid:uuid,snapshotname:snaps,only:only},function(data){if (data.html) box.find('#targetsnapimages').html(data.html);},'json');
}
document.getElementById("targetsnapfspc").checked = true;
box.dialog({
@@ -1473,14 +1481,29 @@ function LockButton() {
$('table.dashboard').sortable('destroy');
}
}
function cpu_parse(msg) {
var parse = {}, section = '';
msg.split('\n').forEach(function(row) {
if (row.substr(0,1) == '[') {
section = row.substr(1,row.length-2);
parse[section] = {};
} else {
var data = row.split('=');
parse[section][data[0]] = data[1];
}
});
return parse;
}
var dashboard = new NchanSubscriber('/sub/cpuload,update1,update2,update3<?=$wireguard?",wireguard":""?>',{subscriber:'websocket'});
dashboard.on('message',function(msg,meta) {
switch (meta.id.channel()) {
case 0:
var get = parseINI(msg);
var get = cpu_parse(msg);
// cpu load
$.each(get,function(k,v) {
var load = v['host'];
var load = v.host;
var color = setColor(load, 90, 70);
if (k=='cpu') {
addChartCpu(load);
@@ -1536,30 +1559,27 @@ dashboard.on('message',function(msg,meta) {
case 2:
if (!update2) break;
var get = JSON.parse(msg);
var data = get.disk.split('\n');
var info = moreInfo(data,"_(Array)_");
var info = moreInfo(get.disk,"_(Array)_");
// array devices
$('#array_list tr.updated').remove();
$('#array_list').append(data[0]).hideMe();
$('#array_list').append(get.disk[0]).hideMe();
$('#array_info').parent().css({'display':info?'':'none'});
$('#array_info').html(info);
smartMenu('#array_list');
// pool devices
for (var i=0,pool; pool=get.pool[i]; i++) {
var data = pool.split('\n');
var info = moreInfo(data,"_(Pool)_");
for (let i=0; i < get.pool.length; i++) {
var info = moreInfo(get.pool[i],"_(Pool)_");
$('#pool_list'+i+' tr.updated').remove();
$('#pool_list'+i).append(pool).hideMe();
$('#pool_list'+i).append(get.pool[i][0]).hideMe();
$('#pool_info'+i).parent().css({'display':info?'':'none'});
$('#pool_info'+i).html(info);
smartMenu('#pool_list'+i);
}
<?if ($devs):?>
// unassigned devices
var data = get.open.split('\n');
var info = moreInfo(data,"_(Unassigned)_");
var info = moreInfo(get.open,"_(Unassigned)_");
$('#devs_list tr.updated').remove();
$('#devs_list').append(data[0]).hideMe();
$('#devs_list').append(get.open[0]).hideMe();
$('#devs_info').parent().css({'display':info?'':'none'});
$('#devs_info').html(info);
smartMenu('#devs_list');
@@ -1567,14 +1587,13 @@ dashboard.on('message',function(msg,meta) {
// parity status
$('span.parity').html(get.parity);
// parity schedule
var data = get.schedule.split('\n');
$('#parity').html(data[0]);
$('#program').html(data[1]);
$('#parity').html(get.schedule[0]);
$('#program').html(get.schedule[1]);
break;
case 3:
var get = JSON.parse(msg);
// rx & tx speeds
for (var i=0,port; port=get.port[i]; i++) {
for (let i=0,port; port=get.port[i]; i++) {
if (port[0] == port_select) {
$('#inbound').text(port[1]);
$('#outbound').text(port[2]);
@@ -1618,17 +1637,17 @@ dashboard.on('message',function(msg,meta) {
});
<?if ($apcupsd):?>
var apcups = new NchanSubscriber('/sub/apcups',{subscriber:'websocket'});
apcups.on('message',function(data) {
data = data.split(';');
$('#ups_model').html(data[0]);
$('#ups_status').html(data[1]);
$('#ups_status_').html(data[1]);
$('#ups_bcharge').html(data[2]);
$('#ups_timeleft').html(data[3]);
$('#ups_nompower').html(data[4]);
$('#ups_loadpct').html(data[5]);
$('#ups_loadpct_').html(data[5]);
$('#ups_outputv').html(data[6]);
apcups.on('message',function(msg) {
var get = JSON.parse(msg);
$('#ups_model').html(get[0]);
$('#ups_status').html(get[1]);
$('#ups_status_').html(get[1]);
$('#ups_bcharge').html(get[2]);
$('#ups_timeleft').html(get[3]);
$('#ups_nompower').html(get[4]);
$('#ups_loadpct').html(get[5]);
$('#ups_loadpct_').html(get[5]);
$('#ups_outputv').html(get[6]);
});
<?endif;?>
+19
View File
@@ -0,0 +1,19 @@
Menu="Tasks:2"
Type="xmenu"
Code="e970"
---
<script>
function delPage(page) {
$.post('/webGui/include/MyFavorites.php',{action:'del',page:page},function(){refresh();});
}
$(function(){
$('i.PanelIcon').each(function(){
var icon = $(this);
var page = icon.closest('a').prop('href').split('/').pop();
icon.after('<i class="fa fa-heartbeat favo" title="_(Remove from favorites)_" onclick="delPage(&quot;'+page+'&quot;);return false"></i>');
icon.parent().parent().parent().hover(function(){icon.next().show();},function(){icon.next().hide();});
});
if ($('i.PanelIcon').length==0) $('#nofavs').show();
});
</script>
+6
View File
@@ -0,0 +1,6 @@
Menu="Favorites"
Type="menu"
Title="My Favorites"
Tag="icon-u-star"
---
<div id="nofavs" style="display:none;width:100%"><center>_(No favorites available)_</center></div>
+68
View File
@@ -0,0 +1,68 @@
Menu="OtherSettings"
Type="xmenu"
Title="Power Mode"
Icon="icon-energysaving"
Tag="icon-energysaving"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$cpufreq = '/sys/devices/system/cpu/cpu0/cpufreq';
$current = exec("cat $cpufreq/scaling_governor 2>/dev/null");
exec("cat $cpufreq/scaling_available_governors 2>/dev/null | tr ' ' '\n' | sed '/^$/d' | sort -u",$governor);
function value(...$modes) {
global $current, $governor;
$checked = $value = '';
$disabled = ' disabled';
foreach ($modes as $mode) {
if ($mode==$current) $checked = ' checked';
if (in_array($mode,$governor)) {$value = "value=\"$mode\""; $disabled = '';}
}
return $value.$checked.$disabled;
}
?>
<script>
function preparePowermode(form) {
$(form).find('[name="#arg[1]"]').val(form.powermode.value);
}
$(function(){
$('input[type=radio]').each(function(){
if ($(this).prop('disabled')) $(this).next('span').html(" <i>(_(unavailable)_)</i>");
});
<?if (exec("dmesg | grep -Pom1 'Hypervisor detected'")):?>
$('#vm').show();
<?endif;?>
});
</script>
<form markdown="1" name="PowerMode" method="POST" action="/update.php" target="progressFrame" onsubmit="preparePowermode(this)">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg">
<input type="hidden" name="#section" value="powermode">
<input type="hidden" name="#command" value="/webGui/scripts/powermode">
<input type="hidden" name="#arg[1]" value="">
_(Change power mode)_:
: <input name="powermode" type="radio"<?=value('powersave')?>>_(Best power efficiency)_<span></span>
&nbsp;
: <input name="powermode" type="radio"<?=value('ondemand','balance_power')?>>_(Balanced operation)_<span></span>
&nbsp;
: <input name="powermode" type="radio"<?=value('performance')?>>_(Best performance)_<span></span>
&nbsp;
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<div id="vm" class="notice">_(When running Unraid virtualized, there are no available power modes)_</div>
+18 -1
View File
@@ -1,4 +1,21 @@
Menu="Tasks:4"
Type="xmenu"
Tabs="false"
Code="e924"
Code="e924"
---
<script>
function addPage(page) {
$.post('/webGui/include/MyFavorites.php',{action:'add',page:page},function(){
swal({title:"_(Added to Favorites)_",text:"",type:"success",html:true,confirmButtonText:"_(Ok)_"});
});
}
$(function(){
$('i.PanelIcon').each(function(){
var icon = $(this);
var page = icon.closest('a').prop('href').split('/').pop();
icon.after('<i class="fa fa-heart favo" title="_(Add to favorites)_" onclick="addPage(&quot;'+page+'&quot;);return false"></i>');
icon.parent().parent().parent().hover(function(){icon.next().show();},function(){icon.next().hide();});
});
});
</script>
+10 -2
View File
@@ -147,7 +147,7 @@ _(Local syslog number of files)_:
_(Remote syslog server)_:
: <span class="span"><input type="text" name="remote_server" class="narrow" value="<?=_var($syslog,'remote_server')?>" maxlength="23" placeholder="_(name or ip address)_"></span>
<select name="remote_protocol" class="narrow" size="1">
<select name="remote_protocol" class="narrow">
<?=mk_option(_var($syslog,'remote_protocol'), "udp", _("UDP"))?>
<?=mk_option(_var($syslog,'remote_protocol'), "tcp", _("TCP"))?>
</select>
@@ -156,13 +156,21 @@ _(Remote syslog server)_:
:syslog_remote_server_help:
_(Mirror syslog to flash)_:
: <select name="syslog_flash" size="1">
: <select name="syslog_flash">
<?=mk_option(_var($syslog,'syslog_flash'), "", _("No"))?>
<?=mk_option(_var($syslog,'syslog_flash'), "1", _("Yes"))?>
</select>
:syslog_mirror_flash_help:
_(Copy syslog to flash on shutdown)_:
: <select name="syslog_shutdown">
<?=mk_option(_var($syslog,'syslog_shutdown'), "", _("Yes"))?>
<?=mk_option(_var($syslog,'syslog_shutdown'), "1", _("No"))?>
</select>
:syslog_shutdown_flash_help:
&nbsp;
: <input type="button" value="_(Apply)_" onclick='validatePort(this.form)' disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
+18 -1
View File
@@ -1,4 +1,21 @@
Menu="Tasks:90"
Type="xmenu"
Tabs="false"
Code="e909"
Code="e909"
---
<script>
function addPage(page) {
$.post('/webGui/include/MyFavorites.php',{action:'add',page:page},function(){
swal({title:"_(Added to Favorites)_",text:"",type:"success",html:true,confirmButtonText:"_(Ok)_"});
});
}
$(function(){
$('i.PanelIcon').each(function(){
var icon = $(this);
var page = icon.closest('a').prop('href').split('/').pop();
icon.after('<i class="fa fa-heart favo" title="_(Add to favorites)_" onclick="addPage(&quot;'+page+'&quot;);return false"></i>');
icon.parent().parent().parent().hover(function(){icon.next().show();},function(){icon.next().hide();});
});
});
</script>
+1
View File
@@ -26,6 +26,7 @@ hot="45"
max="55"
hotssd="60"
maxssd="70"
power=""
theme="white"
locale=""
raw=""
@@ -0,0 +1,2 @@
#!/bin/bash
/usr/local/emhttp/webGui/scripts/update_services 10
@@ -13,13 +13,17 @@
?>
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
// add translations
$_SERVER['REQUEST_URI'] = 'dashboard';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'dashboard';
require_once "$docroot/webGui/include/Translations.php";
if (isset($_POST['ntp'])) {
$ntp = exec("ntpq -pn|awk '{if (NR>3 && $2!=\".INIT.\") c++} END {print c}'");
die($ntp ? sprintf(_('Clock synchronized with %s NTP server'.($ntp==1?'':'s')),$ntp) : _('Clock is unsynchronized with no NTP servers'));
}
if ($_POST['docker']) {
$user_prefs = $dockerManPaths['user-prefs'];
@@ -0,0 +1,47 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
$permit = ['del','add'];
$action = $_POST['action']??'';
$page = glob("$docroot/plugins/*/{$_POST['page']}.page",GLOB_NOSORT)[0];
$cfg = '/boot/config/favorites.cfg';
// validate input
if (!$page || !in_array($action,$permit)) exit;
$file = fopen($page,'r');
// get current Menu settings
extract(parse_ini_string(fgets($file)));
fclose($file);
// remove label and escape single quotes for sed command
$Menu = str_replace([' MyFavorites',"'"],['',"'\''"],$Menu);
switch ($action) {
case $permit[0]: // del
$del = str_replace('/','\/',$page);
exec("sed -i '/$del/d' $cfg 2>/dev/null");
break;
case $permit[1]: // add
$file = fopen($cfg,'a+');
fseek($file,0,0);
while (($line = fgets($file))!==false) {
if (rtrim($line) == $page) break;
}
if (feof($file)) fwrite($file, $page."\n");
fclose($file);
$Menu .= ' MyFavorites';
break;
}
// update Menu settings
exec("sed -ri '0,/^Menu=\".+\"$/s//Menu=\"$Menu\"/' $page 2>/dev/null");
@@ -38,6 +38,9 @@ function duration(&$hrs) {
$age = date_diff($poh,$now);
$hrs = "$hrs (".($age->y?"{$age->y}y, ":"").($age->m?"{$age->m}m, ":"").($age->d?"{$age->d}d, ":"")."{$age->h}h)";
}
function blocks_size(&$blks,$blk_size) {
$blks = "$blks (".my_scale($blks*$blk_size,$unit)." $unit)";
}
function append(&$ref, &$info) {
if ($info) $ref .= ($ref ? " " : "").$info;
}
@@ -62,6 +65,7 @@ case "attributes":
$hot = _var($disk,'hotTemp',-1)>=0 ? $disk['hotTemp'] : ($hotNVME>=0 ? $hotNVME : (_var($disk,'rotational',1)==0 && $display['hotssd']>=0 ? $display['hotssd'] : $display['hot']));
$max = _var($disk,'maxTemp',-1)>=0 ? $disk['maxTemp'] : ($maxNVME>=0 ? $maxNVME : (_var($disk,'rotational',1)==0 && $display['maxssd']>=0 ? $display['maxssd'] : $display['max']));
$top = $_POST['top'] ?? 120;
$ssd_remaining = NULL;
$empty = true;
exec("smartctl -n standby -A $type ".escapeshellarg("/dev/$port"),$output);
// remove empty rows
@@ -83,6 +87,8 @@ case "attributes":
}
if ($info[8]=='-') $info[8] = 'Never';
if ($info[0]==9 && is_numeric(size($info[9]))) duration($info[9]);
if (str_starts_with($info[1], 'Total_LBAs_')) blocks_size($info[9],512); // Assumes 512 byte sectors
if (str_ends_with($info[1], '_32MiB')) blocks_size($info[9],32*1024*1024);
echo "<tr{$color}>".implode('',array_map('normalize', $info))."</tr>";
$empty = false;
}
@@ -101,11 +107,38 @@ case "attributes":
case 'Power on hours':
if (is_numeric(size($value))) duration($value);
break;
case 'Percentage used':
$ssd_remaining = 100 - str_replace('%', '', $value);
break;
}
if (str_ends_with($name, ', hours') && str_starts_with($value, 'minutes ')) {
$name = substr($name, 0, -7);
$value = substr($value, 8);
if (is_numeric(size($value))) duration($value);
}
echo "<tr{$color}><td>-</td><td>$name</td><td colspan='8'>$value</td></tr>";
$empty = false;
}
}
if (is_null($ssd_remaining)) {
// Try to look up SSD's 'Percentage Used Endurance Indicator' with special command
exec("smartctl -n standby -l ssd $type ".escapeshellarg("/dev/$port"), $ssd_out);
$ssd_out = array_filter($ssd_out);
foreach ($ssd_out as $row) {
if (str_ends_with($row, 'Percentage Used Endurance Indicator')) {
// Probably a SATA SSD
$info = explode(' ', trim(preg_replace('/\s+/',' ',$row)), 6);
$ssd_remaining = 100 - $info[3];
} elseif (str_starts_with($row, 'Percentage used endurance indicator:')) {
// Probably a SAS SSD
[$name,$value] = array_map('trim',explode(':', $row));
$ssd_remaining = 100 - str_replace('%','',$value);
}
}
}
if (!is_null($ssd_remaining)) {
echo "<tr><td>-</td><td>SSD endurance remaining</td><td colspan='8'>$ssd_remaining %</td></tr>";
}
if ($empty) echo "<tr><td colspan='10' style='text-align:center;padding-top:12px'>"._('Attributes not available')."</td></tr>";
break;
case "capabilities":
+3 -3
View File
@@ -38,9 +38,9 @@ function update_translation($locale) {
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
$language = unserialize(file_get_contents($store));
}
$text = "$docroot/languages/$locale/main.txt";
$text = "$docroot/languages/$locale/dashboard.txt";
if (file_exists($text)) {
$store = "$docroot/languages/$locale/main.dot";
$store = "$docroot/languages/$locale/dashboard.dot";
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
$language = array_merge($language,unserialize(file_get_contents($store)));
}
@@ -92,7 +92,7 @@ while (true) {
// add fans information
if (count($fans)) $echo['fan'] = array_map(function($fan){return "$fan RPM";},$fans);
// add streams information
exec("LANG='en_US.UTF8' lsof -Fn /mnt/disk[0-9]* 2>/dev/null|awk -F/ '(NR>1){print \$4}'",$lsof);
exec('LANG="en_US.UTF8" lsof -Fn /mnt/* 2>/dev/null|awk -F/ \'$1=="n" && $2=="mnt" && $5!="" {print $4"/"$5"/"$6"/"$7}\'|sort -u|awk -F/ \'{print $1}\'',$lsof);
$share = array_keys(parse_ini_file("$varroot/shares.ini",true));
$count = array_count_values($lsof);
foreach ($share as $name) $echo['stream'][] = $count[$name]??0;
+17 -36
View File
@@ -223,16 +223,17 @@ function device_usage(&$disk, &$full, &$high) {
if ($critical>0 && $load>=$critical) {$class = 'redbar'; $full++;}
elseif ($warning>0 && $load>=$warning) {$class = 'orangebar'; $high++;}
else $class = 'greenbar';
}
else
} else {
$class = false;
}
return $text%10==0 ? $used : "<span class='load'>$used</span><div class='usage-disk sys'><span style='width:$used'".($class?" class='$class'":"")."></span><span></span></div>";
}
else
} else {
return $text%10==0 ? "-" : "<span class='load'>-</span><div class='usage-disk sys none'><span></span></div>";
}
}
function array_group($type, $pool=false) {
global $disks,$error,$warning,$red,$orange,$fail,$smart,$full,$high;
if ($type != 'Data') {$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;}
$echo = [];
foreach ($disks as $disk) if (_var($disk,'type')==$type && strpos(_var($disk,'status'),'DISK_NP')===false && (!$pool||$pool==prefix(_var($disk,'name')))) {
$echo[] = "<tr class='updated'><td>";
@@ -247,6 +248,7 @@ function array_group($type, $pool=false) {
}
function extra_group() {
global $devs,$error,$warning,$red,$orange,$fail,$smart,$full,$high;
$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;
$echo = [];
foreach ($devs as $disk) {
$name = _var($disk,'name');
@@ -292,9 +294,9 @@ while (true) {
$devs = (array)@parse_ini_file("$varroot/devs.ini",true);
$disks = (array)@parse_ini_file("$varroot/disks.ini",true);
$saved = (array)@parse_ini_file("$varroot/monitor.ini",true);
$echo = [];
$size = _var($var,'mdResyncSize');
$spot = _var($var,'mdResyncPos');
$echo = []; $p = 0;
$size = _var($var,'mdResyncSize',0);
$spot = _var($var,'mdResyncPos',0);
require "$docroot/webGui/include/CustomMerge.php";
require "$docroot/webGui/include/Preselect.php";
// check for language changes
@@ -304,33 +306,15 @@ while (true) {
update_translation($locale_init);
}
//array devices
$a = 'disk';
$echo[$a] = [];
$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;
$echo[$a][] = array_group('Parity');
$echo[$a][] = array_group('Data');
$echo[$a][] = "\n".($error+$warning)."\n".($red+$orange)."\n".($fail+$smart)."\n".($full+$high);
$echo[$a] = implode($echo[$a]);
$echo['disk'] = [array_group('Parity').array_group('Data'), $error+$warning, $red+$orange, $fail+$smart, $full+$high];
//pool devices
$a = 'pool'; $p = 0;
$echo[$a] = [];
foreach (pools_filter($disks) as $pool) {
if (empty($disks[$pool]['devices'])) continue;
$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;
$echo[$a][$p] = [];
$echo[$a][$p][] = array_group('Cache',$pool);
$echo[$a][$p][] = "\n".($error+$warning)."\n".($red+$orange)."\n".($fail+$smart)."\n".($full+$high);
$echo[$a][$p] = implode($echo[$a][$p]);
$p++;
$echo['pool'][$p++] = [array_group('Cache',$pool), $error+$warning, $red+$orange, $fail+$smart, $full+$high];
}
//unassigned devices
$a = 'open';
$echo[$a] = [];
$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;
$echo[$a][] = extra_group();
$echo[$a][] = "\n".($error+$warning)."\n".($red+$orange)."\n".($fail+$smart)."\n".($full+$high);
$echo[$a] = implode($echo[$a]);
$echo['open'] = [extra_group(), $error+$warning, $red+$orange, $fail+$smart, $full+$high];
// parity status
$a = 'parity';
@@ -371,7 +355,6 @@ while (true) {
// parity schedule
$a = 'schedule';
$echo[$a] = [];
[$delta,$bytes] = [_var($var,'mdResyncDt',0),_var($var,'mdResyncDb',0)];
$synced = create_sync($stamps);
$sbSynced = array_shift($synced) ?: _var($var,'sbSynced');
@@ -381,6 +364,7 @@ while (true) {
$echo[$a][] = "<br><i class='fa fa-fw fa-clock-o'></i> "._('Elapsed time').": "._(my_clock(floor((time()-$sbSynced)/60)),2);
$echo[$a][] = "<br><i class='fa fa-fw fa-flag-checkered'></i> "._('Estimated finish').': '.($bytes ? _(my_clock(round(((($delta*(($size-$spot)/($bytes/100+1)))/100)/60),0)),2) : _('Unknown'));
$echo[$a][] = "<br><i class='fa fa-fw fa-search'></i> ".print_error(_var($var,'sbSyncErrs',0));
$echo[$a] = implode($echo[$a]);
} else {
[$date,$duration,$speed,$status,$error,$action,$size] = last_parity_log();
if (_var($var,'sbSyncExit',0)!=0) {
@@ -414,7 +398,7 @@ while (true) {
$echo[$a][] = "<br><i class='fa fa-fw fa-clock-o'></i> "._('Duration').': '.my_check($duration,$speed);
$echo[$a][] = "<br><i class='fa fa-fw fa-search'></i> ".print_error(_var($var,'sbSyncErrs',0));
}
[$m,$h] = explode(' ', $parity['hour']);
[$m,$h] = explode(' ',$parity['hour']);
$time = time();
$check = true;
switch ($parity['mode']) {
@@ -476,17 +460,14 @@ while (true) {
case 'WL': $t = stage(0); break;}
break;
}
$echo[$a][] = "\n";
if ($check) {
$frmt = _var($display,'date').(_var($display,'date')!='%c' ? ", "._var($display,'time') : "");
$echo[$a][] = sprintf(_('Next check scheduled on **%s**'),_(my_date($frmt,$time+$t),0));
$echo[$a][] = "<br><i class='fa fa-fw fa-clock-o'></i> "._('Due in').": "._(my_clock(floor($t/60)),2);
$extra = sprintf(_('Next check scheduled on **%s**'),_(my_date($frmt,$time+$t),0))."<br><i class='fa fa-fw fa-clock-o'></i> "._('Due in').": "._(my_clock(floor($t/60)),2);
} else {
$echo[$a][] = _('Scheduled parity check is disabled');
$extra = _('Scheduled parity check is disabled');
}
$echo[$a] = [implode($echo[$a]), $extra];
}
$echo[$a] = implode($echo[$a]);
$echo = json_encode($echo);
$md5_new = md5($echo,true);
if ($md5_new !== $md5_old) {
+13 -13
View File
@@ -68,8 +68,8 @@ while (true) {
$locale_init = _var($display,'locale');
update_translation($locale_init);
}
unset($status,$rows,$power,$load,$freq,$output,$volt);
$status = array_fill(0,7,"<span>-</span>");
unset($echo,$rows,$power,$load,$freq,$output,$volt);
$echo = array_fill(0,7,"<span>-</span>");
if (file_exists("/var/run/apcupsd.pid")) {
// get battery-level and runtime settings
$cfg = parse_plugin_cfg('dynamix.apcupsd');
@@ -80,32 +80,32 @@ while (true) {
[$key, $val] = array_map('trim', explode(':', $row, 2));
switch ($key) {
case 'MODEL':
$status[0] = $val;
$echo[0] = $val;
break;
case 'STATUS':
$text = strtr($val, $state);
$status[1] = $val ? (strpos($val,'ONLINE')!==false ? "<span $green>$text</span>" : "<span $red>$text</span>") : "<span $orange>"._('Refreshing')."...</span>";
$echo[1] = $val ? (strpos($val,'ONLINE')!==false ? "<span $green>$text</span>" : "<span $red>$text</span>") : "<span $orange>"._('Refreshing')."...</span>";
break;
case 'BCHARGE':
$charge = round($val);
$status[2] = $charge>$level ? "<span $green>$charge %</span>" : "<span $red>$charge %</span>";
$echo[2] = $charge>$level ? "<span $green>$charge %</span>" : "<span $red>$charge %</span>";
break;
case 'TIMELEFT':
$time = round($val);
$unit = _('minutes');
$status[3] = $time>$runtime ? "<span $green>$time $unit</span>" : "<span $red>$time $unit</span>";
$echo[3] = $time>$runtime ? "<span $green>$time $unit</span>" : "<span $red>$time $unit</span>";
break;
case 'NOMPOWER':
$power = $val;
$status[4] = $power>0 ? "<span $green>$power W</span>" : "<span $red>$power W</span>";
$echo[4] = $power>0 ? "<span $green>$power W</span>" : "<span $red>$power W</span>";
break;
case 'LOADPCT':
$load = $val;
$status[5] = round($load)." %";
$echo[5] = round($load)." %";
break;
case 'OUTPUTV':
$output = round($val);
$status[6] = "$output V";
$echo[6] = "$output V";
break;
case 'NOMINV':
$volt = $val;
@@ -117,11 +117,11 @@ while (true) {
break;
}
}
if (isset($power) && isset($load)) $status[5] = ($load<90 ? "<span $green>" : "<span $red>").round($power*$load/100)." W (".$status[5].")</span>";
elseif (isset($load)) $status[5] = ($load<90 ? "<span>" : "<span $red>").$status[5]."</span>";
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<span $green>" : "<span $red>").$status[6].(isset($freq) ? " ~ $freq Hz" : "")."</span>") : $status[6];
if (isset($power) && isset($load)) $echo[5] = ($load<90 ? "<span $green>" : "<span $red>").round($power*$load/100)." W (".$echo[5].")</span>";
elseif (isset($load)) $echo[5] = ($load<90 ? "<span>" : "<span $red>").$echo[5]."</span>";
$echo[6] = isset($output) ? ((empty($volt) || ($minv<$output && $output<$maxv) ? "<span $green>" : "<span $red>").$echo[6].(isset($freq) ? " ~ $freq Hz" : "")."</span>") : $echo[6];
}
$echo = implode(';', $status);
$echo = json_encode($echo);
$md5_new = md5($echo,true);
if ($md5_new !== $md5_old) {
publish('apcups', $echo);
+8 -2
View File
@@ -51,12 +51,12 @@ function write(...$messages){
}
curl_close($com);
}
function run($cmd, &$save=null) {
function run($cmd, &$save=null, $timeout=30) {
global $cli,$diag;
// output command for display
write($cmd);
// execute command with timeout of 30s
exec("timeout -s9 30 $cmd", $save);
exec("timeout -s9 $timeout $cmd", $save);
return implode("\n",$save);
}
@@ -351,6 +351,12 @@ if ($cli) {
$date = "{$split[2]}-{$split[3]}";
}
// Run Fix Common Problems if present and results are old / not present
if ( is_file("/usr/local/emhttp/plugins/fix.common.problems/scripts/scan.php") ) {
if ( ! is_file("/tmp/fix.common.problems/errors.json") || (time() - filemtime("/tmp/fix.common.problems/errors.json")) > 86400) {
run("/usr/local/emhttp/plugins/fix.common.problems/scripts/scan.php diagnostics",$ignore,60);
}
}
// don't anonymize system share names
$vardomain = (array)@parse_ini_file('/boot/config/domain.cfg');
$vardocker = (array)@parse_ini_file('/boot/config/docker.cfg');
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
if [[ -n $1 ]]; then
# $1 is new governor
echo $1 | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor &>/dev/null
fi
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/php -q
<?PHP
$cfg = '/boot/config/favorites.cfg';
if (!file_exists($cfg)) exit(0);
$file = fopen($cfg,'r');
while (($page = fgets($file))!==false) {
// update each favorite
$page = rtrim($page);
$line = fopen($page,'r');
// get current Menu settings
extract(parse_ini_string(fgets($line)));
fclose($line);
// remove and re-add label and escape single quotes for sed command
$Menu = str_replace([' MyFavorites',"'"],['',"'\''"],$Menu).' MyFavorites';
// update Menu settings
exec("sed -ri '0,/^Menu=\".+\"$/s//Menu=\"$Menu\"/' $page 2>/dev/null");
}
fclose($file);
exit(0);
?>
+7 -7
View File
@@ -35,8 +35,9 @@ span.w26{min-width:26%;max-width:26%;display:inline-block;float:left;overflow:hi
span.w36{min-width:36%;max-width:36%;display:inline-block;float:left;overflow:hidden;text-overflow:ellipsis}
span.w44{min-width:44%;max-width:44%;display:inline-block;float:left;overflow:hidden;text-overflow:ellipsis}
span.w72{min-width:72%;max-width:72%;display:inline-block;float:left;overflow:hidden;text-overflow:ellipsis}
span.w18:hover{overflow:visible}
span.center{display:block;width:96px;text-align:center;margin:4px 0 8px 0}
span.w26:hover,span.w18:hover{overflow:visible}
span.center{text-align:center;margin-bottom:4px}
span.center>div{margin:0 auto}
select#cpuline,select#netline{border:none;padding:0 12px 0 0}
select[name=enter_share],select[name=enter_user]{margin-top:0;float:none}
img#mycase{width:auto;max-width:128px;height:auto;max-height:128px}
@@ -53,7 +54,7 @@ i[class^="icon-u-"]{font-size:inherit}
i#mycase[class^="case-"]{font-size:128px}
i#mycase[class^="fa "]{font-size:96px}
a.cpu_close,span.hand{cursor:pointer;z-index:1001}
a.info{white-space:normal;word-spacing:40px}
a.info{white-space:normal;word-spacing:92px;word-break:break-all}
a.info span{word-spacing:normal}
tr#var0,tr#var1,tr#var2,tr#var3,tr#var4{cursor:alias}
tr#var1,tr#var4,tr#cpu_chart,.cpu_open{display:none}
@@ -70,9 +71,8 @@ input[value=Edit]{margin:12px 0 0 0;padding:5px 10px}
#current_date{font-size:1.3rem;margin-left:18px}
table.snapshot{margin-top:0}
.switch-button-background{margin-top:4px!important}
div.pie{height:96px;width:96px;border-radius:50%;display:flex;justify-content:center;align-items:center}
div.pie::after{content:'';position:absolute;height:72px;width:72px;border-radius:50%}
div.pie{height:92px;width:92px;border-radius:50%;display:flex;justify-content:center;align-items:center}
div.pie::after{content:'';position:absolute;height:68px;width:68px;border-radius:50%}
div.pie span{z-index:2;font-size:1.6rem;font-weight:bold}
div.more{margin-top:8px}
.var0,.var1,.var2,.var3{display:none;font-size:1.3rem!important}
legend{font-variant:small-caps;margin:8px 0 4px 0}
legend{font-variant:small-caps;margin-bottom:4px}
@@ -0,0 +1,2 @@
input[type=radio]{margin:0 10px 0 0}
div#vm{display:none;margin-left:35%}
@@ -19,6 +19,7 @@ i.spacing{margin-left:0;margin-right:10px}
i.icon{font-size:1.6rem;margin-right:4px;vertical-align:middle}
i.title{display:none}
i.control{cursor:pointer;color:#909090;font-size:1.8rem}
i.favo{display:none;font-size:1.8rem;position:absolute}
pre ul{margin:0;padding-top:0;padding-bottom:0;padding-left:28px}
pre li{margin:0;padding-top:0;padding-bottom:0;padding-left:18px}
big{font-size:1.4rem;font-weight:bold;text-transform:uppercase}
@@ -121,6 +122,7 @@ table.unraid thead tr:first-child>td{font-size:1.2rem;text-transform:uppercase;l
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(0,0,0,0.05)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}
@@ -19,6 +19,7 @@ i.spacing{margin-left:-6px}
i.icon{font-size:1.6rem;margin-right:4px;vertical-align:middle}
i.title{margin-right:8px}
i.control{cursor:pointer;color:#606060;font-size:1.8rem}
i.favo{display:none;font-size:1.8rem;position:absolute;margin-left:12px}
hr{border:none;height:1px!important;color:#2b2b2b;background-color:#2b2b2b}
input[type=text],input[type=password],input[type=number],input[type=url],input[type=email],input[type=date],input[type=file],textarea,.textarea{font-family:clear-sans;font-size:1.3rem;background-color:transparent;border:none;border-bottom:1px solid #e5e5e5;padding:4px 0;text-indent:0;min-height:2rem;line-height:2rem;outline:none;width:300px;margin:0 20px 0 0;box-shadow:none;border-radius:0;color:#f2f2f2}
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:1.8px;text-transform:uppercase;min-width:86px;margin:10px 12px 10px 0;padding:8px;text-align:center;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:none;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
@@ -30,7 +31,7 @@ input:hover[type=button],input:hover[type=reset],input:hover[type=submit],button
input[disabled],textarea[disabled]{color:#f2f2f2;border-bottom-color:#6c6c6c;opacity:0.5;cursor:default}
input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled],button[disabled],button[type=button][disabled],a.button[disabled]
input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],a.button:hover[disabled]
input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],a.button:active[disabled]{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],a.button:active[disabled]{opacity:0.5;cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
input::-webkit-input-placeholder{color:#486dba}
select{-webkit-appearance:none;font-family:clear-sans;font-size:1.3rem;min-width:166px;max-width:300px;padding:5px 8px 5px 0;text-indent:0;margin:0 10px 0 0;border:none;border-bottom:1px solid #e5e5e5;box-shadow:none;border-radius:0;color:#f2f2f2;background-color:transparent;background-image:linear-gradient(66.6deg, transparent 60%, #f2f2f2 40%),linear-gradient(113.4deg, #f2f2f2 40%, transparent 60%);background-position:calc(100% - 4px),100%;background-size:4px 6px,4px 6px;background-repeat:no-repeat;outline:none;display:inline-block;cursor:pointer}
select option{color:#f2f2f2;background-color:#262626}
@@ -119,6 +120,7 @@ table.unraid tbody tr:nth-child(even){background-color:#212121}
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(255,255,255,0.1)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}
@@ -209,7 +211,7 @@ div.tab [type=radio]+label~.content{display:none}
div.tab [type=radio]:checked+label~.content{display:inline}
div.tab [type=radio]+label{position:relative;font-size:1.4rem;letter-spacing:1.8px;padding:4px 10px;margin-right:2px;border-top-left-radius:6px;border-top-right-radius:6px;border:1px solid #6c6c6c;border-bottom:none;background-color:#3c3c3c;opacity:0.5}
div.tab [type=radio]+label img{padding-right:4px}
div.Panel{text-align:center;float:left;margin:0 30px 30px 12px;height:8rem}
div.Panel{text-align:center;float:left;margin:0 0 30px 10px;padding-right:50px;height:8rem}
div.Panel a{text-decoration:none}
div.Panel span{height:42px;display:block}
div.Panel:hover .PanelText{text-decoration:underline}
@@ -19,6 +19,7 @@ i.spacing{margin-left:0;margin-right:10px}
i.icon{font-size:1.6rem;margin-right:4px;vertical-align:middle}
i.title{display:none}
i.control{cursor:pointer;color:#606060;font-size:1.8rem}
i.favo{display:none;font-size:1.8rem;position:absolute}
pre ul{margin:0;padding-top:0;padding-bottom:0;padding-left:28px}
pre li{margin:0;padding-top:0;padding-bottom:0;padding-left:18px}
big{font-size:1.4rem;font-weight:bold;text-transform:uppercase}
@@ -31,7 +32,7 @@ input[type=number]{-moz-appearance:textfield}
input:focus[type=text],input:focus[type=password],input:focus[type=number],input:focus[type=url],input:focus[type=email],input:focus[type=file],textarea:focus{background-color:#121510;border-color:#0072c6}
input:hover[type=button],input:hover[type=reset],input:hover[type=submit],button:hover,button:hover[type=button],a.button:hover{border-color:#0072c6;color:#b0b0b0}
input:active[type=button],input:active[type=reset],input:active[type=submit],button:active,button:active[type=button],a.button:active{border-color:#0072c6;box-shadow:none}
input[disabled],button[disabled],input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],textarea[disabled]{color:#808080;border-color:#808080;background-color:#383a34;opacity:0.3;cursor:default}
input[disabled],button[disabled],input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],textarea[disabled]{color:#808080;border-color:#808080;background-color:#383a34;opacity:0.5;cursor:default}
input::-webkit-input-placeholder{color:#00529b}
select{-webkit-appearance:none;font-family:clear-sans;font-size:1.3rem;min-width:188px;max-width:314px;padding:6px 14px 6px 6px;margin:0 10px 0 0;border:1px solid #606e7f;box-shadow:none;border-radius:0;color:#606e7f;background-color:transparent;background-image:linear-gradient(66.6deg, transparent 60%, #606e7f 40%),linear-gradient(113.4deg, #606e7f 40%, transparent 60%);background-position:calc(100% - 8px),calc(100% - 4px);background-size:4px 6px,4px 6px;background-repeat:no-repeat;outline:none;display:inline-block;cursor:pointer}
select option{color:#606e7f;background-color:#121510}
@@ -121,6 +122,7 @@ table.unraid thead tr:first-child>td{font-size:1.2rem;text-transform:uppercase;l
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(255,255,255,0.05)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}
@@ -6,7 +6,7 @@ input:hover[type=button],input:hover[type=reset],input:hover[type=submit],button
input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled],button[disabled],button[type=button][disabled],a.button[disabled]
input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],a.button:hover[disabled]
input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],a.button:active[disabled]
{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
{opacity:0.5;cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
table{border-collapse:collapse;border-spacing:0;margin:0;width:100%}
table thead td{padding:6px 0}
table tbody td{padding:4px 0}
@@ -19,6 +19,7 @@ i.spacing{margin-left:-6px}
i.icon{font-size:1.6rem;margin-right:4px;vertical-align:middle}
i.title{margin-right:8px}
i.control{cursor:pointer;color:#909090;font-size:1.8rem}
i.favo{display:none;font-size:1.8rem;position:absolute;margin-left:12px}
hr{border:none;height:1px!important;color:#e3e3e3;background-color:#e3e3e3}
input[type=text],input[type=password],input[type=number],input[type=url],input[type=email],input[type=date],input[type=file],textarea,.textarea{font-family:clear-sans;font-size:1.3rem;background-color:transparent;border:none;border-bottom:1px solid #1c1b1b;padding:4px 0;text-indent:0;min-height:2rem;line-height:2rem;outline:none;width:300px;margin:0 20px 0 0;box-shadow:none;border-radius:0;color:#1c1b1b}
input[type=button],input[type=reset],input[type=submit],button,button[type=button],a.button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:1.8px;text-transform:uppercase;min-width:86px;margin:10px 12px 10px 0;padding:8px;text-align:center;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:none;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
@@ -30,7 +31,7 @@ input:hover[type=button],input:hover[type=reset],input:hover[type=submit],button
input[disabled],textarea[disabled]{color:#1c1b1b;border-bottom-color:#a2a2a2;opacity:0.5;cursor:default}
input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled],button[disabled],button[type=button][disabled],a.button[disabled]
input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],a.button:hover[disabled]
input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],a.button:active[disabled]{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],a.button:active[disabled]{opacity:0.5;cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
input::-webkit-input-placeholder{color:#486dba}
select{-webkit-appearance:none;font-family:clear-sans;font-size:1.3rem;min-width:166px;max-width:300px;padding:5px 8px 5px 0;text-indent:0;margin:0 10px 0 0;border:none;border-bottom:1px solid #1c1b1b;box-shadow:none;border-radius:0;color:#1c1b1b;background-color:transparent;background-image:linear-gradient(66.6deg, transparent 60%, #1c1b1b 40%),linear-gradient(113.4deg, #1c1b1b 40%, transparent 60%);background-position:calc(100% - 4px),100%;background-size:4px 6px,4px 6px;background-repeat:no-repeat;outline:none;display:inline-block;cursor:pointer}
select option{color:#1c1b1b;background-color:#e8e8e8}
@@ -119,6 +120,7 @@ table.unraid tbody tr:nth-child(even){background-color:#ededed}
table.unraid tbody tr:not(.tr_last):hover>td{background-color:rgba(0,0,0,0.1)}
table.unraid tr>td{overflow:hidden;text-overflow:ellipsis;padding-left:8px}
table.unraid tr>td:hover{overflow:visible}
table.legacy{table-layout:auto}
table.disk_status{table-layout:fixed}
table.disk_status tr>td:last-child{padding-right:8px}
table.disk_status tr>td:nth-child(1){width:13%}
@@ -209,7 +211,7 @@ div.tab [type=radio]+label~.content{display:none}
div.tab [type=radio]:checked+label~.content{display:inline}
div.tab [type=radio]+label{position:relative;font-size:1.4rem;letter-spacing:1.8px;padding:4px 10px;margin-right:2px;border-top-left-radius:6px;border-top-right-radius:6px;border:1px solid #b2b2b2;border-bottom:none;background-color:#e2e2e2;opacity:0.5}
div.tab [type=radio]+label img{padding-right:4px}
div.Panel{text-align:center;float:left;margin:0 30px 30px 12px;height:8rem}
div.Panel{text-align:center;float:left;margin:0 0 30px 10px;padding-right:50px;height:8rem}
div.Panel a{text-decoration:none}
div.Panel span{height:42px;display:block}
div.Panel:hover .PanelText{text-decoration:underline}
+12
View File
@@ -70,6 +70,18 @@ $path = substr(strtok(_var($_SERVER,'REQUEST_URI'),'?'),1);
// The current "task" is the first element of the path
$task = strtok($path,'/');
// Add translation for favorites page
if ($locale && $task=='Favorites') {
foreach(['settings','tools'] as $more) {
$text = "$docroot/languages/$locale/$more.txt";
if (!file_exists($text)) continue;
// additional translations
$store = "$docroot/languages/$locale/$more.dot";
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
$language = array_merge($language,unserialize(file_get_contents($store)));
}
}
// Here's the page we're rendering
$myPage = $site[basename($path)];
$pageroot = $docroot.'/'._var($myPage,'root');