diff --git a/static/images/base4NFDI_kurz_rgb.png b/static/images/base4NFDI_kurz_rgb.png new file mode 100644 index 0000000000000000000000000000000000000000..4d44e8688b1e81a84ef5f65bfaf9d92ca0a59840 Binary files /dev/null and b/static/images/base4NFDI_kurz_rgb.png differ diff --git a/static/images/jupyter4nfdi_logo.png b/static/images/jupyter4nfdi_logo.png new file mode 100755 index 0000000000000000000000000000000000000000..1a31cc97efcbaa2161f2b6f0810551f50c0c85a9 Binary files /dev/null and b/static/images/jupyter4nfdi_logo.png differ diff --git a/static/images/nfdi-logo-small.svg b/static/images/nfdi-logo-small.svg new file mode 100644 index 0000000000000000000000000000000000000000..e4e29d919a6869f2b4d0c0c8aa59bc0d8a80b5e1 --- /dev/null +++ b/static/images/nfdi-logo-small.svg @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + viewBox="0 0 283.47122 126.13" + xml:space="preserve" + sodipodi:docname="nfdi-logo-small.svg" + inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" + width="283.47122" + height="126.13" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"><defs + id="defs103" /><sodipodi:namedview + id="namedview101" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + showgrid="false" + inkscape:zoom="0.84333982" + inkscape:cx="390.11558" + inkscape:cy="-40.908776" + inkscape:window-width="1920" + inkscape:window-height="1200" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="Ebene_1" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" /> +<style + type="text/css" + id="style2"> + .st0{fill:none;} + .st1{fill:#B3BCC2;} + .st2{fill:#FFFFFF;} + .st3{fill:#0BBBEF;} + .st4{fill:#A2C617;} + .st5{fill:#8A959C;} + .st6{fill:#45556A;} +</style> + + +<g + id="g98" + transform="translate(-70.86,-70.87)"> + <path + class="st2" + d="m 220.66,70.87 c -22.97,0 -41.65,18.68 -41.65,41.65 v 76.35 c 0,4.49 3.64,8.13 8.13,8.13 4.49,0 8.13,-3.64 8.13,-8.13 v -50.61 h 12.86 c 4.18,0 7.57,-3.46 7.57,-7.73 0,-4.27 -3.39,-7.73 -7.57,-7.73 h -12.86 v -10.28 c 0,-14 11.39,-25.39 25.39,-25.39 4.49,0 8.13,-3.64 8.13,-8.13 0,-4.49 -3.64,-8.13 -8.13,-8.13" + id="path82" /> + <g + id="g88"> + <path + class="st2" + d="m 147.31,196.99 c -4.49,0 -8.13,-3.64 -8.13,-8.13 l 0.06,-33.76 c 0,-14 -11.39,-25.39 -25.39,-25.39 -14,0 -25.39,11.39 -25.39,25.39 0,4.49 -3.64,8.13 -8.13,8.13 -4.49,0 -8.13,-3.64 -8.13,-8.13 0,-22.96 18.68,-41.65 41.65,-41.65 22.97,0 41.65,18.68 41.65,41.65 v 33.76 c 0,4.49 -3.7,8.13 -8.19,8.13" + id="path84" /> + <path + class="st3" + d="m 89.8,187.5 c 0,5.23 -4.24,9.47 -9.47,9.47 -5.23,0 -9.47,-4.24 -9.47,-9.47 0,-5.23 4.24,-9.47 9.47,-9.47 5.23,0 9.47,4.24 9.47,9.47" + id="path86" /> + </g> + <g + id="g94"> + <path + class="st4" + d="m 351.91,95.15 c 3.49,3.89 3.17,9.88 -0.72,13.37 -3.89,3.49 -9.88,3.16 -13.37,-0.73 -3.49,-3.89 -3.17,-9.88 0.72,-13.37 3.89,-3.49 9.88,-3.17 13.37,0.73" + id="path90" /> + <path + class="st2" + d="m 352.99,133.86 v 55 c 0,4.49 -3.64,8.13 -8.13,8.13 v 0 c -4.49,0 -8.13,-3.64 -8.13,-8.13 v -55 c 0,-4.49 3.64,-8.13 8.13,-8.13 v 0 c 4.5,0 8.13,3.64 8.13,8.13 z" + id="path92" /> + </g> + <path + class="st2" + d="m 304.88,70.87 c -4.49,0 -8.13,3.64 -8.13,8.13 v 43.2 c -7.06,-5.47 -15.91,-8.73 -25.51,-8.73 -23.03,0 -41.77,18.73 -41.77,41.76 0,23.03 18.73,41.76 41.77,41.76 23.03,0 41.76,-18.73 41.76,-41.76 V 79 c 0,-4.49 -3.63,-8.13 -8.12,-8.13 z m -33.64,109.87 c -14.07,0 -25.51,-11.44 -25.51,-25.51 0,-14.06 11.44,-25.51 25.51,-25.51 14.06,0 25.51,11.44 25.51,25.51 -0.01,14.07 -11.45,25.51 -25.51,25.51 z" + id="path96" /> +</g> +</svg> diff --git a/static/images/nfdi_rgb_Wortmarke_Zusatz_hoch.png b/static/images/nfdi_rgb_Wortmarke_Zusatz_hoch.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad76de01d746e2196ddf7fff049d8baa747a9d8 Binary files /dev/null and b/static/images/nfdi_rgb_Wortmarke_Zusatz_hoch.png differ diff --git a/templates/footer.html b/templates/footer.html new file mode 100644 index 0000000000000000000000000000000000000000..124760db1749fc44de57facda2f91bced3a0056b --- /dev/null +++ b/templates/footer.html @@ -0,0 +1,206 @@ +{%- import "macros/svgs.jinja" as svg -%} + +{%- set jupyter_name = "Jupyter-JSC" -%} + +{#- Get all systems configured for this hub, + sort them by weight and assign status ids -#} +{#- Jupyter should always be first -#} +{%- set incident_services = custom_config.get("incidentCheck", {}).get("services", {}) -%} +{%- set systems_default_order = [["JUPYTER", incident_services.get("JUPYTER", 40)]] -%} +{%- for system in custom_config.get("systems", {}) | sort(attribute='weight') -%} + {%- set system = system.upper().replace("-", '') -%} + {%- set status_id = incident_services.get(system, 0) -%} + {%- do systems_default_order.append([system, status_id]) -%} +{%- endfor -%} + +{%- macro random_int(len) -%} + {%- for _ in range(len) -%} + {{ range(10) | random }} + {%- endfor -%} +{%- endmacro -%} + +{%- macro number_of_users(system) -%} + {%- if system == "jupyter" -%} + {%- set system_svg = svg.users_svg -%} + {%- set url_suffix = "" -%} + {%- elif system == "jsccloud"%} + {%- set system_svg = svg.servers_svg -%} + {%- set url_suffix = "var-system=JSC-Cloud" -%} + {%- else -%} + {%- set system_svg = svg.servers_svg -%} + {%- set url_suffix = "var-system=" + system.upper() -%} + {%- endif -%} +<a class="system-users d-inline-block text-muted ms-1" + data-bs-toggle="tooltip" data-bs-placement="top" title="Number of active {%- if system == 'jupyter' %} users in the last 24 hours {%- else %} servers {%- endif -%}" + href="https://{{hostname}}/grafana/?{{url_suffix}}" target="_blank"> + <span id="{{system}}-users">0</span> + <span> {{ system_svg | safe }} </span> + <div class="system-users-link-div d-inline-block"> + <span class="system-users-link" id="{{system}}-users-link"> + {{ svg.link_svg | safe }} + </span> + </div> +</a> +{%- endmacro -%} + +{%- macro ampel(system, system_id) -%} +{%- set system_lower = system.lower() %} +<div id="ampel-{{system_lower}}" class="text-center"> + <img class="ampel-img" src='{{static_url( "images/footer/systems/" + system_lower + ".svg?v=" + random_int(10) )}}' /> + <a id="ampel-{{system_lower}}-tooltip" href="https://status.jsc.fz-juelich.de/services/{{system_id}}" target="_blank" class="align-middle" data-bs-toggle="tooltip" data-bs-placement="top"> + {%- if system == "JUPYTER" -%} + {{ jupyter_name }} + {%- elif system == "JSCCLOUD" -%} + JSC-Cloud + {%- else -%} + {{ system }} + {%- endif -%} + </a> + {{ number_of_users(system_lower) }} +</div> +{%- endmacro -%} + +{%- macro create_carousel_systems(start_index, length) -%} +{%- set end_index = start_index + length -%} +{%- for system_config in systems_default_order %} + {%- if loop.index0 >= start_index and loop.index0 < end_index %} +{{ ampel(system_config[0], system_config[1]) }} + {%- endif -%} +{%- endfor -%} +{%- endmacro -%} + + +{%- block footer -%} +<footer class="navbar mt-auto p-0"> + <div id="footer-top" class="container-fluid justify-content-evenly p-4"> + {%- if systems_default_order | length > 5 -%} + {#- We create a carousel to be able to show all systems in the footer #} + <div id="footerSystemsCarousel" class="carousel carousel-dark slide w-100" data-bs-ride="carousel" data-bs-interval="10000"> + <div class="carousel-inner"> + <div class="carousel-item active"> + <div id="systems-page-1" class="d-flex justify-content-evenly"> + {{ create_carousel_systems(0, 4) }} + </div> + </div> + <div class="carousel-item"> + <div id="systems-page-2" class="d-flex justify-content-evenly"> + {{ create_carousel_systems(4, 4) }} + </div> + </div> + </div> + <button class="carousel-control-prev" type="button" data-bs-target="#footerSystemsCarousel" data-bs-slide="prev" style="width: unset;"> + <span class="carousel-control-prev-icon"></span> + <span class="visually-hidden">Previous</span> + </button> + <button class="carousel-control-next" type="button" data-bs-target="#footerSystemsCarousel" data-bs-slide="next" style="width: unset;"> + <span class="carousel-control-next-icon"></span> + <span class="visually-hidden">Next</span> + </button> + </div> + {%- else -%} + {#- We only have a few systems and do not need a carousel to display them #} + <div id="systems-page-1" class="d-flex justify-content-evenly w-100"> + {%- for system_config in systems_default_order %} + {{ ampel(system_config[0], system_config[1]) }} + {%- endfor %} + </div> + {%- endif %} + </div> + <div id="footer-bottom" class="container-fluid justify-content-center"> + {%- set logo_width = "220px" -%} + {%- set div_classes = "px-2 text-center" %} + <a class="py-2 {{div_classes}}" target="_blank" href="https://www.fz-juelich.de">© Forschungszentrum Jülich</a> + <div class="flex-grow-1 {{div_classes}}"> + {%- set footer_margin = "m-1" %} + <a href="{{ base_url }}imprint">Legal Notice</a> + <span class="{{ footer_margin }}">|</span> + <a href="{{ base_url }}privacy">Privacy Policy</a> + <span class="{{ footer_margin }}">|</span> + <a href="{{ base_url }}terms">Terms of Service</a> + <span class="{{ footer_margin }}">|</span> + <a href="mailto:ds-support@fz-juelich.de?subject=Jupyter4NFDI Support&body=Please describe your problem here. (english or german)">Support</a> + </div> + <div class="py-4 {{div_classes}}"> + <a href="https://www.nfdi.de/" target="_blank"> + <img id="helmholtz-logo" src='{{ static_url("images/nfdi-logo-small.svg", include_version=False) }}' height="60px"> + </a> + </div> + </div> +</footer> +{%- endblock -%} + + +{%- block script -%} +<script type="text/javascript"> +require(["jquery", "home/utils"], function ( + $, + utils +) { + "use strict"; + + function reorderSystems(incidentsData) { + const systemsDefaultOrder = {{ systems_default_order | tojson}}; + // Create copy of data and filter it + var systemsFiltered = { ...incidentsData }; + for (let key in systemsFiltered) { + if (systemsFiltered[key].health < 30) delete systemsFiltered[key]; + } + delete systemsFiltered["JUPYTER"]; // Jupyter should always be first + + var systemsFilteredandSortedBySeverity = Object.keys(systemsFiltered).sort((a, b) => systemsFiltered[a]["health"] < systemsFiltered[b]["health"]); + + // Finally, create sorted list with all systems + var systemsSorted = ["JUPYTER"]; + systemsFilteredandSortedBySeverity.forEach((system) => { + systemsSorted.push(system); + }); + systemsDefaultOrder.forEach(systemConfig => { + var system = systemConfig[0]; + if (!systemsSorted.includes(system)) { + systemsSorted.push(system); + } + }) + + var carousel_exists = $("#footerSystemsCarousel").length; + // Recreate footer with systems in the sorted order + for (const [index, system] of systemsSorted.entries()) { + let ampel = $(`#ampel-${system.toLowerCase()}`); + ampel.remove(); + if (!carousel_exists) { + $("#systems-page-1").append(ampel); + } + else { + if (index < 4) $("#systems-page-1").append(ampel); + else $("#systems-page-2").append(ampel); + } + } + } + + function updateSystemHoverTooltips() { + const incidents = {{ incidents | tojson }}; + for (const [system, systemInfo] of Object.entries(incidents)) { + if (systemInfo.incident) { + $(`#ampel-${system.toLowerCase()}-tooltip`) + .attr('data-bs-original-title', systemInfo.incident); + } + } + reorderSystems(incidents); + } + + $(document).ready(function() { + updateSystemHoverTooltips(); + utils.updateNumberOfUsers(); + }) + + if (!(window.location.pathname.endsWith("home") || window.location.pathname.includes("spawn-pending"))) { + console.log("setup SSE") + let userSpawnerNotificationUrl = `${jhdata.base_url}api/users/${jhdata.user}/notifications/spawners?_xsrf=${window.jhdata.xsrf_token}`; + evtSourcesGlobal["footer"] = new EventSource(userSpawnerNotificationUrl); + evtSourcesGlobal["footer"].onmessage = (e) => { + utils.updateNumberOfUsers(); + }; + } + +}) +</script> +{%- endblock -%} diff --git a/templates/header.html b/templates/header.html new file mode 100644 index 0000000000000000000000000000000000000000..1802e22c650c1d930709ae5a9e7b828beb827968 --- /dev/null +++ b/templates/header.html @@ -0,0 +1,73 @@ +{%- macro create_user_widget() -%} +{%- if user %} +<div class="dropdown"> + <button class="btn btn-outline-primary dropdown-toggle mb-2" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside">{{ user.name }}</button> + <ul class="dropdown-menu dropdown-menu-end w-100"> + {%- if auth_state and auth_state.get("last_login", False) %} + <li><h6 class="dropdown-header">Last login</h6></li> + <li><a class="dropdown-item disabled text-black">{{ auth_state.get("last_login") }}</a></li> + <li><hr class="dropdown-divider"></li> + {%- endif -%} + <li><a class="dropdown-item text-decoration-none" href="{{ base_url }}2FA">2-Factor Authentication</a></li> + <li><hr class="dropdown-divider"></li> + <li> + <button id="logout" class="dropdown-item"> + <svg class="align-middle" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-right" viewBox="0 0 16 16"> + <path fill-rule="evenodd" d="M10 12.5a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v2a.5.5 0 0 0 1 0v-2A1.5 1.5 0 0 0 9.5 2h-8A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h8a1.5 1.5 0 0 0 1.5-1.5v-2a.5.5 0 0 0-1 0v2z"/> + <path fill-rule="evenodd" d="M15.854 8.354a.5.5 0 0 0 0-.708l-3-3a.5.5 0 0 0-.708.708L14.293 7.5H5.5a.5.5 0 0 0 0 1h8.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3z"/> + </svg> + <span class="align-middle">Logout</span> + </button> + </li> + </ul> +</div> +{%- else %} +<div class="empty mb-3"></div> +{%- endif -%} +{%- endmacro -%} + +{%- macro create_navigation(prefix="") -%} +<ul class="nav"> + {#- Show different headers depending on if a user is logged in or not -#} + + {#- If not logged in, we cannot show these links in the user widget, so we put them in the nav bar instead -#} + <div class="d-flex"> + {%- if user %} + <li class="nav-item"><a id="{{prefix}}start-nav-item" class="nav-link text-decoration-none" href="{{ base_url }}home">JupyterLab</a></li> + {%- if user.admin %} + <li class="nav-item"><a id="{{prefix}}admin-nav-item" class="nav-link text-decoration-none" href="{{ base_url }}admin">Admin</a></li> + {%- endif -%} + {%- else %} + <li class="nav-item"><a id="{{prefix}}start-nav-item" class="nav-link text-decoration-none" href="{{ base_url }}login">Login</a></li> + {%- endif %} + <li class="nav-item"><a id="{{prefix}}status-nav-item" class="nav-link text-decoration-none" target="_blank" href="https://status.jsc.fz-juelich.de/">JSC Status</a></li> + <li class="nav-item"><a id="{{prefix}}docs-nav-item" class="nav-link text-decoration-none" target="_blank" href="https://docs.{{hostname}}/github/FZJ-JSC/jupyter-jsc-notebooks/blob/documentation/index.ipynb">Documentation</a></li> + <li class="nav-item"><a id="{{prefix}}links-nav-item" class="nav-link text-decoration-none" href="{{ base_url }}links">More Links</a></li> + </div> +</ul> +{%- endmacro -%} + +{%- block header %} +<nav class="navbar navbar-light navbar-expand-lg bg-white pb-0"> + <div class="container-fluid"> + <a class="navbar-brand" href="https://fz-juelich.de/jsc/en" target="_blank"> + <img id="jsc-logo" class="p-3" title="https://base4nfdi.de/" alt="base4NFDIJSC" src='{{ static_url("images/base4NFDI_kurz_rgb.png", include_version=False) }}' height="100px"> + </a> + {#- Button that toggles the navigation. Is visible on medium screens and smaller. #} + <button class="navbar-toggler mb-4" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapsibleContent"> + <span class="navbar-toggler-icon"></span> + </button> + {#- This div is hidden on medium screens and smaller. #} + <div class="collapse navbar-collapse align-self-end"> + {{ create_navigation() }} + </div> + <div class="d-flex flex-column align-items-end ms-auto"> + {{ create_user_widget() }} + </div> + </div> + {#- This div is toggled by the navbar toggle button above and appears below the logos. #} + <div class="collapse navbar-collapse d-lg-none" style="margin-left: 2rem;" id="navbarCollapsibleContent"> + {{ create_navigation(prefix="collapse-") }} + </div> +</nav> +{%- endblock %} diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000000000000000000000000000000000000..3975c005e2b03a9d19d7546012eb38a570e1c073 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,115 @@ +{%- extends "page.html" -%} + +{%- block stylesheet -%} +<link rel="stylesheet" href='{{static_url("css/login.css")}}' type="text/css" /> +{%- endblock -%} + + +{%- macro carousel_item(title, href, title_text, text, active="") -%} +<div class="carousel-item {{active}}"> + <a target="_blank" href="{{href}}" title="{{title}}"> + <div class="text-small"> + <ul type="square"> + <li class="text-dark"><small>{{ title.upper() }}</small></li> + </ul> + </div> + <h3>{{ title_text }}</h3> + </a> + <p class="fs-5" style="color: #023d6b;">We are pleased to bring "Supercomputing in your browser".</p> + <p class="fs-5"> {{ text }} <a target="_blank" href="{{href}}">Read more.</a> </p> +</div> +{%- endmacro -%} + + +{%- block main -%} +<div class="row g-0 h-100 justify-content-center"> + <div class="col-12 col-lg-4 order-lg-1"> + <div id="login-div" class="d-flex flex-column bg-secondary h-100"> + <div id="upper-login-div" class="d-flex flex-column justify-content-center mx-auto p-4"> + <h3>Jupyter4NFDI</h3> + <p class="fs-5"> + A central JupyterHub providing access to various software stacks + and computing resources across the NFDI consortia. + <br><br> + Log in is currently possible via Helmholtz AAI. Once <a href="https://nfdi-aai.de/" target="_blank">IAM4NFDI</a> is ready, we will use this AAI instead. + The resources you can use depend on the selected Identity Provider. + <br><br> + If you are an administrator and would like to add your resources to this central JupytreHub, feel free to <a href="mailto:ds-support@fz-juelich.de">contact</a> us. + </p> + </div> + <div id="lower-login-div" class="bg-info"> + <div class="d-flex justify-content-center align-items-center mx-auto p-4"> + <a id="btn-login" class="btn btn-primary" role="button">Login</a> + <div class="white-line"></div> + <img src='{{static_url("images/pages/login/User.svg", include_version=False) }}' /> + <div class="white-line"></div> + <a id="btn-register" class="btn btn-primary" role="button" + href="https://judoor.fz-juelich.de">Register</a> + </div> + </div> + </div> + </div> + + <div class="col-12 col-lg-8 order-lg-0"> + <div id="carousel-background" class="d-flex align-items-center h-100"> + <div id="login-carousel" class="carousel slide d-flex justify-content-center w-100" data-bs-ride="carousel"> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#login-carousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#login-carousel" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#login-carousel" data-bs-slide-to="2" aria-label="Slide 3"></button> + <button type="button" data-bs-target="#login-carousel" data-bs-slide-to="3" aria-label="Slide 4"></button> + </div> + <div class="carousel-inner"> + {{ carousel_item("Jupyter", "https://jupyter.org", "Supercomputing in Your Browser", + "Jupyter-JSC is designed to provide the rich high performance computing (HPC) ecosystem + to the world's most popular software: web browsers. JupyterLab is a web-based interactive + development environment for Jupyter notebooks, code, and data. JupyterLab is flexible + to support a wide range of workflows in data science, scientific computing, and machine learning.", + "active") }} + + {{ carousel_item("Jupyter Notebooks", "https://jupyter-notebook.readthedocs.io/en/stable/notebook.html", + "Share your Workflows", "Jupyter-JSC allows you to create and share documents that contain + live code, equations, visualizations and explanatory text. Uses include: data cleaning and transformation, + numerical simulation, statistical modeling, machine learning and much more.") + }} + + {{ carousel_item("JupyterLab", "https://jupyterlab.readthedocs.io", "Next-Generation Notebook Interface", + "Jupyter-JSC gives access to JupyterLab, a web-based interactive development environment for Jupyter + notebooks, code, and data. JupyterLab is flexible: configure and arrange the user interface to support a + wide range of workflows in data science, scientific computing, and machine learning. JupyterLab is extensible + and modular: write plugins that add new components and integrate with existing ones.") + }} + + {{ carousel_item("JupyterHub", "https://jupyterhub.readthedocs.io", "Serving Jupyter Notebooks for Multiple + Users", "Jupyter-JSC is a JupyterHub to serve Jupyter notebooks for multiple users. It can be used in + classes of students, a corporate data science group or scientific research group. It is a multi-user hub + that spawns, manages, and proxies multiple instances of the single-user Jupyter notebook server.") }} + </div> + + <button class="carousel-control-prev" type="button" data-bs-target="#login-carousel" data-bs-slide="prev"> + <span class="carousel-control-prev-icon" aria-hidden="true"></span> + <span class="visually-hidden">Previous</span> + </button> + <button class="carousel-control-next" type="button" data-bs-target="#login-carousel" data-bs-slide="next"> + <span class="carousel-control-next-icon" aria-hidden="true"></span> + <span class="visually-hidden">Next</span> + </button> + </div> + </div> + </div> +</div> +{%- endblock -%} + +{%- block script -%} +<script src='{{static_url("js/login.js", include_version=False) }}'></script> + +<script> +$("nav [id$=nav-item]").removeClass("active"); +$("#start-nav-item, #collapse-start-nav-item").addClass("active"); + +$("#btn-login").click(function () { + var url = window.location.search; + window.location.href = "{{ base_url }}oauth_login" + url; +}); +</script> +{%- endblock -%}