diff --git a/jupyterhub-static/data/static/css/header.css b/jupyterhub-static/data/static/css/header.css index 708bfe8c623b3f7bc2ff6d720c5210daa2c8a1ad..b721b5737a0cb8e9543c47509a6d3749b97267fe 100755 --- a/jupyterhub-static/data/static/css/header.css +++ b/jupyterhub-static/data/static/css/header.css @@ -1,18 +1,18 @@ -#header { - min-height: 113px; -} - .jpy-logo { height: 51px; } .navbar-top { background: white; - min-height: 113px; padding-bottom: 0px; } -.navbar-light .navbar-nav .nav-link { +.navbar-top > .container { + min-height: 113px; +} + +.navbar-light .navbar-nav .nav-link, +.navbar-light .navbar-nav .nav-link:focus { color: black; } @@ -82,4 +82,4 @@ li.dropdown-submenu:hover ul.dropdown-menu-2 { select option { font-size: 14px; -} \ No newline at end of file +} diff --git a/jupyterhub-static/data/static/jupyter-jsc-devel/css/header.css b/jupyterhub-static/data/static/jupyter-jsc-devel/css/header.css index 708bfe8c623b3f7bc2ff6d720c5210daa2c8a1ad..b721b5737a0cb8e9543c47509a6d3749b97267fe 100755 --- a/jupyterhub-static/data/static/jupyter-jsc-devel/css/header.css +++ b/jupyterhub-static/data/static/jupyter-jsc-devel/css/header.css @@ -1,18 +1,18 @@ -#header { - min-height: 113px; -} - .jpy-logo { height: 51px; } .navbar-top { background: white; - min-height: 113px; padding-bottom: 0px; } -.navbar-light .navbar-nav .nav-link { +.navbar-top > .container { + min-height: 113px; +} + +.navbar-light .navbar-nav .nav-link, +.navbar-light .navbar-nav .nav-link:focus { color: black; } @@ -82,4 +82,4 @@ li.dropdown-submenu:hover ul.dropdown-menu-2 { select option { font-size: 14px; -} \ No newline at end of file +} diff --git a/jupyterhub-static/data/static/jupyter-jsc-devel/css/pages/admin.css b/jupyterhub-static/data/static/jupyter-jsc-devel/css/pages/admin.css index 3eedb007b25b2ed8a8553655f74fe092faec8047..ab84ec231a88a1d6e2d59bdcff3372e113e72181 100755 --- a/jupyterhub-static/data/static/jupyter-jsc-devel/css/pages/admin.css +++ b/jupyterhub-static/data/static/jupyter-jsc-devel/css/pages/admin.css @@ -35,6 +35,10 @@ color: #225f8d; border-color: #225f8d; } +.default-cursor { + cursor: default !important; +} + /* .table-striped > tbody > tr:nth-of-type(2n+1):hover { color: #212529; diff --git a/jupyterhub-static/data/static/jupyter-jsc-devel/js/admin.js b/jupyterhub-static/data/static/jupyter-jsc-devel/js/admin.js index 4702b22fbb7488be24ce98f86bd0e9055eedc137..068c3ee05d1273cb9efa7a2813ab3beeaeaa4566 100755 --- a/jupyterhub-static/data/static/jupyter-jsc-devel/js/admin.js +++ b/jupyterhub-static/data/static/jupyter-jsc-devel/js/admin.js @@ -12,22 +12,15 @@ require(["jquery", "bootstrap", "moment", "jhapi", "utils"], function ( // Logging functionalities // ["jhub", "backend", "tunneling", "userlabs-mgr", "jusuf-cloud"] - ["jhub", "backend", "tunneling", "userlabs-mgr", "jusuf-cloud"].forEach(function (system) { - if (system == "jhub") { - var logger_url = "api/logger"; - } else { - var logger_url = "api/" + system + "/logger"; - } - + ["jhub", "backend", "tunneling", "jusuf-cloud"].forEach(function (system) { + var logger_url = "api/logger/" + system; + $(document).ready(function () { // Set inputs according to values from backend ["stream", "file", "mail", "syslog"].forEach(function (handler) { $.get(logger_url + "/" + handler, function (log_info) { - // console.log(handler, log_info); + console.log(system, handler, log_info); let enabled = $.parseJSON(log_info["enabled"]); - $("#" + system + "-" + handler + "-create").prop("disabled", enabled); - $("#" + system + "-" + handler + "-patch").prop("disabled", !enabled); - $("#" + system + "-" + handler + "-delete").prop("disabled", !enabled); toggle_log_infos(system, handler, enabled); @@ -35,22 +28,31 @@ require(["jquery", "bootstrap", "moment", "jhapi", "utils"], function ( $("#" + system + "-" + handler + "-formatter").val(log_info["formatter"]); switch (handler) { case "file": - $("#" + system + "-" + handler + "-logfile").val(log_info["logfile"]); + $("#" + system + "-" + handler + "-filename").val(log_info["filename"] || "/mnt/logs/file.log"); + $("#" + system + "-" + handler + "-backupcount").val(log_info["backupCount"] || 7 ); break; case "mail": - $("#" + system + "-" + handler + "-receiver").val(log_info["receiver"]); - $("#" + system + "-" + handler + "-host").val(log_info["host"]); - $("#" + system + "-" + handler + "-from").val(log_info["from"]); - $("#" + system + "-" + handler + "-subject").val(log_info["subject"]); + let toaddrs = log_info["toaddrs"] || []; + $("#" + system + "-" + handler + "-receiver").val(toaddrs.join(";")); + $("#" + system + "-" + handler + "-host").val(log_info["mailhost"] || "mail.fz-juelich.de"); + $("#" + system + "-" + handler + "-from").val(log_info["fromaddr"] || "logs@fz-juelich.de"); + $("#" + system + "-" + handler + "-subject").val(log_info["subject"] || "Log Notification"); break; case "syslog": - $("#" + system + "-" + handler + "-host").val(log_info["host"]); - $("#" + system + "-" + handler + "-port").val(log_info["port"]); - $("#" + system + "-" + handler + "-protocol").val(log_info["protocol"]); - let enabled = $.parseJSON(log_info["memory_enabled"]); - $("#" + system + "-" + handler + "-memory").prop("checked", enabled); - $("#" + system + "-" + handler + "-memory-capacity").val(log_info["memory_capacity"]); - $("#" + system + "-" + handler + "-memory-flushlevel").val(log_info["memory_flushlevel"]); + if ( "address" in log_info ) { + var host = log_info["address"][0] || "127.0.0.1"; + var port = log_info["address"][1] || 514; + } else { + var host = "127.0.0.1"; + var port = 514; + } + $("#" + system + "-" + handler + "-host").val(host); + $("#" + system + "-" + handler + "-port").val(port); + $("#" + system + "-" + handler + "-socktype").val(log_info["socktype"]); + //let enabled = $.parseJSON(log_info["memory_enabled"]); + //$("#" + system + "-" + handler + "-memory").prop("checked", enabled); + //$("#" + system + "-" + handler + "-memory-capacity").val(log_info["memory_capacity"]); + //$("#" + system + "-" + handler + "-memory-flushlevel").val(log_info["memory_flushlevel"]); break; } }) @@ -61,70 +63,55 @@ require(["jquery", "bootstrap", "moment", "jhapi", "utils"], function ( var handler_url = logger_url + "/" + handler; // POST $("#" + system + "-" + handler + "-create").click(function () { + let data = collect_data(system, handler); $(this).prop("disabled", true); - $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>') - let loglevel = $("#" + system + "-" + handler + "-loglevel").val(); - let formatter = $("#" + system + "-" + handler + "-formatter").val(); - let post_url = handler_url + "/" + loglevel + "/" + formatter; - switch (handler) { - case "file": - var filename = $("#" + system + "-" + handler + "-logfile").val(); - filename = encodeURIComponent(encodeURIComponent(filename)); - post_url += "/" + filename; - break; - case "mail": - var receiver = $("#" + system + "-" + handler + "-receiver").val(); - var host = $("#" + system + "-" + handler + "-host").val(); - var from = $("#" + system + "-" + handler + "-from").val(); - var subject = $("#" + system + "-" + handler + "-subject").val(); - post_url += "/" + receiver + "/" + host + "/" + from + "/" + subject; - break; - case "syslog": - var host = $("#" + system + "-" + handler + "-host").val(); - var port = $("#" + system + "-" + handler + "-port").val(); - var protocol = $("#" + system + "-" + handler + "-protocol").val(); - var memory = $("#" + system + "-" + handler + "-memory").prop("checked"); - var memory_capacity = $("#" + system + "-" + handler + "-memory-capacity").val(); - var memory_flushlevel = $("#" + system + "-" + handler + "-memory-flushlevel").val(); - post_url += "/" + host + "/" + port + "/" + protocol + "/" + memory + "/" + memory_capacity + "/" + memory_flushlevel; - break; - } - $.post(post_url).always(function (response) { - if (response.status == 200) { - $("#" + system + "-" + handler + "-alert").text("Successfully created a new " + handler + " handler"); - reset_alert(system, handler); - $("#" + system + "-" + handler + "-alert").addClass("alert-success"); - $("#" + system + "-" + handler + "-create").prop("disabled", true); - $("#" + system + "-" + handler + "-patch").prop("disabled", false); - $("#" + system + "-" + handler + "-delete").prop("disabled", false); - toggle_log_infos(system, handler, true); - } else { - set_error_alert(system, handler, response); - $("#" + system + "-" + handler + "-create").prop("disabled", false); - } - $("#" + system + "-" + handler + "-create").html("Create"); + $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>'); + + $.ajax({ + url: handler_url, + type: 'POST', + contentType: "application/json", + cache: false, + dataType: "json", + data: JSON.stringify(data) }) + .always(function (response) { + if (response.status == 200) { + $("#" + system + "-" + handler + "-alert").text("Successfully created " + handler); + reset_alert(system, handler); + $("#" + system + "-" + handler + "-alert").addClass("alert-success"); + toggle_log_infos(system, handler, true); + } else { + set_error_alert(system, handler, response); + toggle_log_infos(system, handler, false); + } + $("#" + system + "-" + handler + "-create").html("Create"); + }); }); // PATCH $("#" + system + "-" + handler + "-patch").click(function () { - $(this).prop("disabled", true); - $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>') - let loglevel = $("#" + system + "-" + handler + "-loglevel").val(); - let patch_url = handler_url + "/" + loglevel; + let data = collect_data(system, handler); + $(this).prop<("disabled", true); + $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>'); $.ajax({ - url: patch_url, + url: handler_url, type: 'PATCH', + contentType: "application/json", + cache: false, + dataType: "json", + data: JSON.stringify(data) }) .always(function (response) { if (response.status == 200) { - $("#" + system + "-" + handler + "-alert").text("Successfully updated the loglevel to " + loglevel); + $("#" + system + "-" + handler + "-alert").text("Successfully updated " + handler); reset_alert(system, handler); $("#" + system + "-" + handler + "-alert").addClass("alert-success"); } else { set_error_alert(system, handler, response); } - $("#" + system + "-" + handler + "-patch").prop("disabled", false); + $(this).prop("disabled", false); $("#" + system + "-" + handler + "-patch").html("Patch"); + toggle_log_infos(system, handler, true); }); }); // DELETE @@ -137,30 +124,128 @@ require(["jquery", "bootstrap", "moment", "jhapi", "utils"], function ( }) .always(function (response) { if (response.status == 200) { - $("#" + system + "-" + handler + "-alert").text("Successfully deleted " + handler + " handler"); + $("#" + system + "-" + handler + "-alert").text("Successfully deleted " + handler); reset_alert(system, handler); $("#" + system + "-" + handler + "-alert").addClass("alert-success"); - $("#" + system + "-" + handler + "-create").prop("disabled", false); - $("#" + system + "-" + handler + "-patch").prop("disabled", true); - $("#" + system + "-" + handler + "-delete").prop("disabled", true); toggle_log_infos(system, handler, false); } else { set_error_alert(system, handler, response); - $("#" + system + "-" + handler + "-delete").prop("disabled", false); + toggle_log_infos(system, handler, false); } $("#" + system + "-" + handler + "-delete").html("Delete"); }); }); + // LogTests + $("#" + system + "-" + handler + "-tests").click(function () { + $(this).prop("disabled", true); + $(this).html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>'); + $.ajax({ + url: logger_url + "/test", + type: 'GET', + }) + .always(function (response) { + if (response.status == 200) { + $("#" + system + "-" + handler + "-alert").text("Test logs sent"); + reset_alert(system, handler); + $("#" + system + "-" + handler + "-alert").addClass("alert-success"); + } else { + set_error_alert(system, handler, response); + } + $("#" + system + "-" + handler + "-tests").prop("disabled", false); + $("#" + system + "-" + handler + "-tests").removeClass("disabled"); + $("#" + system + "-" + handler + "-tests").html("Send test logs"); + }); + }); + + // Update enabled "button" if anything's changed + ["loglevel", "formatter", "filename", "backupcount", "receiver", "host", "from", "subject", "port", "socktype"].forEach(function (inputelement) { + // only change if handler is enabled and not already changed + $("#" + system + "-" + handler + "-" + inputelement).change(function () { + if ( $("#" + system + "-" + handler + "-enabled").hasClass("btn-success") ) { + $("#" + system + "-" + handler + "-enabled").text("Values changed"); + $("#" + system + "-" + handler + "-enabled").removeClass("btn-success"); + $("#" + system + "-" + handler + "-enabled").addClass("btn-primary"); + $("#" + system + "-" + handler + "-tests").addClass("disabled"); + $("#" + system + "-" + handler + "-tests").prop("disabled", true); + } + }); + }); }) + function collect_data(system, handler) { + let data = {}; + switch(handler) { + case "stream": + data = { + "level": parseInt($("#" + system + "-" + handler + "-loglevel").val()), + "formatter": $("#" + system + "-" + handler + "-formatter").val(), + }; + break; + case "file": + data = { + "level": parseInt($("#" + system + "-" + handler + "-loglevel").val()), + "formatter": $("#" + system + "-" + handler + "-formatter").val(), + "filename": $("#" + system + "-" + handler + "-filename").val(), + "backupCount": parseInt($("#" + system + "-" + handler + "-backupcount").val()), + }; + break; + case "mail": + data = { + "level": parseInt($("#" + system + "-" + handler + "-loglevel").val()), + "formatter": $("#" + system + "-" + handler + "-formatter").val(), + "toaddrs": $("#" + system + "-" + handler + "-receiver").val().split(";"), + "mailhost": $("#" + system + "-" + handler + "-host").val(), + "fromaddr": $("#" + system + "-" + handler + "-from").val(), + "subject": $("#" + system + "-" + handler + "-subject").val(), + }; + break; + case "syslog": + let host = $("#" + system + "-" + handler + "-host").val(); + let port = parseInt($("#" + system + "-" + handler + "-port").val()); + let address = [host, port]; + data = { + "level": parseInt($("#" + system + "-" + handler + "-loglevel").val()), + "formatter": $("#" + system + "-" + handler + "-formatter").val(), + "address": address, + "socktype": $("#" + system + "-" + handler + "-socktype").val(), + }; + break; + default: + data = {}; + } + return data + } + function toggle_log_infos(system, handler, enabled) { - let children = $("#" + system + "-" + handler).children(); if (enabled) { - children.prop("disabled", true); - $("#" + system + "-" + handler + "-loglevel").prop("disabled", false); + $("#" + system + "-" + handler + "-create").addClass("disabled"); + $("#" + system + "-" + handler + "-create").prop("disabled", true); + $("#" + system + "-" + handler + "-patch").removeClass("disabled"); + $("#" + system + "-" + handler + "-patch").prop("disabled", false); + $("#" + system + "-" + handler + "-delete").removeClass("disabled"); + $("#" + system + "-" + handler + "-delete").prop("disabled", false); + + $("#" + system + "-" + handler + "-enabled").removeClass("btn-danger"); + $("#" + system + "-" + handler + "-enabled").addClass("btn-success"); + $("#" + system + "-" + handler + "-enabled").text("Enabled"); } else { - children.prop("disabled", false); + $("#" + system + "-" + handler + "-create").removeClass("disabled"); + $("#" + system + "-" + handler + "-create").prop("disabled", false); + $("#" + system + "-" + handler + "-patch").addClass("disabled"); + $("#" + system + "-" + handler + "-patch").prop("disabled", true); + $("#" + system + "-" + handler + "-delete").addClass("disabled"); + $("#" + system + "-" + handler + "-delete").prop("disabled", true); + + $("#" + system + "-" + handler + "-enabled").addClass("btn-danger"); + $("#" + system + "-" + handler + "-enabled").removeClass("btn-success"); + $("#" + system + "-" + handler + "-enabled").text("Disabled"); } + + $("#" + system + "-" + handler + "-tests").removeClass("disabled"); + $("#" + system + "-" + handler + "-tests").prop("disabled", false); + // It's primary while we're receiving it's status + $("#" + system + "-" + handler + "-enabled").removeClass("btn-primary"); + return } function set_error_alert(system, handler, response) { diff --git a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html index 16ec7f4894558509770abf2bbb7ea95c4cbd5f7e..31cb6cbd8fc47c22285ace280cfbfa1fb3e811c2 100755 --- a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html +++ b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/admin.html @@ -1,7 +1,7 @@ {% extends "jupyter-jsc-devel.fz-juelich.de/page.html" %} {% block stylesheet %} -<link rel="stylesheet" href='{{ static_url("jupyter-jsc-devel/css/pages/admin.css", include_version=False) }}' +<link rel="stylesheet" href='{{ static_url("jupyter-jsc-devel/css/pages/admin.css", include_version=False) }}?v=210812' type="text/css" /> {% endblock %} @@ -45,17 +45,24 @@ </div> {% endmacro %} + {% macro current_status(log, system, enabled) %} + <div class="mb-2"> + <button id="{{system}}-{{log|lower}}-enabled" disabled class="disabled btn btn-rounded btn-primary">Receive status <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span></button> + <button id="{{system}}-{{log|lower}}-tests" class="disabled btn btn-rounded btn-primary hidden">Send test logs</button> + </div> + {% endmacro %} + {% macro select(log, system, id="loglevel", text="LogLevel") %} <label for="{{system}}-{{log|lower}}-{{id}}">{{ text }}</label> <select class="form-control mb-2" id="{{system}}-{{log|lower}}-{{id}}"> - <option value="NOTSET">NotSet</option> - <option value="TRACE">Trace</option> - <option value="DEBUG">Debug</option> - <option value="INFO">Info</option> - <option value="WARNING">Warning</option> - <option value="ERROR">Error</option> - <option value="CRITICAL">Critical</option> - <option value="DEACTIVATE">Deactivate</option> + <option value="0">NotSet</option> + <option value="5">Trace</option> + <option value="10">Debug</option> + <option value="20">Info</option> + <option value="30">Warning</option> + <option value="40">Error</option> + <option value="50">Critical</option> + <option value="60">Deactivate</option> </select> {% endmacro %} @@ -74,19 +81,23 @@ {% macro stream_logger(log, system) %} {{ request_buttons(log, system) }} + {{ current_status(log, system) }} {{ select(log, system) }} {{ formatter(log, system) }} {% endmacro %} {% macro file_logger(log, system) %} {{ request_buttons(log, system) }} + {{ current_status(log, system) }} {{ select(log, system) }} {{ formatter(log, system) }} - {{ input(log, system, "logfile", "Log File") }} + {{ input(log, system, "filename", "Log File") }} + {{ input(log, system, "backupcount", "BackupCount", type="number") }} {% endmacro %} {% macro mail_logger(log, system) %} {{ request_buttons(log, system) }} + {{ current_status(log, system) }} {{ select(log, system) }} {{ formatter(log, system) }} {{ input(log, system, "receiver", "Receiver (if multiple, ; separated)") }} @@ -97,15 +108,17 @@ {% macro syslog_logger(log, system) %} {{ request_buttons(log, system) }} + {{ current_status(log, system) }} {{ select(log, system) }} {{ formatter(log, system) }} {{ input(log, system, "host", "Host") }} {{ input(log, system, "port", "Port", type="number") }} - <label for="{{system}}-{{log|lower}}-protocol">{{ log }} Protocol</label> - <select class="form-control mb-2" id="{{system}}-{{log|lower}}-protocol"> - <option value="udp">UDP</option> - <option value="tcp">TCP</option> + <label for="{{system}}-{{log|lower}}-socktype">{{ log }} Protocol</label> + <select class="form-control mb-2" id="{{system}}-{{log|lower}}-socktype"> + <option value="ext://socket.SOCK_DGRAM">UDP</option> + <option value="ext://socket.SOCK_STREAM">TCP</option> </select> + {# <hr/> <div class="custom-control custom-switch mb-2"> <input class="custom-control-input" type="checkbox" id="{{system}}-{{log|lower}}-memory"> @@ -114,7 +127,7 @@ </label> </div> {{ input(log, system, "memory-capacity", "Memory Capacity", type="number") }} - {{ select(log, system, "memory-flushlevel", "Memory FlushLevel") }} + {{ select(log, system, "memory-flushlevel", "Memory FlushLevel") }} #} {% endmacro %} {% macro loglevel_interface(title, system) %} @@ -155,7 +168,7 @@ {{ loglevel_interface("JupyterHub", "jhub") }} {{ loglevel_interface("Backend", "backend") }} {{ loglevel_interface("Tunnel", "tunneling") }} - {{ loglevel_interface("Userlabs Manager", "userlabs-mgr") }} + <!-- {{ loglevel_interface("Userlabs Manager", "userlabs-mgr") }} --> {{ loglevel_interface("JUSUF Cloud Userlabs Manager", "jusuf-cloud") }} </div> @@ -360,4 +373,4 @@ You can choose to leave the proxy and/or single-user servers running by unchecki </script> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/header.html b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/header.html index 875d91d8b4d4a78e39b6dc1fc5398461742d195f..3c1ec9575179a0d88e7afd18cb6cd2c65d6bf910 100755 --- a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/header.html +++ b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/header.html @@ -1,7 +1,7 @@ {% macro submenu(title, caption_href) %} {% set id = title.replace('-', '') %} <li class="dropdown-submenu"> - <a id="navbarNavDropdown{{id}}" href="" aria-haspopup="true" aria-expanded="false" class="dropdown-item"> + <a id="navbarNavDropdown{{id}}" aria-haspopup="true" aria-expanded="false" class="dropdown-item"> {{ title }} </a> <ul aria-labelledby="navbarNavDropdown{{id}}" class="dropdown-menu dropdown-menu-2"> @@ -119,4 +119,4 @@ </div> </div> </nav> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/spawn_depth_1.html b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/spawn_depth_1.html index 6bcd40ca7dd076a4ebf58469d4047085f8b49954..cf536c43f7c1e2d5aa1efaa4a50c0d123cdd5e1b 100755 --- a/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/spawn_depth_1.html +++ b/jupyterhub/config/data/templates/jupyter-jsc-devel.fz-juelich.de/spawn_depth_1.html @@ -9,7 +9,7 @@ {% endblock %} {% macro input(name, value) %} -<input id="{{name}}" name="{{name}}" autocomplete="off" value="{{value}}" style="display: None" /> +<input id="{{name}}" name="{{name}}" autocomplete="off" value="{{value}}" style="display: none;" /> {% endmacro %} {% macro dropdown(id, function_name) %} @@ -35,6 +35,23 @@ </div> {% endmacro %} +{% macro checkbox_div(id, text, callback) %} +<div id="{{id}}_checkbox_div" class="card border-dark rounded-0 mb-2" style="display: none;"> + <div class="card-text text-right my-2 mr-4"> + <span class="align-middle"> {{ text }} </span> + <img class="mr-2" id="{{id}}-checkbox-qm" + src="https://jupyter-jsc.fz-juelich.de/hub/static/images/qm.png" data-original-title="" title="" + height="20" /> + + <div class="material-switch pull-right"> + <input id="{{id}}_checkbox_input" name="{{id}}_checkbox_input" onclick="{{callback}}()" + class="form-control" type="checkbox" /> + <label for="{{id}}_checkbox_input" class="label-primary mb-1"></label> + </div> + </div> +</div> +{% endmacro %} + {% macro resource_div(id, name, label, min, max, value) %} <div id="resource_{{id}}_div" style="display: none"> <label id="resource_{{id}}_label" class="custom-label resource" for="resource_{{id}}_input"> @@ -52,9 +69,11 @@ </tr> {% endmacro %} + {% block main %} -<div id="spawn-d1-page" class="row justify-content-around px-md-0 px-lg-4"> - <div id="spawn-options" class="col col-auto"> +<!-- <div id="spawn-d1-page" class="row justify-content-around px-md-0 px-lg-4"> --> +<div id="spawn-d1-page" class="row px-md-0 px-lg-4"> + <div id="spawn-options" class="col col-auto offset-1 col-xl-3" style="min-width: 350px;"> {% block heading %} <h1 id="optionsheader"></h1> {% endblock %} @@ -75,6 +94,7 @@ {{ input("project_input", "undefined") }} {{ input("partition_input", "undefined") }} {{ input("reservation_input", "undefined") }} + {{ input("modules_input", "") }} </div> {% if ( spawner_options_form.get('dropdown_lists', {}).get('options', {}).keys() | length > 0) -%} @@ -89,20 +109,8 @@ {{ resource_div("runtime", "Runtime", "Runtime (min) [1, 1440]", 1, 1440, 30) }} {{ resource_div("gpus", "GPUS", "GPUs [1, 4]", 1, 4, 4) }} - <div id="reservations_checkbox_div" class="card border-dark rounded-0 mb-2" style="display: none;"> - <div class="card-text text-right my-2 mr-4"> - <span class="align-middle">Show reservation info</span> - <img class="mr-2" id="reservations-checkbox-qm" - src="https://jupyter-jsc.fz-juelich.de/hub/static/images/qm.png" data-original-title="" title="" - height="20" /> - - <div class="material-switch pull-right"> - <input id="reservations_checkbox_input" name="reservations_checkbox_input" onclick="reservationCB()" - class="form-control" type="checkbox" /> - <label for="reservations_checkbox_input" class="label-primary mb-1"></label> - </div> - </div> - </div> + {# {{ checkbox_div("modules", "Configure modules", "modulesCB") }} #} + {{ checkbox_div("reservations", "Show reservation info", "reservationCB") }} <input type="submit" value="Start" class="btn btn-rounded btn-primary form-control" /> @@ -116,37 +124,53 @@ </form> </div> - <div id="reservation-infos" class="col col-auto"> - <h1 style="visibility: hidden">Server Options</h1> - <div id="reservation_info_empty_div" style="display: none; overflow-x: auto"> - <table class="bg-white"> - <tr> - <th colspan="2" class="custom-th" style="color: red"> Please choose a reservation </th> - </tr> - </table> + <div id="extra-infos" class="col col-auto offset-1 offset-xl-0 col-xl-6 row no-gutters justify-content-between"> + <div id="module-options" class="col col-12 col-xl-auto" style="display: none;"> + <h1>Module Configuration</h1> + <div id="module-options-div"> + {# {% macro form_check(id, label, disabled="false")%} + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" id="{{id}}" + {% if disabled == "true" %} disabled {% endif %}> + <label class="form-check-label" for="{{id}}">{{ label }}</label> + </div> + {% endmacro %} #} + </div> </div> - <div id="reservation_info_div" style="display: none; overflow-x: auto"> - <table class="bg-white"> - <tr> - <th colspan="2" class="custom-th" id="reservation_table_name"> Reservation: Name </th> - </tr> - {{ tr("state", "State", "INACTIVE") }} - {{ tr("users", "Users") }} - {{ tr("accounts", "Accounts") }} - {{ tr("partition", "PartitionName") }} - {{ tr("start", "StartTime") }} - {{ tr("end", "EndTime") }} - {{ tr("duration", "Duration") }} - {{ tr("nodescnt", "NodeCnt") }} - {{ tr("nodes", "Nodes") }} - {{ tr("corecnt", "CoreCnt") }} - {{ tr("tres", "TRES") }} - {{ tr("features", "Features") }} - {{ tr("flags", "Flags") }} - {{ tr("licenses", "Licenses") }} - {{ tr("burstbuffer", "BurstBuffer") }} - {{ tr("watts", "Watts") }} - </table> + + <div id="reservation-infos" class="col col-12 col-xl-auto"> + <div id="reservation_info_empty_div" style="display: none; overflow-x: auto"> + <h1>Reservation Infos</h1> + <table class="bg-white"> + <tr> + <th colspan="2" class="custom-th" style="color: red"> Please choose a reservation </th> + </tr> + </table> + </div> + <div id="reservation_info_div" style="display: none; overflow-x: auto"> + <h1>Reservation Infos</h1> + <table class="bg-white"> + <tr> + <th colspan="2" class="custom-th" id="reservation_table_name"> Reservation: Name </th> + </tr> + {{ tr("state", "State", "INACTIVE") }} + {{ tr("users", "Users") }} + {{ tr("accounts", "Accounts") }} + {{ tr("partition", "PartitionName") }} + {{ tr("start", "StartTime") }} + {{ tr("end", "EndTime") }} + {{ tr("duration", "Duration") }} + {{ tr("nodescnt", "NodeCnt") }} + {{ tr("nodes", "Nodes") }} + {{ tr("corecnt", "CoreCnt") }} + {{ tr("tres", "TRES") }} + {{ tr("features", "Features") }} + {{ tr("flags", "Flags") }} + {{ tr("licenses", "Licenses") }} + {{ tr("burstbuffer", "BurstBuffer") }} + {{ tr("watts", "Watts") }} + </table> + </div> </div> </div> @@ -182,10 +206,15 @@ function _hide_divs() { var divs = ["resource_nodes", "resource_runtime", "resource_gpus", "reservations_checkbox", "reservation_info_empty", "reservation_info"]; - divs.forEach(function (item, index) { + divs.forEach(function (item) { $("#" + item + "_div").hide(); }); - $('#reservations_checkbox_input').prop("checked", false); + $("#reservations_checkbox_input").prop("checked", false); + // $("#modules_checkbox_input").prop("checked", false); + // var module_checkboxes = ["nvdashboard"] + // module_checkboxes.forEach(function(item) { + // $("#" + item).prop("checked", false); + // }) } function _hide_and_reset(ids) { @@ -193,8 +222,10 @@ if (item == "option1") { $("#options1_input").val("undefined"); } else $("#" + item + "_input").val("undefined"); + $("#modules_input").val(""); // always reset modules input $("#" + item + "s_dropdown").hide(); }); + _hide_divs(); } @@ -220,8 +251,9 @@ $('#systems_dropdown_button').val("{{ first_element.get("foo") }}").trigger("change"); $('#systems_dropdown').show(); } - {% endfor -%} {# option1 -#} + {% endfor -%} } + function onChangeSystems() { var option1 = $('#options1_input').val(); var system = $('#systems_dropdown_button').val(); @@ -251,6 +283,45 @@ {% endif -%} {% endfor -%} {% endfor -%} + + if ( option1 == "JupyterLab-3.1" ) { + $("#module-options-div").html(""); // empty the div + var modules = {{ modules.get("UNICORE", {}) | safe }}; + if (!$.isEmptyObject(modules[system])) { + $.each(modules[system], function(key, value) { + let input = '<div class="form-check">'; + if (value["disabled"] == "true") input += '<input class="form-check-input" type="checkbox" value="" id="' + value["name"] + '" disabled>'; + else input += '<input class="form-check-input" type="checkbox" value="" id="' + value["name"] + '">'; + input += '<label class="form-check-label" for="' + value["name"] + '">' + key + '</label>'; + input += "</div>"; + $("#module-options-div").append(input); + if (value["checked"] == "true") $("#" + value["name"]).prop("checked", true); + }) + + $("#module-options-div>.form-check").each( function() { + $(this).change( function() { + let input = $(this).children().first(); + let label = $(this).children().last().text(); + let old_val = $('#modules_input').val(); + + if ( input.prop("checked") ) { + var new_val = old_val + label + ";"; + } else { + if ( old_val.includes(label) ) { + var new_val = old_val.replace(label + ";", ""); + } + } + $('#modules_input').val(new_val); + }) + }) + $("#module-options").show(); + } else { + $("#module-options").hide(); + } + } else { + $("#module-options").hide(); + $("#module-options-div").html(""); + } } function onChangeAccounts() { @@ -471,6 +542,7 @@ } $('#reservations_checkbox_div').show(); } + function reservationCB() { var reservation = $('#reservations_dropdown_button').val(); if ( $('#reservations_checkbox_input').is(":checked") ) { @@ -486,5 +558,13 @@ $('#reservation_info_empty_div').hide(); } } + + // function modulesCB() { + // if ( $('#modules_checkbox_input').is(":checked") ) { + // $('#module-options').show(); + // } else { + // $('#module-options').hide(); + // } + // } </script> {% endblock script %} diff --git a/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/header.html b/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/header.html index 97e20eaf76bd2958bf7e448793855d5ea05a24c3..ce526e18dcbdb49e4d9b3775a28b1621165ab030 100755 --- a/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/header.html +++ b/jupyterhub/config/data/templates/jupyter-jsc.fz-juelich.de/header.html @@ -1,7 +1,7 @@ {% macro submenu(title, caption_href) %} {% set id = title.replace('-', '') %} <li class="dropdown-submenu"> - <a id="navbarNavDropdown{{id}}" href="" aria-haspopup="true" aria-expanded="false" class="dropdown-item"> + <a id="navbarNavDropdown{{id}}" aria-haspopup="true" aria-expanded="false" class="dropdown-item"> {{ title }} </a> <ul aria-labelledby="navbarNavDropdown{{id}}" class="dropdown-menu dropdown-menu-2"> @@ -119,4 +119,4 @@ </div> </div> </nav> -{% endblock %} \ No newline at end of file +{% endblock %}