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 %}