Merge pull request #2 from limetech/master

LT Catchup
This commit is contained in:
Squidly271
2018-06-23 13:45:20 -04:00
committed by GitHub
16 changed files with 86 additions and 36 deletions

View File

@@ -20,9 +20,9 @@ exec("/etc/rc.d/rc.apcupsd stop");
exec("sed -i -e '/^NISIP/c\\NISIP 0.0.0.0' $conf");
exec("sed -i -e '/^UPSTYPE/c\\UPSTYPE '".str_replace("'","\\'",$new['UPSTYPE'])."'' $conf");
exec("sed -i -e '/^DEVICE/c\\DEVICE '".str_replace("'","\\'",$new['DEVICE'])."'' $conf");
exec("sed -i -e '/^BATTERYLEVEL/c\\BATTERYLEVEL '".str_replace("'","\\'",$new['BATTERYLEVEL'])."'' $conf");
exec("sed -i -e '/^MINUTES/c\\MINUTES '".str_replace("'","\\'",$new['MINUTES'])."'' $conf");
exec("sed -i -e '/^TIMEOUT/c\\TIMEOUT '".str_replace("'","\\'",$new['TIMEOUT'])."'' $conf");
exec("sed -i -e '/^BATTERYLEVEL/c\\BATTERYLEVEL '".intval($new['BATTERYLEVEL'])."'' $conf");
exec("sed -i -e '/^MINUTES/c\\MINUTES '".intval($new['MINUTES'])."'' $conf");
exec("sed -i -e '/^TIMEOUT/c\\TIMEOUT '".intval($new['TIMEOUT'])."'' $conf");
exec("sed -i -e '/^UPSCABLE/c\\UPSCABLE '".str_replace("'","\\'",$cable)."'' $conf");
if ($new['KILLUPS']=='yes' && $new['SERVICE']=='enable')

View File

@@ -35,6 +35,7 @@ img.paused{opacity:0.6}
.switch-button-label.off{color:inherit}
th.five{width:5%}
th.eight{width:8%}
th.load{width:100px}
tbody > tr.sortable:hover{cursor:move}
</style>
<div id="dialog-confirm" style="display:none;" title="Dialog Title"></div>
@@ -42,8 +43,8 @@ tbody > tr.sortable:hover{cursor:move}
<span class="status" style="margin-top:-44px"><span><input type="checkbox" class="advancedview"></span></span>
<div class="spinner fixed"></div>
<table id="docker_containers" class="tablesorter shift">
<thead><tr><th><a href="#" style="cursor:hand;margin-left:12px" onclick="resetSorting()" title="Reset sorting"><i class="fa fa-th-list"></i></a></th><th>Application</th><th>Version</th><th>Network</th><th>Port Mappings <small>(App to Host)</small></th><th>Volume Mappings <small>(App to Host)</small></th><th class="eight">Autostart</th><th class="five">Log</th></tr></thead>
<tbody id="docker_list"><tr><td colspan='8'><div class="spinner"></div></td></tr></tbody>
<thead><tr><th><a href="#" style="cursor:hand;margin-left:12px" onclick="resetSorting()" title="Reset sorting"><i class="fa fa-th-list"></i></a></th><th>Application</th><th>Version</th><th>Network</th><th>Port Mappings <small>(App to Host)</small></th><th>Volume Mappings <small>(App to Host)</small></th><th class="load advanced">CPU load</th><th class="load advanced">Memory load</th><th class="eight">Autostart</th><th class="five">Log</th></tr></thead>
<tbody id="docker_list"><tr><td class="advanced"></td><td colspan='8'><div class="spinner"></div></td><td class="advanced"></td></tr></tbody>
</table>
<input type="button" onclick="addContainer()" value="Add Container" style="display:none">
<input type="button" onclick="startAll()" value="Start all Containers" style="display:none">
@@ -101,6 +102,9 @@ function loadlist(update) {
resize();
$(window).bind('resize',function(){resize(true);});
<?endif;?>
$('.iconstatus').each(function(){
if ($(this).hasClass('stopped')) $('div.'+$(this).prop('id')).hide();
});
$('.autostart').switchButton({labels_placement:"right"});
$('.autostart').change(function() {
$.post( "/plugins/dynamix.docker.manager/include/UpdateConfig.php",{action:'autostart',container:$(this).attr('container'),response:'json'},function(data){$(this).prop('checked',data.autostart);},'json');
@@ -112,6 +116,15 @@ function loadlist(update) {
if (!update) $('input#updateAll').hide();
});
}
var watchDocker = new NchanSubscriber('/sub/dockerload', /^((?!chrome|android).)*safari/i.test(navigator.userAgent) ? {subscriber:'longpoll'} : {});
watchDocker.on('message', function(data) {
data = data.split('\n');
for (var i=0,row; row=data[i]; i++) {
var id = row.split(' ');
$('#cpu-'+id[0]).css('width',id[1]).text(id[1].replace('.','<?=$display['number'][0]?>'));
$('#mem-'+id[0]).css('width',id[2]).text(id[2].replace('.','<?=$display['number'][0]?>'));
}
});
$(function() {
$('.advancedview').switchButton({labels_placement:'left', on_label:'Advanced View', off_label:'Basic View', checked:$.cookie('docker_listview_mode')=='advanced'});
$('.advancedview').change(function() {
@@ -121,5 +134,6 @@ $(function() {
listview();
});
$.post('/plugins/dynamix.docker.manager/include/DockerUpdate.php',{},function(u){loadlist(u);});
watchDocker.start();
});
</script>

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# daemonize the 'docker_load' script
DAEMON="/usr/local/emhttp/plugins/dynamix.docker.manager/scripts/docker_load"
if [[ "$(pgrep -f $DAEMON)" == "" ]]; then
logger "Starting $(basename $DAEMON)"
$DAEMON &>/dev/null &
fi

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# stop docker_load daemon
DAEMON="docker_load"
if [[ "$(pgrep $DAEMON)" != "" ]]; then
logger "Stopping $DAEMON"
pkill $DAEMON
fi

View File

@@ -168,6 +168,7 @@ function postToXML($post, $setOwnership=false) {
$xml->Registry = xml_encode(trim($post['contRegistry']));
$xml->Network = xml_encode($post['contNetwork']);
$xml->MyIP = xml_encode($post['contMyIP']);
$xml->Shell = xml_encode($post['contShell']);
$xml->Privileged = strtolower($post['contPrivileged'])=='on' ? 'true' : 'false';
$xml->Support = xml_encode($post['contSupport']);
$xml->Project = xml_encode($post['contProject']);
@@ -242,6 +243,7 @@ function xmlToVar($xml) {
$out['Registry'] = xml_decode($xml->Registry);
$out['Network'] = xml_decode($xml->Network);
$out['MyIP'] = xml_decode($xml->MyIP ?? '');
$out['Shell'] = xml_decode($xml->Shell ?? 'sh');
$out['Privileged'] = xml_decode($xml->Privileged);
$out['Support'] = xml_decode($xml->Support);
$out['Project'] = xml_decode($xml->Project);
@@ -584,7 +586,9 @@ if (isset($_POST['contName'])) {
// force kill container if still running after 10 seconds
removeContainer($existing,1);
// remove old template
@unlink("$userTmplDir/my-$existing.xml");
if (strtolower($filename) != strtolower("$userTmplDir/my-$existing.xml")) {
@unlink("$userTmplDir/my-$existing.xml");
}
}
if ($startContainer) $cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
execCommand($cmd);
@@ -1421,6 +1425,14 @@ optgroup.title{background-color:#625D5D;color:#FFFFFF;text-align:center;margin-t
</blockquote>
</td>
</tr>
<tr <?=$showAdditionalInfo?>>
<td>Console shell command:</td>
<td><select name="contShell" class="narrow">
<?=mk_option(1,'sh','Shell')?>
<?=mk_option(1,'bash','Bash')?>
</select>
</td>
</tr>
<tr <?=$showAdditionalInfo?>>
<td>Privileged:</td>
<td><input type="checkbox" name="contPrivileged" class="switch-on-off"></td>

View File

@@ -270,6 +270,7 @@ class DockerTemplates {
$port = &$ct['Ports'][0];
$ip = ($ct['NetworkMode']=='host'||$port['NAT'] ? $host : $port['IP']);
$tmp['url'] = strpos($tmp['url'],$ip)!==false ? $tmp['url'] : $this->getControlURL($ct, $ip);
$tmp['shell'] = $tmp['shell'] ?? $this->getTemplateValue($image, 'Shell');
}
$tmp['registry'] = $tmp['registry'] ?? $this->getTemplateValue($image, 'Registry');
$tmp['Support'] = $tmp['Support'] ?? $this->getTemplateValue($image, 'Support');
@@ -291,7 +292,7 @@ class DockerTemplates {
public function getIcon($Repository) {
global $docroot, $dockerManPaths;
$imgUrl = $this->getTemplateValue($Repository, 'Icon');
preg_match_all("/(.*?):([\w]*$)/i", $Repository, $matches);
preg_match_all("/(.*?):([\S]*$)/i", $Repository, $matches);
$name = preg_replace("%\/|\\\%", '-', $matches[1][0]);
$version = $matches[2][0];
$iconRAM = sprintf('%s/%s-%s-%s.png', $dockerManPaths['images-ram'], $name, $version, 'icon');
@@ -531,7 +532,7 @@ class DockerClient {
'304' => 'Container already started',
'400' => 'Bad parameter',
'404' => 'No such container',
'409' => 'Image can not be deleted<br><i>In use by other container(s)</i>',
'409' => 'Image can not be deleted, in use by other container(s)',
'500' => 'Server error'
];

View File

@@ -39,7 +39,6 @@ $docker = ['var docker=[];'];
$null = '0.0.0.0';
$menu = [];
$n = 0;
foreach ($containers as $ct) {
$name = $ct['Name'];
$id = $ct['Id'];
@@ -49,10 +48,11 @@ foreach ($containers as $ct) {
$is_autostart = $info['autostart'] ? 'true':'false';
$updateStatus = $info['updated']=='true'||$info['updated']=='undef' ? 'true':'false';
$template = $info['template'];
$shell = $info['shell'];
$webGui = html_entity_decode($info['url']);
$support = html_entity_decode($info['Support']);
$project = html_entity_decode($info['Project']);
$menu[] = sprintf("addDockerContainerContext('%s','%s','%s',%s,%s,%s,%s,'%s','%s','%s','%s');", addslashes($name), addslashes($ct['ImageId']), addslashes($template), $running, $paused, $updateStatus, $is_autostart, addslashes($webGui), $id, addslashes($support), addslashes($project));
$menu[] = sprintf("addDockerContainerContext('%s','%s','%s',%s,%s,%s,%s,'%s','%s','%s','%s','%s');", addslashes($name), addslashes($ct['ImageId']), addslashes($template), $running, $paused, $updateStatus, $is_autostart, addslashes($webGui), $shell, $id, addslashes($support), addslashes($project));
$docker[] = "docker.push({name:'$name',id:'$id',state:$running,pause:$paused,update:'$updateStatus'});";
$shape = $running ? ($paused ? 'pause' : 'play') : 'square';
$status = $running ? ($paused ? 'paused' : 'started') : 'stopped';
@@ -71,7 +71,7 @@ foreach ($containers as $ct) {
echo "<tr class='sortable'><td style='width:48px;padding:4px'>";
echo "<div id='$id' style='display:block; cursor:pointer'><div style='position:relative;width:48px;height:48px;margin:0px auto'>";
echo "<img src='".htmlspecialchars($icon)."' class='$status' style='position:absolute;top:0;bottom:0;left:0;right:0;width:48px;height:48px'>";
echo "<i class='fa iconstatus fa-$shape $status' title='$status'></i></div></div>";
echo "<i id='load-$id' class='fa iconstatus fa-$shape $status' title='$status'></i></div></div>";
echo "</td><td class='ct-name'>";
if ($template) {
echo "<a class='exec' onclick=\"editContainer('".addslashes(htmlspecialchars($name))."','".addslashes(htmlspecialchars($template))."')\">".htmlspecialchars($name)."</a>";
@@ -79,7 +79,7 @@ foreach ($containers as $ct) {
echo htmlspecialchars($name);
}
echo "<div class='advanced' style='width:160px'>Container ID: $id</div>";
if ($ct['BaseImage']) echo "<div class='advanced' style='width:160px;'><i class='fa fa-cubes' style='margin-right:5px'></i>".htmlspecialchars(${ct['BaseImage']})."</div>";
if ($ct['BaseImage']) echo "<div class='advanced' style='width:160px;'><i class='fa fa-cubes' style='margin-right:5px'></i>".htmlspecialchars(${ct['BaseImage']})."</div>";
echo "<div class='advanced' style='width:160px'>By:";
$registry = $info['registry'];
if ($registry) {
@@ -100,6 +100,8 @@ foreach ($containers as $ct) {
echo "</td><td>{$ct['NetworkMode']}</td>";
echo "<td style='white-space:nowrap'><span class='docker_readmore'>".implode('<br>',$ports)."</span></td>";
echo "<td style='word-break:break-all'><span class='docker_readmore'>".implode('<br>',$paths)."</span></td>";
echo "<td class='advanced'><div class='usage-disk sys load-$id'><span id='cpu-$id' style='width:0'></span></div></td>";
echo "<td class='advanced'><div class='usage-disk sys load-$id'><span id='mem-$id' style='width:0'></span></div></td>";
echo "<td><input type='checkbox' class='autostart' container='".htmlspecialchars($name)."'".($info['autostart'] ? ' checked':'')."></td>";
echo "<td><a class='log' onclick=\"containerLogs('".addslashes(htmlspecialchars($name))."','$id',false,false)\"><img class='basic' src='/plugins/dynamix/icons/log.png'><div class='advanced'>";
echo htmlspecialchars(str_replace('Up','Uptime',$ct['Status']))."</div><div class='advanced' style='margin-top:4px'>Created ".htmlspecialchars($ct['Created'])."</div></a></td></tr>";
@@ -115,7 +117,7 @@ foreach ($images as $image) {
echo "</div></div></td>";
echo "<td><i>(orphan image)</i><div style='width:160px;'>Image ID: $id</div>";
echo "<div style='width:160px'>".implode('<br>',array_map('htmlspecialchars',$image['Tags']))."</div></td>";
echo "<td colspan='5'></td>";
echo "<td colspan='5'></td><td class='advanced' colspan='2'></td>";
echo "<td><div class='advanced' style='width:124px'>Created ".htmlspecialchars($image['Created'])."</div></td></tr>";
}
echo "\0".implode($menu).implode($docker);

View File

@@ -92,10 +92,11 @@ switch ($action) {
}
break;
case 'terminal':
$shell = $_REQUEST['shell'] ?: 'sh';
$pid = exec("pgrep -a ttyd|awk '/\\/$name\\.sock/{print \$1}'");
if ($pid) exec("kill $pid");
@unlink("/var/tmp/$name.sock");
exec("exec ttyd -o -d0 -i '/var/tmp/$name.sock' docker exec -it '$name' sh &>/dev/null &");
exec("exec ttyd -o -d0 -i '/var/tmp/$name.sock' docker exec -it '$name' $shell &>/dev/null &");
break;
default:
$arrResponse = ['error' => "Unknown action '$action'"];

View File

@@ -1,10 +1,10 @@
var eventURL = '/plugins/dynamix.docker.manager/include/Events.php';
function addDockerContainerContext(container, image, template, started, paused, update, autostart, webui, id, Support, Project) {
function addDockerContainerContext(container, image, template, started, paused, update, autostart, webui, shell, id, Support, Project) {
var opts = [{header:container, image:'/plugins/dynamix.docker.manager/images/dynamix.docker.manager.png'}];
if (started && !paused) {
if (webui !== '' && webui != '#') opts.push({text:'WebUI', icon:'fa-globe', href:webui, target:'_blank'});
opts.push({text:'Console', icon:'fa-terminal', action:function(e){e.preventDefault(); dockerTerminal(container);}});
opts.push({text:'Console', icon:'fa-terminal', action:function(e){e.preventDefault(); dockerTerminal(container,shell);}});
opts.push({divider:true});
}
if (!update) {
@@ -45,12 +45,12 @@ function addDockerImageContext(image, imageTag) {
opts.push({text:'Remove', icon:'fa-trash', action:function(e){e.preventDefault(); rmImage(image, imageTag);}});
context.attach('#'+image, opts);
}
function dockerTerminal(container) {
function dockerTerminal(container,shell) {
var height = 600;
var width = 900;
var top = (screen.height-height)/2;
var left = (screen.width-width)/2;
$.get(eventURL,{action:'terminal',name:container});
$.get(eventURL,{action:'terminal',name:container,shell:shell});
setTimeout(function(){window.open('/dockerterminal/'+container+'/', container, 'resizeable=yes,scrollbars=yes,height='+height+',width='+width+',top='+top+',left='+left).focus();},180);
}
function execUpContainer(container) {

View File

@@ -0,0 +1,4 @@
#!/bin/bash
while :; do
curl -sfd "$(docker stats --no-stream --format='{{.Container}} {{.CPUPerc}} {{.MemPerc}}')" --unix-socket /var/run/nginx.socket http://localhost/pub/dockerload?buffer_length=0 >/dev/null 2>&1
done &

View File

@@ -2,6 +2,6 @@
# daemonize the 'diskload' script
DAEMON="/usr/local/emhttp/webGui/scripts/diskload"
if [[ "$(pgrep -f $DAEMON)" == "" ]]; then
logger "Starting $DAEMON"
logger "Starting $(basename $DAEMON)"
$DAEMON &>/dev/null &
fi

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2017, Lime Technology
* Copyright 2012-2017, Bergware International.
/* Copyright 2005-2018, Lime Technology
* Copyright 2012-2018, 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,
@@ -54,11 +54,11 @@ foreach ($file as $row) {
foreach ($rows as $row) $show |= strpos($disks[$tag.str_replace($tag,'',$row)]['fsType'],'luks:')!==false;
if ($show) foreach ($rows as $row) {
switch ($disks[$tag.str_replace($tag,'',$row)]['luksState']) {
case 0: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-unlock grey-text'></i><span>Not encrypted</span></a>"; break;
case 1: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-unlock-alt green-text'></i><span>Encrypted and unlocked</span></a>"; break;
case 2: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: missing encryption key</span></a>"; break;
case 3: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: wrong encryption key</span></a>"; break;
default: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: unknown error</span></a>"; break;}
case 0: $luks .= "<a class='info' onclick='return false'><i class='lock fa fa-unlock grey-text'></i><span>Not encrypted</span></a>"; break;
case 1: $luks .= "<a class='info' onclick='return false'><i class='lock fa fa-unlock-alt green-text'></i><span>Encrypted and unlocked</span></a>"; break;
case 2: $luks .= "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: missing encryption key</span></a>"; break;
case 3: $luks .= "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: wrong encryption key</span></a>"; break;
default: $luks .= "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: unknown error</span></a>"; break;}
}
$list[] = [
'type' => $attr[0],

View File

@@ -42,10 +42,11 @@ if (pgrep('dockerd')!==false && ($display=='icons' || $display=='docker')) {
$is_autostart = $info['autostart'] ? 'true':'false';
$updateStatus = $info['updated']=='true'||$info['updated']=='undef' ? 'true':'false';
$template = $info['template'];
$shell = $info['shell'];
$webGui = html_entity_decode($info['url']);
$support = html_entity_decode($info['Support']);
$project = html_entity_decode($info['Project']);
$menu[] = sprintf("addDockerContainerContext('%s','%s','%s',%s,%s,%s,%s,'%s','%s','%s','%s');", addslashes($name), addslashes($ct['ImageId']), addslashes($template), $running, $paused, $updateStatus, $is_autostart, addslashes($webGui), $id, addslashes($support), addslashes($project));
$menu[] = sprintf("addDockerContainerContext('%s','%s','%s',%s,%s,%s,%s,'%s','%s','%s','%s','%s');", addslashes($name), addslashes($ct['ImageId']), addslashes($template), $running, $paused, $updateStatus, $is_autostart, addslashes($webGui), $shell, $id, addslashes($support), addslashes($project));
$shape = $running ? ($paused ? 'pause' : 'play') : 'square';
$status = $running ? ($paused ? 'paused' : 'started') : 'stopped';
$icon = $info['icon'] ?: '/plugins/dynamix.docker.manager/images/question.png';

View File

@@ -139,10 +139,9 @@ function chkDelete(form, button) {
}
function openBox(cmd,title,height,width,load,func,id) {
// open shadowbox window (run in foreground)
if (id === undefined) id = '';
var run = cmd.split('?')[0].substr(-4)=='.php' ? cmd : '/logging.htm?cmd='+cmd+'&csrf_token=<?=$var['csrf_token']?>';
var options = load ? (func ? {modal:true,onClose:function(){setTimeout(func+'('+'"'+id+'")',0);}} : {modal:true,onClose:function(){location=location;}}) : {modal:true};
Shadowbox.open({content:run, player:'iframe', title:title, height:height, width:width, options:options});
var options = load ? (func ? {modal:true,onClose:function(){setTimeout(func+'('+'"'+(id||'')+'")',0);}} : {modal:true,onClose:function(){location=location;}}) : {modal:true};
Shadowbox.open({content:run, player:'iframe', title:title, height:Math.min(height,screen.availHeight), width:Math.min(width,screen.availWidth), options:options});
}
function openWindow(cmd,title,height,width) {
// open regular window (run in background)
@@ -160,8 +159,10 @@ function openWindow(cmd,title,height,width) {
form_html += '</form>';
var form = $(form_html);
$('body').append(form);
var top = (screen.height-height)/2;
var left = (screen.width-width)/2;
var top = (screen.availHeight-height)/2;
if (top < 0) {top = 0; height = screen.availHeight;}
var left = (screen.availWidth-width)/2;
if (left < 0) {left = 0; width = screen.availWidth;}
var options = 'resizeable=yes,scrollbars=yes,height='+height+',width='+width+',top='+top+',left='+left;
window.open('', window_name, options);
form.submit();

View File

@@ -56,11 +56,11 @@ form+p{display:none}
#nav-block{-ms-overflow-style:none;overflow:-moz-scrollbars-none}
#nav-block.mozilla{margin-left:-17px;overflow-y:scroll}
#nav-block>div{direction:ltr}
#nav-item{width:24px;text-align:left;padding:14px 24px 14px 16px;border-bottom:#42453E 1px solid;font-size:18px;overflow:hidden}
#nav-item{width:40px;text-align:left;padding:14px 24px 14px 0;border-bottom:#42453E 1px solid;font-size:18px;overflow:hidden;transition:.2s background-color ease}
#nav-item:hover{width:150px;color:#5D6833;background:#ABC056;border-bottom-color:#5D6833;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}
#nav-item:hover a{color:#5D6833;background:#ABC056}
#nav-item img{display:none}
#nav-item a{color:#A6A7A7;text-decoration:none}
#nav-item a{color:#A6A7A7;text-decoration:none;padding:19px 80px 12px 16px}
#nav-item a:before{font-family:docker-icon,fontawesome;font-size:26px;margin-right:25px}
#nav-item.active,#nav-item.active a{color:#5D6833;background:#ABC056}
#nav-item.HelpButton.active:hover{background:#ABC056;font-size:18px}

View File

@@ -56,11 +56,11 @@ form+p{display:none}
#nav-block{-ms-overflow-style:none;overflow:-moz-scrollbars-none}
#nav-block.mozilla{margin-left:-17px;overflow-y:scroll}
#nav-block>div{direction:ltr}
#nav-item{width:24px;text-align:left;padding:14px 24px 14px 16px;border-bottom:#42453E 1px solid;font-size:18px;overflow:hidden}
#nav-item{width:40px;text-align:left;padding:14px 24px 14px 0;border-bottom:#42453E 1px solid;font-size:18px;overflow:hidden;transition:.2s background-color ease}
#nav-item:hover{width:150px;color:#5D6833;background:#ABC056;border-bottom-color:#5D6833;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}
#nav-item:hover a{color:#5D6833;background:#ABC056}
#nav-item img{display:none}
#nav-item a{color:#A6A7A7;text-decoration:none}
#nav-item a{color:#A6A7A7;text-decoration:none;padding:19px 80px 12px 16px}
#nav-item a:before{font-family:docker-icon,fontawesome;font-size:26px;margin-right:25px}
#nav-item.active,#nav-item.active a{color:#5D6833;background:#ABC056}
#nav-item.HelpButton.active:hover{background:#ABC056;font-size:18px}