/*! @file @id $Id$ This is the main application as it is fully run in the user's browser. */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 var socket = null; var docker = null; function htmlenc(html) { return $('
').text(html).html(); } function htmldec(data) { return $('').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. Strings are shown to the user, structures are logged only. @param stay (optional) If not given as @c true, reloads page after 5s. */ function error(data) { $("#status").fadeOut("slow", function() { $("#status").addClass("error") $("#status").removeClass("notice") $("#status").removeClass("success") if (data) { if (typeof data == 'string') { $("#status").html(data); console.log("error: "+data); } else { $("#status").html('unknown error: '+JSON.stringify(data)); console.log("error: ", data); console.log((new Error('stacktrace'))); } } else { $("#status").html('error'); console.log("error"); } $("#status").fadeIn("slow"); }); } /// Show notice messsage /** Fades in an notice message and logs to console. @param text (optional) The data is a string. */ function notice(text) { $("#status").fadeOut("slow", function() { $("#status").addClass("notice") $("#status").removeClass("error") $("#status").removeClass("success") if (text) { $("#status").html(text); console.log("notice: "+text); } else { $("#status").html(''); console.log("notice"); } $("#status").fadeIn("slow"); }); } /// Show notice messsage /** Fades in an success message and logs to console. @param text (optional) The data is a string. */ function success(text) { $("#status").fadeOut("slow", function() { $("#status").addClass("success") $("#status").removeClass("error") $("#status").removeClass("notice") if (text) { $("#status").html(text); console.log("success: "+text); } else { $("#status").html(''); console.log("success"); } $("#status").fadeIn("slow"); }); } /// Show status message in the main screen area /** @param text Text is a message or some complex HTML from the server. @param msg The success message text */ function status(text, msg) { $("#main").hide(); $("#main").html(text); if (msg) success(msg); else setTimeout("$('#status').fadeOut('slow')", 5000); zoom(0); $("#main").show(); $("form input:first-child").focus(); } function emit(signal, data) { console.log("<-snd "+signal, data); socket.emit(signal, data); } function connect() { $("#server").html($("#usernamefield").val()+'@'+window.location.hostname) console.log("server connect"); $("#connectionstatus #bad").hide(); $("#connectionstatus #authentication").show(); $("#connectionstatus #good").hide(); success("login to server"); socket.emit('authentication', { username: $("#usernamefield").val(), password: $("#passwordfield").val() }); } function authenticated() { $("#server").html($("#usernamefield").val()+'@'+window.location.hostname) console.log("server authenticated"); $("#connectionstatus #bad").hide(); $("#connectionstatus #authentication").hide(); $("#connectionstatus #good").show(); success("server connected"); start(); } function unauthorized() { $("#server").html($("#usernamefield").val()+'@'+window.location.hostname) console.log("authentication failed"); $("#connectionstatus #good").hide(); $("#connectionstatus #authentication").hide(); $("#connectionstatus #bad").show(); error("authentication failed", true); } function disconnected() { $("#server").html($("#usernamefield").val()+'@'+window.location.hostname) console.log("server disconnected"); $("#connectionstatus #good").hide(); $("#connectionstatus #authentication").hide(); $("#connectionstatus #bad").show(); error("server disconnected", true); } /// Toggle Menu Display function togglemenu() { $("#menu").toggle(); } /// Upload a configuration and send it to server function upload(evt) { if (!window.FileReader) return error("your browser does not support file upload", true); for (var i=0, f; f=evt.target.files[i]; ++i) { var file = f; var reader = new FileReader(); reader.onload = function(evt) { if (evt.target.error) return error("error reading file", true); if (evt.target.readyState==0) return notice("waiting for data …"); if (evt.target.readyState==1) return notice("loading data …"); tobecreated = JSON.parse(evt.target.result); showCreate(); } reader.readAsText(file); } } var tobecreated = {}; function previewCreate() { var name = $('#name').val(); var nodes = Object.create(tobecreated); if (name != '') { nodes[name] = { status: docker.containers.Status.Preview, id: null, name: name, image: { name: $('#image').val(), id: null }, ports: $('#createports option').map(function() {return $(this).data();}).get(), env: $('#createvars option').map(function() {return $(this).val();}).get(), volumes: $('#createvolumes option').map(function() {return $(this).data();}).get(), volumesfrom: $('#createvolumefroms option').map(function() {return $(this).val();}).get(), links: $('#createlinks option').map(function() {return $(this).data();}).get(), entrypoint: $('#createentrypoints option').map(function() {return $(this).val();}).get(), cmd: $('#createcommands option').map(function() {return $(this).val();}).get(), }; $('#doappend').unbind().click(function() { tobecreated[name] = Object.create(nodes[name]); tobecreated[name].status = docker.containers.Status.Prepared; $('#createpreview').append(''); $('#create form input[type=text]').val(''); $('#create form select.collect option').remove(); previewCreate(); }); $('#doremove').unbind().click(function() { $(this).siblings('#createpreview').children('option:selected').each(function(a,b,c) { delete tobecreated[b.innerHTML]; }).remove(); previewCreate(); }); $('#dosend').unbind().click(function() { if (Object.keys(tobecreated).length>0) { emit("docker.container.create", docker.containers.configuration(tobecreated)); tobecreated = {}; showImage(); } }); } if ($('#image').val()!='') { var img = docker.images.get($('#image').val()); if (img) { $('#portintdata').empty().append(img.ports.map(function(i) { var option = document.createElement('option'); option.value = i.replace(/\/.*/g, ''); return option; })); $('#varnamedata').empty().append(img.env.map(function(i) { var option = document.createElement('option'); option.value = i.replace(/=.*/g, ''); return option; })); $('#varvaluedata').empty().append(img.env.map(function(i) { var option = document.createElement('option'); option.value = i.replace(/^[^=]*=/g, ''); return option; })); $('#volumeextdata').empty(); $('#volumeintdata').empty(); for (i in img.volumes) { var option = document.createElement('option'); option.value = i; $('#volumeextdata').append(option); $('#volumeintdata').append(option); } $('#volumesfromdata').empty().append(docker.containers.names(tobecreated).map(function(i) { var option = document.createElement('option'); option.value = i; return option; })); $('#linkcontainerdata').empty().append(docker.containers.names(tobecreated).map(function(i) { var option = document.createElement('option'); option.value = i; return option; })); } } if (name=='' && nodes) for (name in nodes) break; if (name && name!='') $('#preview').html(Viz("digraph {\n"+" rankdir="+rankdir+";\n" +docker.containers.subgraph(name, nodes) +"\n}")); else $('#preview').html(''); } function create() { } var zoomlevel = 0; function zoom(incr = 0) { zoomlevel = (zoomlevel+incr)%2; switch (zoomlevel) { case 0: { $("#main svg, #preview svg").css("width", "auto"); $("#main svg, #preview svg").css("height", "auto"); $("#main svg, #preview svg").css("max-width", "100%"); $("#main svg, #preview svg").css("max-height", "100%"); } break; case 1: { $("#main svg, #preview svg").css("width", "100%"); $("#main svg, #preview svg").css("height", "auto"); $("#main svg, #preview svg").css("max-width", "100%"); $("#main svg, #preview svg").css("max-height", "none"); } break; case 2: { $("#main.svg, #preview svg").css("width", "auto"); $("#main.svg, #preview svg").css("height", "100%"); $("#main.svg, #preview svg").css("max-width", "none"); $("#main.svg, #preview svg").css("max-height", "100%"); } break; } } function showLogin() { $("#close").hide(); $("#console").hide(); $("#create").hide(); $("#imagetools").hide(); $("#login").show(); $("#logs").hide(); $("#main").hide(); } function showImage() { $("#close").hide(); $("#console").hide(); $("#create").hide(); $("#imagetools").show(); $("#login").hide(); $("#logs").hide(); $("#main").show(); } function showCreate() { $("#close").show(); $("#console").hide(); $("#create").show(); $("#imagetools").show(); $("#login").hide(); $("#logs").hide(); $("#main").hide(); previewCreate(); } function showConsole() { $("#close").show(); $("#console").show(); $("#create").hide(); $("#imagetools").hide(); $("#login").hide(); $("#logs").hide(); $("#main").hide(); // $("#command").focus(); // $("#command").val(""); // if ($("#screen").val()!="") $("#screen").append("\n"); } function showLogs() { $("#close").show(); $("#console").hide(); $("#create").hide(); $("#imagetools").hide(); $("#login").hide(); $("#logs").show(); $("#main").hide(); } function images(i) { console.log("->rcv images"); docker.images.set(i); $('#imagedata').empty().append(docker.images.tags().map(function(i) { var option = document.createElement('option'); option.value = i; return option; })); } function logs(data) { console.log("->rcv logs("+data.name+")"); if (data.type=='done') { $("#logs").append('\nDONE'); } else { $("#logs").append(''+htmlenc(data.text)+''); } } 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, ''); ++spans; break; case 2: res = strInsert(res, pos, ''); ++spans; break; case 4: res = strInsert(res, pos, ''); ++spans; break; case 5: res = strInsert(res, pos, ''); ++spans; break; case 7: res = strInsert(res, pos, ''); ++spans; break; case 8: res = strInsert(res, pos, ''); ++spans; break; // reset case 0: for (;spans;--spans) res = strInsert(res, pos, ""); break; case 21: if (spans) --spans; res = strInsert(res, pos, ""); break; case 22: if (spans) --spans; res = strInsert(res, pos, ""); break; case 23: if (spans) --spans; res = strInsert(res, pos, ""); break; case 25: if (spans) --spans; res = strInsert(res, pos, ""); break; case 27: if (spans) --spans; res = strInsert(res, pos, ""); break; case 28: if (spans) --spans; res = strInsert(res, pos, ""); break; // fg colors case 39: res = strInsert(res, pos, ''); ++spans; break; case 30: res = strInsert(res, pos, ''); ++spans; break; case 31: res = strInsert(res, pos, ''); ++spans; break; case 32: res = strInsert(res, pos, ''); ++spans; break; case 33: res = strInsert(res, pos, ''); ++spans; break; case 34: res = strInsert(res, pos, ''); ++spans; break; case 35: res = strInsert(res, pos, ''); ++spans; break; case 36: res = strInsert(res, pos, ''); ++spans; break; case 37: res = strInsert(res, pos, ''); ++spans; break; case 90: res = strInsert(res, pos, ''); ++spans; break; case 91: res = strInsert(res, pos, ''); ++spans; break; case 92: res = strInsert(res, pos, ''); ++spans; break; case 93: res = strInsert(res, pos, ''); ++spans; break; case 94: res = strInsert(res, pos, ''); ++spans; break; case 95: res = strInsert(res, pos, ''); ++spans; break; case 96: res = strInsert(res, pos, ''); ++spans; break; case 97: res = strInsert(res, pos, ''); ++spans; break; // bg colors case 49: res = strInsert(res, pos, ''); ++spans; break; case 40: res = strInsert(res, pos, ''); ++spans; break; case 41: res = strInsert(res, pos, ''); ++spans; break; case 42: res = strInsert(res, pos, ''); ++spans; break; case 43: res = strInsert(res, pos, ''); ++spans; break; case 44: res = strInsert(res, pos, ''); ++spans; break; case 45: res = strInsert(res, pos, ''); ++spans; break; case 46: res = strInsert(res, pos, ''); ++spans; break; case 47: res = strInsert(res, pos, ''); ++spans; break; case 100: res = strInsert(res, pos, ''); ++spans; break; case 101: res = strInsert(res, pos, ''); ++spans; break; case 102: res = strInsert(res, pos, ''); ++spans; break; case 103: res = strInsert(res, pos, ''); ++spans; break; case 104: res = strInsert(res, pos, ''); ++spans; break; case 105: res = strInsert(res, pos, ''); ++spans; break; case 106: res = strInsert(res, pos, ''); ++spans; break; case 107: res = strInsert(res, pos, ''); ++spans; break; } }); } else { break; } } for (;spans;--spans) res += ""; console.log(res); return res.replace(/\r\r\n/g, '\n'); } function ascii(txt) { var res = ""; for (i=0; i