new features log and bash
This commit is contained in:
@@ -13,11 +13,11 @@ var focused = null;
|
||||
|
||||
function DockerContainers() {
|
||||
var Status = Object.freeze({
|
||||
Error: {color: "red", action1: "start", action2: "remove"},
|
||||
Terminated: {color: "yellow", action1: "start", action2: "remove"},
|
||||
Restarting: {color: "lightblue", action1: "start", action2: "remove"},
|
||||
Paused: {color: "lightgrey", action1: "unpause", action2: null},
|
||||
Running: {color: "lightgreen", action1: "pause", action2: "stop"}
|
||||
Error: {color: "red", action1: "start", action2: "remove", bash: false},
|
||||
Terminated: {color: "yellow", action1: "start", action2: "remove", bash: false},
|
||||
Restarting: {color: "lightblue", action1: "start", action2: "remove", bash: false},
|
||||
Paused: {color: "lightgrey", action1: "unpause", action2: null, bash: false},
|
||||
Running: {color: "lightgreen", action1: "pause", action2: "stop", bash: true}
|
||||
});
|
||||
var containers = [];
|
||||
var nodes = [];
|
||||
@@ -40,7 +40,7 @@ function DockerContainers() {
|
||||
if (n.status.action1) {
|
||||
$("#popup").append('<button id="popup1">'+n.status.action1+'</button>');
|
||||
$("#popup1").click(function() {
|
||||
socket.emit(n.status.action1, name);
|
||||
emit(n.status.action1, name);
|
||||
});
|
||||
}
|
||||
$("#popup").append('<button id="popup2">'+(focused?"overview":"focus")+'</button>');
|
||||
@@ -50,11 +50,27 @@ function DockerContainers() {
|
||||
if (n.status.action2) {
|
||||
$("#popup").append('<button id="popup3">'+n.status.action2+'</button>');
|
||||
$("#popup3").click(function() {
|
||||
socket.emit(n.status.action2, name);
|
||||
emit(n.status.action2, name);
|
||||
});
|
||||
}
|
||||
$("#popup").append('<br/>');
|
||||
$("#popup").append('<button id="popup4">download</button>');
|
||||
$("#popup").append('<button id="popup4">logs</button>');
|
||||
$("#popup4").click(function() {
|
||||
emit("logs", name);
|
||||
});
|
||||
if (n.status.bash) {
|
||||
$("#popup").append('<button id="popup5">bash</button>');
|
||||
$("#popup5").click(function() {
|
||||
emit("bash-start", name);
|
||||
$("#console").show();
|
||||
$("#main").hide();
|
||||
$("#bash").submit(function() {
|
||||
emit("bash-input", {name: name, text: $("#command").val()+"\n"});
|
||||
$("#command").val("");
|
||||
})
|
||||
});
|
||||
}
|
||||
$("#popup").append('<button id="popup6">download</button>');
|
||||
$("#popup").css("position", "fixed");
|
||||
$("#popup").css("top", e.pageY-$("#popup").height()/4);
|
||||
$("#popup").css("left", e.pageX-$("#popup").width()/2);
|
||||
@@ -66,49 +82,6 @@ function DockerContainers() {
|
||||
$("#popup").show();
|
||||
})
|
||||
}
|
||||
this.details = function(name) {
|
||||
var res = `
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-1">Overview</a></li>
|
||||
<li><a href="#tabs-2">Logs</a></li>
|
||||
<li><a href="#tabs-3">Dump</a></li>
|
||||
</ul>
|
||||
<div id="tabs-1">
|
||||
<table class="details docker">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Ports</th>
|
||||
<th>Volumes</th>
|
||||
<th>Links</th>
|
||||
<th>Environments</th>
|
||||
<th>Image</th>
|
||||
<th>Command</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
var n = nodes[name];
|
||||
res += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tabs-2">
|
||||
</div>
|
||||
<div id="tabs-3">
|
||||
<pre>`;
|
||||
res += JSON.stringify(containers[nodes[name].id], null, 4);
|
||||
res += `
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {$("#tabs").tabs();});
|
||||
</script>
|
||||
`;
|
||||
return res;
|
||||
}
|
||||
function getIps(n, ips) {
|
||||
n.ports.forEach(function(p) {
|
||||
if (!ips[p.ip]) ips[p.ip] = [];
|
||||
@@ -185,7 +158,7 @@ function DockerContainers() {
|
||||
n = n || nodes;
|
||||
for (name in n) getIps(n[name], ips);
|
||||
res += graphIpClusters(ips);
|
||||
for (name in n) res += graphNode(n[name]);
|
||||
for (name in n) res += graphNode(n[name]);
|
||||
res += "{rank=same;\n";
|
||||
for (name in n) res += graphVolumesInside(n[name]);
|
||||
res+="}\n";
|
||||
@@ -243,7 +216,6 @@ function DockerContainers() {
|
||||
else if (c.State.Restarting) nodes[name].status = Status.Restarting;
|
||||
else if (c.State.ExitCode == 0) nodes[name].status = Status.Terminated;
|
||||
else nodes[name].status = Status.Error;
|
||||
console.log("STATUS", name, c.State, nodes[name].status);
|
||||
nodes[name].volumes = [];
|
||||
var volumes = c.Volumes || c.Config.Volumes;
|
||||
nodes[name].volumes = [];
|
||||
@@ -316,6 +288,14 @@ function DockerContainers() {
|
||||
|
||||
var dc = new DockerContainers();
|
||||
|
||||
function htmlenc(html) {
|
||||
return $('<div/>').text(html).html();
|
||||
}
|
||||
|
||||
function htmldec(data) {
|
||||
return $('<div/>').html(data).text();
|
||||
}
|
||||
|
||||
/// Show error messsage
|
||||
/** Fades in an error message and logs to console.
|
||||
@param data (optional) The error can be a string or any structure.
|
||||
@@ -389,6 +369,7 @@ function status(text, msg) {
|
||||
$("#popup").hide();
|
||||
if (msg) success(msg);
|
||||
else setTimeout("$('#status').fadeOut('slow')", 5000);
|
||||
zoom(0);
|
||||
$("#main").show();
|
||||
$("form input:first-child").focus();
|
||||
dc.contextmenu("#main");
|
||||
@@ -488,7 +469,6 @@ function showviz(vizpath, more) {
|
||||
}
|
||||
res = "digraph {\n"+" rankdir="+rankdir+";\n"+viz+"\n}";
|
||||
try {
|
||||
zoomlevel = 0;
|
||||
status(more?Viz(res)+more:Viz(res));
|
||||
} catch(e) {
|
||||
(res = res.split("\n")).forEach(function(v, i, a) {
|
||||
@@ -504,43 +484,6 @@ function details(name) {
|
||||
showviz(dc.subgraph(focused));
|
||||
}
|
||||
|
||||
function action(container, action) {
|
||||
$("#imagetools").hide();
|
||||
$.ajax({url: "action.php?container="+container+"&action="+action, success: function(res) {
|
||||
success(res);
|
||||
manage();
|
||||
}}).fail(function() {
|
||||
error("offline");
|
||||
});
|
||||
}
|
||||
|
||||
/** Manage Docker Services */
|
||||
function manage() {
|
||||
$("#imagetools").hide();
|
||||
$.ajax({url: "manage.php", success: function(res) {
|
||||
status(res);
|
||||
}}).fail(function() {
|
||||
error("offline");
|
||||
});
|
||||
}
|
||||
|
||||
/** Show an Overview of all Docker Images */
|
||||
function imgs() {
|
||||
$("#imagetools").hide();
|
||||
$.ajax({url: "images.php", success: function(res) {
|
||||
try {
|
||||
showviz(res);
|
||||
} catch(e) {
|
||||
(res = res.split("\n")).forEach(function(v, i, a) {
|
||||
a[i] = ("000"+(i+1)).slice(-3)+": "+v;
|
||||
});
|
||||
status("<h2>Exception Caught:</h2><p>"+e+"<p><pre>"+res.join("\n")+"</pre>");
|
||||
}
|
||||
}}).fail(function() {
|
||||
error("offline");
|
||||
});
|
||||
}
|
||||
|
||||
function containers(c) {
|
||||
console.log("->rcv containers");
|
||||
dc.setContainers(c);
|
||||
@@ -550,6 +493,109 @@ function containers(c) {
|
||||
overview();
|
||||
}
|
||||
|
||||
function logs(data) {
|
||||
console.log("->rcv logs("+data.name+")");
|
||||
$("#main").hide();
|
||||
$("#console").hide();
|
||||
$("#logs").show();
|
||||
if (data.type=='done') {
|
||||
$("#logs").append('<span class="'+data.type+'">\nDONE</span>');
|
||||
} else {
|
||||
$("#logs").append('<span class="'+data.type+'">'+htmlenc(data.text)+'</span>');
|
||||
}
|
||||
}
|
||||
|
||||
function strInsert(str, pos, txt) {
|
||||
return str.slice(0, pos)+txt+str.slice(pos);
|
||||
}
|
||||
|
||||
function ansifilter(data) {
|
||||
console.log("ansifilter");
|
||||
var res = data;
|
||||
var pos = -1;
|
||||
var spans = 0;
|
||||
while ((pos=res.indexOf("\x1B[")) >= 0) {
|
||||
var end = res.indexOf("m", pos+2);
|
||||
if (end>0) {
|
||||
var control= res.slice(pos+2, end);
|
||||
res = res.slice(0, pos)+res.slice(end+1);
|
||||
control.split(';').forEach(function(c) {
|
||||
switch (parseInt(c)) {
|
||||
// set
|
||||
case 1: res = strInsert(res, pos, '<span class="bold">'); ++spans; break;
|
||||
case 2: res = strInsert(res, pos, '<span class="dim">'); ++spans; break;
|
||||
case 4: res = strInsert(res, pos, '<span class="underlined">'); ++spans; break;
|
||||
case 5: res = strInsert(res, pos, '<span class="blink">'); ++spans; break;
|
||||
case 7: res = strInsert(res, pos, '<span class="reverse">'); ++spans; break;
|
||||
case 8: res = strInsert(res, pos, '<span class="hidden">'); ++spans; break;
|
||||
// reset
|
||||
case 0: for (;spans;--spans) res = strInsert(res, pos, "</span>"); break;
|
||||
case 21: if (spans) --spans; res = strInsert(res, pos, "</span>"); break;
|
||||
case 22: if (spans) --spans; res = strInsert(res, pos, "</span>"); break;
|
||||
case 23: if (spans) --spans; res = strInsert(res, pos, "</span>"); break;
|
||||
case 25: if (spans) --spans; res = strInsert(res, pos, "</span>"); break;
|
||||
case 27: if (spans) --spans; res = strInsert(res, pos, "</span>"); break;
|
||||
case 28: if (spans) --spans; res = strInsert(res, pos, "</span>"); break;
|
||||
// fg colors
|
||||
case 39: res = strInsert(res, pos, '<span class="fgdefault">'); ++spans; break;
|
||||
case 30: res = strInsert(res, pos, '<span class="fgblack">'); ++spans; break;
|
||||
case 31: res = strInsert(res, pos, '<span class="fgred">'); ++spans; break;
|
||||
case 32: res = strInsert(res, pos, '<span class="fggreen">'); ++spans; break;
|
||||
case 33: res = strInsert(res, pos, '<span class="fgyellow">'); ++spans; break;
|
||||
case 34: res = strInsert(res, pos, '<span class="fgblue">'); ++spans; break;
|
||||
case 35: res = strInsert(res, pos, '<span class="fgmagenta">'); ++spans; break;
|
||||
case 36: res = strInsert(res, pos, '<span class="fgcyan">'); ++spans; break;
|
||||
case 37: res = strInsert(res, pos, '<span class="fglightgrey">'); ++spans; break;
|
||||
case 90: res = strInsert(res, pos, '<span class="fgdarkgrey">'); ++spans; break;
|
||||
case 91: res = strInsert(res, pos, '<span class="fglightred">'); ++spans; break;
|
||||
case 92: res = strInsert(res, pos, '<span class="fglightgreen">'); ++spans; break;
|
||||
case 93: res = strInsert(res, pos, '<span class="fglightyellow">'); ++spans; break;
|
||||
case 94: res = strInsert(res, pos, '<span class="fglightblue">'); ++spans; break;
|
||||
case 95: res = strInsert(res, pos, '<span class="fglightmagenta">'); ++spans; break;
|
||||
case 96: res = strInsert(res, pos, '<span class="fglightcyan">'); ++spans; break;
|
||||
case 97: res = strInsert(res, pos, '<span class="fgwhite">'); ++spans; break;
|
||||
// bg colors
|
||||
case 49: res = strInsert(res, pos, '<span class="bgdefault">'); ++spans; break;
|
||||
case 40: res = strInsert(res, pos, '<span class="bgblack">'); ++spans; break;
|
||||
case 41: res = strInsert(res, pos, '<span class="bgred">'); ++spans; break;
|
||||
case 42: res = strInsert(res, pos, '<span class="bggreen">'); ++spans; break;
|
||||
case 43: res = strInsert(res, pos, '<span class="bgyellow">'); ++spans; break;
|
||||
case 44: res = strInsert(res, pos, '<span class="bgblue">'); ++spans; break;
|
||||
case 45: res = strInsert(res, pos, '<span class="bgmagenta">'); ++spans; break;
|
||||
case 46: res = strInsert(res, pos, '<span class="bgcyan">'); ++spans; break;
|
||||
case 47: res = strInsert(res, pos, '<span class="bglightgrey">'); ++spans; break;
|
||||
case 100: res = strInsert(res, pos, '<span class="bgdarkgrey">'); ++spans; break;
|
||||
case 101: res = strInsert(res, pos, '<span class="bglightred">'); ++spans; break;
|
||||
case 102: res = strInsert(res, pos, '<span class="bglightgreen">'); ++spans; break;
|
||||
case 103: res = strInsert(res, pos, '<span class="bglightyellow">'); ++spans; break;
|
||||
case 104: res = strInsert(res, pos, '<span class="bglightblue">'); ++spans; break;
|
||||
case 105: res = strInsert(res, pos, '<span class="bglightmagenta">'); ++spans; break;
|
||||
case 106: res = strInsert(res, pos, '<span class="bglightcyan">'); ++spans; break;
|
||||
case 107: res = strInsert(res, pos, '<span class="bgwhite">'); ++spans; break;
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (;spans;--spans) res += "</span>";
|
||||
console.log(res);
|
||||
return res.replace(/\r\r\n/g, '\n');
|
||||
}
|
||||
|
||||
function bash_data(data) {
|
||||
console.log("->rcv bash-data("+data.name+")", data);
|
||||
$("#main").hide();
|
||||
$("#logs").hide();
|
||||
$("#console").show();
|
||||
if (data.type=='done') {
|
||||
$("#screen").append('<span class="'+data.type+'">\nDONE</span>');
|
||||
} else {
|
||||
$("#screen").append('<span class="'+data.type+'">'+ansifilter(htmlenc(data.text))+'</span>');
|
||||
}
|
||||
}
|
||||
|
||||
function overview() {
|
||||
focused = null;
|
||||
showviz(dc.graph());
|
||||
@@ -577,7 +623,9 @@ function init() {
|
||||
.on("error", disconnected);
|
||||
socket
|
||||
.on("fail", error)
|
||||
.on("containers", containers);
|
||||
.on("containers", containers)
|
||||
.on("logs", logs)
|
||||
.on("bash-data", bash_data);
|
||||
start();
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,10 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
@media (min-resolution: 120dpi) {
|
||||
html {
|
||||
font-size: 120%;
|
||||
@@ -228,18 +232,22 @@ table.docker li+li {
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
#main {
|
||||
#main, #logs, #console {
|
||||
position: fixed;
|
||||
top: 2em;
|
||||
top: 1.5em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 2em;
|
||||
padding: 0em 1em 0em 1em;
|
||||
bottom: 1.5em;
|
||||
padding: 1em 1em 1em 1em;
|
||||
clear: both;
|
||||
overflow: auto;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#main {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#popup {
|
||||
position: fixed;
|
||||
background-color: lightblue;
|
||||
@@ -308,3 +316,62 @@ table.docker li+li {
|
||||
#preview img {
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
#logs {
|
||||
background-color: lightgray;
|
||||
}
|
||||
#logs .stdout {
|
||||
color: black;
|
||||
}
|
||||
.stderr {
|
||||
color: red;
|
||||
}
|
||||
.done {
|
||||
color: green;
|
||||
}
|
||||
|
||||
#console {
|
||||
background-color: black;
|
||||
color: white
|
||||
}
|
||||
.bold {font-weight: bold}
|
||||
.dim {color: grey}
|
||||
.underline {text-decoration: underline}
|
||||
.blink {animation: blinker 1s linear infinite}
|
||||
@keyframes blinker {50% { opacity: 0.0;}}
|
||||
.reverse {color: black; background-color: white}
|
||||
.hidden {color: black}
|
||||
.fgdefault {color: white}
|
||||
.fgblack {color: black}
|
||||
.fgred {color: red}
|
||||
.fggreen {color: green}
|
||||
.fgyellow {color: yellow}
|
||||
.fgblue {color: blue}
|
||||
.fgmagenta {color: magenta}
|
||||
.fgcyan {color: cyan}
|
||||
.fglightgrey {color: lightgrey}
|
||||
.fgdarkgrey {color: darkgrey}
|
||||
.fglightred {color: lightred}
|
||||
.fglightgreen {color: lightgreen}
|
||||
.fglightyellow {color: lightyellow}
|
||||
.fglightblue {color: lightblue}
|
||||
.fglightmagenta {color: lightmagenta}
|
||||
.fglightcyan {color: lightcyan}
|
||||
.fgwhite {color: white}
|
||||
.bgdefault {background-color: black}
|
||||
.bgblack {background-color: black}
|
||||
.bgred {background-color: red}
|
||||
.bggreen {background-color: green}
|
||||
.bgyellow {background-color: yellow}
|
||||
.bgblue {background-color: blue}
|
||||
.bgmagenta {background-color: magenta}
|
||||
.bgcyan {background-color: cyan}
|
||||
.bglightgrey {background-color: lightgrey}
|
||||
.bgdarkgrey {background-color: darkgrey}
|
||||
.bglightred {background-color: lightred}
|
||||
.bglightgreen {background-color: lightgreen}
|
||||
.bglightyellow {background-color: lightyellow}
|
||||
.bglightblue {background-color: lightblue}
|
||||
.bglightmagenta {background-color: lightmagenta}
|
||||
.bglightcyan {background-color: lightcyan}
|
||||
.bgwhite {background-color: white}
|
||||
|
Reference in New Issue
Block a user