From ac86b11fb13925a90165767c6d07dccdff314000 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 28 Apr 2016 08:59:05 +0200 Subject: [PATCH 1/6] Updated diagnostics utility --- plugins/dynamix/scripts/diagnostics | 59 +++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/plugins/dynamix/scripts/diagnostics b/plugins/dynamix/scripts/diagnostics index 6b4489333..81ebd686c 100755 --- a/plugins/dynamix/scripts/diagnostics +++ b/plugins/dynamix/scripts/diagnostics @@ -16,6 +16,10 @@ $opt = getopt('a',['all']); $all = isset($opt['a']) || isset($opt['all']); $zip = $all ? $argv[2] : $argv[1]; $cli = empty($zip); +$get = "/var/local/emhttp"; +$var = file_exists("$get/var.ini") ? parse_ini_file("$get/var.ini") : []; + +$folders = ['/boot','/boot/config','/boot/config/plugins','/boot/extra','/boot/syslinux','/var/log','/var/log/plugins','/var/log/packages','/tmp']; function anonymize($text,$select) { global $all; @@ -47,7 +51,6 @@ if ($cli) { // script is called from CLI echo "Starting diagnostics collection... "; exec("mkdir -p /boot/logs"); - $var = @parse_ini_file("/var/local/emhttp/var.ini"); $server = isset($var['NAME']) ? str_replace(' ','_',strtolower($var['NAME'])) : 'tower'; $date = date('Ymd-Hi'); $diag = "$server-diagnostics-$date"; @@ -60,8 +63,11 @@ if ($cli) { } // create folder structure exec("mkdir -p /$diag/system /$diag/config /$diag/logs /$diag/shares /$diag/smart /$diag/qemu"); +// make unRAID version reference +$unraid = parse_ini_file('/etc/unraid-version'); +file_put_contents("/$diag/unRAID-".$unraid['version'].".txt",$unraid['version']); // copy ini variables -foreach (glob("/var/local/emhttp/*.ini") as $file) { +foreach (glob("$get/*.ini") as $file) { $ini = basename($file,".ini"); // skip users file in anonymized mode if ($all || $ini != "users") file_put_contents("/$diag/system/vars.txt",preg_replace(["/\n/","/^Array/"],["\r\n",$ini],anonymize(print_r(parse_ini_file($file,true),true),1)),FILE_APPEND); @@ -73,6 +79,7 @@ exec("free -mt 2>/dev/null|todos >/$diag/system/memory.txt"); exec("ps -ef 2>/dev/null|todos >/$diag/system/ps.txt"); exec("lsof -Pni 2>/dev/null|todos >/$diag/system/lsof.txt"); exec("lsmod 2>/dev/null|todos >/$diag/system/lsmod.txt"); +exec("df -h 2>/dev/null|todos >/$diag/system/df.txt"); exec("ifconfig -s 2>/dev/null|grep -Po '^(eth|bond)[0-9]+'", $ports); // create ethernet information information (suppress errors) foreach ($ports as $port) { @@ -85,6 +92,11 @@ exec("ifconfig 2>/dev/null|todos >/$diag/system/ifconfig.txt"); // create system information (suppress errors) exec("find /sys/kernel/iommu_groups/ -type l 2>/dev/null|todos >/$diag/system/iommu_groups.txt"); exec("todos /$diag/system/cmdline.txt"); +// create folder structure listing +$dest = "/$diag/system/folders.txt"; +foreach ($folders as $folder) { + if (is_dir($folder)) exec("echo -ne \"\r\n$folder\r\n\" >>$dest;ls -l $folder|todos >>$dest"); else exec("echo -ne \"\r\n$folder\r\nfolder does not exist\r\n\" >>$dest"); +} // copy configuration files (suppress errors) exec("cp /boot/config/*.{cfg,conf,dat} /boot/config/go /$diag/config 2>/dev/null"); // anonymize configuration files @@ -98,27 +110,29 @@ foreach ($files as $file) { if (!$all) exec("sed -ri 's/^(share(Comment|ReadList|WriteList)=\")[^\"]+/\\1.../' '$dest' 2>/dev/null"); } // create default user shares information -$ini = "/var/local/emhttp/shares.ini"; -$shares = file_exists($ini) ? parse_ini_file($ini, true) : []; +$shares = file_exists("$get/shares.ini") ? parse_ini_file("$get/shares.ini", true) : []; foreach ($shares as $share) { $name = $share['name']; if (!in_array("/boot/config/shares/$name.cfg",$files)) file_put_contents(anonymize("/$diag/shares/$name.cfg",2),"# This share has default settings.\r\n"); } // copy syslog information (anonymize if applicable) +$max = 3*1024*1024; //3MB foreach (glob("/var/log/syslog*") as $file) { - $dest = "/$diag/logs/".basename($file).".txt"; - exec("todos <$file >$dest"); + $log = "/$diag/logs/".basename($file); + exec("todos <$file >$log.txt"); if (!$all) { unset($titles,$rows); - exec("grep -Po 'logger: moving \"\K[^\"]+' $dest 2>/dev/null|sort|uniq", $titles); - exec("sed -ri 's|\b\S+@\S+\.\S+\b|xxx@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' $dest"); + exec("grep -Po 'logger: moving \"\K[^\"]+' $log.txt 2>/dev/null|sort|uniq", $titles); + exec("sed -ri 's|\b\S+@\S+\.\S+\b|xxx@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' $log.txt"); foreach ($titles as $mover) { $title = "/{$mover[0]}..".substr($mover,-1)."/..."; - exec("sed -ri 's|(logger: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' $dest 2>/dev/null"); + exec("sed -ri 's|(logger: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' $log.txt 2>/dev/null"); } - exec("grep -n ' cache_dirs: -' $dest 2>/dev/null|cut -d: -f1", $rows); - for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) exec("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' $dest 2>/dev/null"); + exec("grep -n ' cache_dirs: -' $log.txt 2>/dev/null|cut -d: -f1", $rows); + for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) exec("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' $log.txt 2>/dev/null"); } + exec("tail -n 200 $log.txt >$log.last200.txt"); + exec("truncate -s '<$max' $log.txt"); } // copy docker information (if existing) $docker = "/var/log/docker.log"; @@ -131,10 +145,31 @@ if ($qemu) else file_put_contents("/$diag/qemu/no qemu log files",""); // create SMART reports (suppress errors) +$disks = file_exists("$get/disks.ini") ? parse_ini_file("$get/disks.ini", true) : []; +include_once '/usr/local/emhttp/webGui/include/CustomMerge.php'; exec("ls -l /dev/disk/by-id/[au]* 2>/dev/null|awk '$0!~/-part/{split($11,a,\"/\");print a[3],substr($9,21)}'", $devices); foreach ($devices as $device) { $disk = explode(' ',$device); - exec("smartctl -a /dev/${disk[0]} 2>/dev/null|todos >/$diag/smart/${disk[1]}-$date.txt"); + $type = ''; + foreach ($disks as $find) { + if ($find['device']==$disk[0]) { + $type = isset($find['smType']) ? $find['smType'] : -1; + if ($type==-1) $type = isset($var['smType']) ? $var['smType'] : ''; + if ($type) { + $ports = []; + if (isset($find['smDevice']) && strlen($find['smDevice'])) $port = $find['smDevice']; + if (isset($find['smPort1']) && strlen($find['smPort1'])) $ports[] = $find['smPort1']; + if (isset($find['smPort2']) && strlen($find['smPort2'])) $ports[] = $find['smPort2']; + if (isset($find['smPort3']) && strlen($find['smPort3'])) $ports[] = $find['smPort3']; + if ($ports) { + $glue = isset($find['smGlue']) ? $find['smGlue'] : ','; + $type .= ','.implode($glue,$ports); + } + } + break; + } + } + exec("smartctl -a $type /dev/${disk[0]} 2>/dev/null|todos >/$diag/smart/${disk[1]}-$date.txt"); } // create resulting zip file and remove temp folder exec("zip -qmr $zip /$diag"); From 94ebb0222ea490b96fe650e83f3391ff91d0cd04 Mon Sep 17 00:00:00 2001 From: bergware Date: Sat, 30 Apr 2016 10:46:08 +0200 Subject: [PATCH 2/6] Plugin manager: added unRAID min and max version attributes --- plugins/dynamix.plugin.manager/scripts/plugin | 60 ++++++++++++++----- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/plugins/dynamix.plugin.manager/scripts/plugin b/plugins/dynamix.plugin.manager/scripts/plugin index 8952ce0ed..588384ca8 100755 --- a/plugins/dynamix.plugin.manager/scripts/plugin +++ b/plugins/dynamix.plugin.manager/scripts/plugin @@ -3,7 +3,7 @@ // Copyright 2015, Lime Technology LLC. // License: GPLv2 only // -// Program updates made by Bergware International (December 2014) +// Program updates made by Bergware International (April 2016) $usage = <<attributes()->Method)) { if (!in_array($method, explode(" ", $file->attributes()->Method))) continue; } else if ($method != "install") continue; - - // Name can be missing but only makes sense if Run attribute is present $name = $file->attributes()->Name; + // bergware - check unRAID version dependency (if present) + $min = $file->attributes()->Min; + if ($min && version_compare($unraid['version'],$min,'<')) { + echo "plugin: skipping: ".basename($name)." - unRAID version too low, requires at least version $min\n"; + continue; + } + $max = $file->attributes()->Max; + if ($max && version_compare($unraid['version'],$max,'>')) { + echo "plugin: skipping: ".basename($name)." - unRAID version too high, requires at most version $max\n"; + continue; + } + // Name can be missing but only makes sense if Run attribute is present if ($name) { // Ensure parent directory exists // @@ -382,6 +393,7 @@ if ($argc < 3) { // b) [plugin_file] is a URL // c) dirname of [plugin_file] is not /boot/config/plugins // +$unraid = parse_ini_file('/etc/unraid-version'); if ($method == "install") { echo "plugin: installing: $argv[2]\n"; // check for URL @@ -396,9 +408,18 @@ if ($method == "install") { } } else $plugin_file = realpath($argv[2]); - + // bergware - check unRAID version dependency (if present) + $min = plugin("min", $plugin_file, $error); + if ($min && version_compare($unraid['version'],$min,'<')) { + echo "plugin: installed unRAID version is too low, require at least version $min\n"; + exit(1); + } + $max = plugin("max", $plugin_file, $error); + if ($max && version_compare($unraid['version'],$max,'>')) { + echo "plugin: installed unRAID version is too high, require at most version $max\n"; + exit(1); + } $plugin = basename($plugin_file); - // check for re-install $installed_plugin_file = @readlink("/var/log/plugins/$plugin"); if ($installed_plugin_file !== false) { @@ -418,13 +439,12 @@ if ($method == "install") { exit(1); } // do not re-install if same plugin already installed or has higher version - if (strcmp($version, $installed_version) <= 0) { - if (strcmp($version, $installed_version) < 0) { - echo "plugin: not installing older version\n"; - } - if (strcmp($plugin_version, $installed_version) == 0) { - echo "plugin: not reinstalling same version\n"; - } + if (strcmp($version, $installed_version) < 0) { + echo "plugin: not installing older version\n"; + exit(1); + } + if (strcmp($version, $installed_version) == 0) { + echo "plugin: not reinstalling same version\n"; exit(1); } if (plugin("install", $plugin_file, $error) === false) { @@ -445,9 +465,8 @@ if ($method == "install") { exit(1); } } - // register successful install - // Bergware change: add user or system plugin selection + // Bergware change: add user or system plugin selection - deprecated $plugintype = plugin("plugintype", $plugin_file, $error); $target = $plugintype != "system" ? "/boot/config/plugins/$plugin" : "/boot/plugins/$plugin"; if ($target != $plugin_file) copy($plugin_file, $target); @@ -533,6 +552,17 @@ if ($method == "update") { echo "plugin: $plugin_file does not exist, check first\n"; exit (1); } + // bergware - check unRAID version dependency (if present) + $min = plugin("min", $plugin_file, $error); + if ($min && version_compare($unraid['version'],$min,'<')) { + echo "plugin: installed unRAID version is too low, require at least version $min\n"; + exit(1); + } + $max = plugin("max", $plugin_file, $error); + if ($max && version_compare($unraid['version'],$max,'>')) { + echo "plugin: installed unRAID version is too high, require at most version $max\n"; + exit(1); + } // install the updated plugin if (plugin("install", $plugin_file, $error) === false) { echo "plugin: $error\n"; From 7390691369fe0edc7e765b0f7a8c97e0c777f593 Mon Sep 17 00:00:00 2001 From: bergware Date: Sat, 30 Apr 2016 21:11:59 +0200 Subject: [PATCH 3/6] Support of extended data array and cache pool size on Dashboard page --- plugins/dynamix/DashStats.page | 73 ++++++++++++++++-------- plugins/dynamix/include/DashUpdate.php | 69 ++++++++++++++-------- plugins/dynamix/styles/default-black.css | 3 +- plugins/dynamix/styles/default-white.css | 3 +- 4 files changed, 98 insertions(+), 50 deletions(-) diff --git a/plugins/dynamix/DashStats.page b/plugins/dynamix/DashStats.page index 87a0528d8..8d5e50a67 100644 --- a/plugins/dynamix/DashStats.page +++ b/plugins/dynamix/DashStats.page @@ -33,8 +33,8 @@ $memory_maximum = exec("dmidecode -t 16 | awk -F: '/^\tMaximum Capacity: [0-9]+ // If maximum < installed then roundup maximum to the next power of 2 size of installed. E.g. 6 -> 8 or 12 -> 16 if ($memory_maximum*1024 < $memory_installed) $memory_maximum = pow(2,ceil(log($memory_installed/1024)/log(2))); -function init_row($label,$slots) { - echo "$label".str_repeat("",$slots).""; +function init_row($label) { + echo "$label".str_repeat("",30).""; } function parity_status() { global $var,$disks; @@ -105,6 +105,11 @@ function export_settings($protocol,$share) { if ($share['export']=='e') return ucfirst($share['security']); return ''.ucfirst($share['security']).''; } +function active_disks($disk) { + return $disk['status']!='DISK_NP' && preg_match('/^(Parity|Data|Cache)$/',$disk['type']); +} +$disks = array_filter($disks,'active_disks'); +$slots = count($disks) + count($devs); ?> @@ -112,32 +117,48 @@ function export_settings($protocol,$share) { -"); $i = 0; -foreach ($disks as $disk) - if ($disk['type']=='Parity' && $disk['status']!='DISK_NP') - $row0[$i++] = ""; -foreach ($disks as $disk) - if ($disk['type']=='Data' && $disk['status']!='DISK_NP') - $row0[$i++] = ""; -foreach ($disks as $disk) - if ($disk['type']=='Cache' && $disk['status']!='DISK_NP') - $row0[$i++] = ""; -foreach ($devs as $dev) - $row0[$i++] = ""; +$row0 = array_fill(0,30,""); $i = 0; +foreach ($disks as $disk) if ($disk['type']=='Parity') $row0[$i++] = ""; +foreach ($disks as $disk) if ($disk['type']=='Data') $row0[$i++] = ""; +if ($slots <= 30) { + foreach ($disks as $disk) if ($disk['type']=='Cache') $row0[$i++] = ""; + foreach ($devs as $dev) $row0[$i++] = ""; +} +echo "".implode('',$row0); +?> + + + + + + + + + + + + 30):?> +
+ + +-"); $i = 0; +foreach ($disks as $disk) if ($disk['type']=='Cache' && $disk['status']!='DISK_NP') $row0[$i++] = ""; echo "".implode('',$row0); ?> - - - - - - - + + + + + + + + + @@ -400,8 +421,12 @@ function update30() { $.post('',{cmd:'port',view:tag,ports:''},function(data) { if (data) $.each(data.split('#'),function(k,v) {$('#'+tag+k).html(v);}); }); - $.post('',{cmd:'disk',hot:'',max:'',unit:''},function(data) { - if (data) $('#dash1').html(data); + $.post('',{cmd:'disk',hot:'',max:'',unit:'',slots:},function(data) { + + if (data) $('#dash0').html(data); + + if (data) $.each(data.split('#'),function(k,v) {$('#dash'+k).html(v);}); + clearTimeout(timer2); timer2 = setTimeout(heatAlarm,2000); $('[id^="smart-"]').each(function() { diff --git a/plugins/dynamix/include/DashUpdate.php b/plugins/dynamix/include/DashUpdate.php index 3772d8549..30068c896 100644 --- a/plugins/dynamix/include/DashUpdate.php +++ b/plugins/dynamix/include/DashUpdate.php @@ -65,25 +65,28 @@ function mhz($speed) { function rpm($speed) { return "$speed RPM"; } +function active_disks($disk) { + return $disk['status']!='DISK_NP' && preg_match('/^(Parity|Data|Cache)$/',$disk['type']); +} $path = '/webGui/images'; $failed = ['FAILED','NOK']; switch ($_POST['cmd']) { case 'disk': $i = 1; $var = []; - $disks = @parse_ini_file('state/disks.ini',true); + $disks = @array_filter(parse_ini_file('state/disks.ini',true),'active_disks'); $devs = @parse_ini_file('state/devs.ini',true); $saved = @parse_ini_file('state/monitor.ini',true); require_once 'CustomMerge.php'; require_once 'Preselect.php'; - $slots = max(count($disks)+count($devs)-1, 25)+1; - $row1 = array_fill(0,$slots,''); my_insert($row1[0],'Active'); - $row2 = array_fill(0,$slots,''); my_insert($row2[0],'Inactive'); - $row3 = array_fill(0,$slots,''); my_insert($row3[0],'Unassigned'); - $row4 = array_fill(0,$slots,''); my_insert($row4[0],'Faulty'); - $row5 = array_fill(0,$slots,''); my_insert($row5[0],'Heat alarm'); - $row6 = array_fill(0,$slots,''); my_insert($row6[0],'SMART status'); - $row7 = array_fill(0,$slots,''); my_insert($row7[0],'Utilization'); + $slots = $_POST['slots']; + $row1 = array_fill(0,31,''); my_insert($row1[0],'Active'); + $row2 = array_fill(0,31,''); my_insert($row2[0],'Inactive'); + $row3 = array_fill(0,31,''); my_insert($row3[0],'Unassigned'); + $row4 = array_fill(0,31,''); my_insert($row4[0],'Faulty'); + $row5 = array_fill(0,31,''); my_insert($row5[0],'Heat alarm'); + $row6 = array_fill(0,31,''); my_insert($row6[0],'SMART status'); + $row7 = array_fill(0,31,''); my_insert($row7[0],'Utilization'); $funcRenderRow = function($n,$disk) use (&$row1,&$row2,&$row3,&$row4,&$row5,&$row6,&$row7,$path,$_POST) { if ($n>0) { $state = $disk['color']; @@ -115,22 +118,16 @@ case 'disk': my_usage($row7[$n],($disk['type']!='Parity' && $disk['fsStatus']=='Mounted')?(round((1-$disk['fsFree']/$disk['fsSize'])*100).'%'):''); } }; - foreach ($disks as $disk) - if ($disk['type']=='Parity' && $disk['status']!='DISK_NP') - $funcRenderRow($i++,$disk); - foreach ($disks as $disk) - if ($disk['type']=='Data' && $disk['status']!='DISK_NP') - $funcRenderRow($i++,$disk); - foreach ($disks as $disk) - if ($disk['type']=='Cache' && $disk['status']!='DISK_NP') { - if ($disk['name']!='cache') $disk['fsStatus']=='-'; - $funcRenderRow($i++,$disk); + foreach ($disks as $disk) if ($disk['type']=='Parity') $funcRenderRow($i++,$disk); + foreach ($disks as $disk) if ($disk['type']=='Data') $funcRenderRow($i++,$disk); + if ($slots <= 30) { + foreach ($disks as $disk) if ($disk['type']=='Cache') $funcRenderRow($i++,$disk); + foreach ($devs as $dev) { + $device = $dev['device']; + $state = exec("hdparm -C /dev/$device|grep -Po active") ? 'blue-on' : 'blue-blink'; + if ($state=='blue-on') my_smart($row6[$i],$device,'New'); + my_insert($row3[$i++],""); } - foreach ($devs as $dev) { - $device = $dev['device']; - $state = exec("hdparm -C /dev/$device|grep -Po active") ? 'blue-on' : 'blue-blink'; - if ($state=='blue-on') my_smart($row6[$i],$device,'New'); - my_insert($row3[$i++],""); } echo "".implode('',$row1).""; echo "".implode('',$row2).""; @@ -139,6 +136,30 @@ case 'disk': echo "".implode('',$row5).""; echo "".implode('',$row6).""; echo "".implode('',$row7).""; + if ($slots > 30) { + echo '#'; $i = 1; + $row1 = array_fill(0,31,''); my_insert($row1[0],'Active'); + $row2 = array_fill(0,31,''); my_insert($row2[0],'Inactive'); + $row3 = array_fill(0,31,''); my_insert($row3[0],'Unassigned'); + $row4 = array_fill(0,31,''); my_insert($row4[0],'Faulty'); + $row5 = array_fill(0,31,''); my_insert($row5[0],'Heat alarm'); + $row6 = array_fill(0,31,''); my_insert($row6[0],'SMART status'); + $row7 = array_fill(0,31,''); my_insert($row7[0],'Utilization'); + foreach ($disks as $disk) if ($disk['type']=='Cache') $funcRenderRow($i++,$disk); + foreach ($devs as $dev) { + $device = $dev['device']; + $state = exec("hdparm -C /dev/$device|grep -Po active") ? 'blue-on' : 'blue-blink'; + if ($state=='blue-on') my_smart($row6[$i],$device,'New'); + my_insert($row3[$i++],""); + } + echo "".implode('',$row1).""; + echo "".implode('',$row2).""; + echo "".implode('',$row3).""; + echo "".implode('',$row4).""; + echo "".implode('',$row5).""; + echo "".implode('',$row6).""; + echo "".implode('',$row7).""; + } break; case 'sys': exec("grep -Po '^Mem(Total|Available):\s+\K\d+' /proc/meminfo",$memory); diff --git a/plugins/dynamix/styles/default-black.css b/plugins/dynamix/styles/default-black.css index fb37ea32d..2317c40b7 100644 --- a/plugins/dynamix/styles/default-black.css +++ b/plugins/dynamix/styles/default-black.css @@ -148,7 +148,8 @@ table.share_status tr.share_status_size>td+td{padding-left:15px;} table.share_status tbody tr:nth-child(even){background-color:#0C0C0C;} table.share_status.share tr td:last-child{width:4%;text-align:right;padding-right:10px;} table.share_status.fixed{border:1px solid #202020;} -table.share_status.fixed tr>td+td{width:45px;text-align:center;padding:0;} +table.share_status.fixed thead tr>td+td{font-size:11px;} +table.share_status.fixed tr>td+td{width:38px;text-align:center;padding:0;} table.share_status.fixed tbody tr{border-bottom:1px #202020 dotted;} table.share_status.fixed tbody tr:nth-child(even){background-color:#000000;} table.share_status.fixed tbody tr td:nth-child(even){background-color:#0C0C0C;} diff --git a/plugins/dynamix/styles/default-white.css b/plugins/dynamix/styles/default-white.css index d01d889ca..2b6a59463 100644 --- a/plugins/dynamix/styles/default-white.css +++ b/plugins/dynamix/styles/default-white.css @@ -146,7 +146,8 @@ table.share_status tr.share_status_size>td+td{padding-left:15px;} table.share_status tbody tr:nth-child(even){background-color:#F8F8F8;} table.share_status.share tr td:last-child{width:4%;text-align:right;padding-right:10px;} table.share_status.fixed{border:1px solid #D0D0D0;} -table.share_status.fixed tr>td+td{width:45px;text-align:center;padding:0;} +table.share_status.fixed thead tr>td+td{font-size:11px;} +table.share_status.fixed tr>td+td{width:38px;text-align:center;padding:0;} table.share_status.fixed tbody tr{border-bottom:1px #D0D0D0 dotted;} table.share_status.fixed tbody tr:nth-child(even){background-color:#FFFFFF;} table.share_status.fixed tbody tr td:nth-child(even){background-color:#F8F8F8;} From cf4472fefbb5a97f5fe7b074a28e6571a8690805 Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 6 May 2016 16:42:24 +0200 Subject: [PATCH 4/6] Added "safe mode" indicator --- plugins/dynamix/include/DefaultPageLayout.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/plugins/dynamix/include/DefaultPageLayout.php b/plugins/dynamix/include/DefaultPageLayout.php index f4c107089..5dd62a34b 100644 --- a/plugins/dynamix/include/DefaultPageLayout.php +++ b/plugins/dynamix/include/DefaultPageLayout.php @@ -325,8 +325,6 @@ echo ""; ?>