mirror of
https://github.com/stellarshenson/stellars-jupyterhub-ds.git
synced 2026-03-08 06:00:29 +00:00
- Add ActivitySample SQLAlchemy model for database persistence - Add ActivityMonitor singleton with scoring, reset, lifecycle methods - Add JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER env var (default 60 min) - Update defaults: SAMPLE_INTERVAL=600s, RETENTION_DAYS=7 - Fix score calculation to use measured samples only (not theoretical max) - Add 3-state status: green (active), yellow (inactive), red (offline) - Add recently_active field in API response - Add Reset button with confirmation dialog - Fix green color (explicit #28a745 instead of text-success) - Add ThreadPoolExecutor for non-blocking Docker stats - Remove old background sampler code (on-demand sampling now) - Bump version to 3.7.0
247 lines
9.2 KiB
HTML
247 lines
9.2 KiB
HTML
{% macro modal(title, btn_label=None, btn_class="btn-primary") %}
|
|
{% set key = title.replace(' ', '-').lower() %}
|
|
{% set btn_label = btn_label or title %}
|
|
<div class="modal fade"
|
|
id="{{ key }}-dialog"
|
|
tabindex="-1"
|
|
role="dialog"
|
|
aria-labelledby="{{ key }}-label"
|
|
aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2 class="modal-title" id="{{ key }}-label">{{ title }}</h2>
|
|
<button type="button"
|
|
class="btn-close"
|
|
data-bs-dismiss="modal"
|
|
aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">{{ caller() }}</div>
|
|
<div class="modal-footer">
|
|
<button type="button"
|
|
class="btn {{ btn_class }}"
|
|
data-bs-dismiss="modal"
|
|
data-dismiss="modal">{{ btn_label }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endmacro %}
|
|
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>
|
|
{%- block title -%}
|
|
JupyterHub
|
|
{%- endblock title -%}
|
|
</title>
|
|
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
{% block stylesheet %}
|
|
<link rel="stylesheet"
|
|
href="{{ static_url('css/style.min.css') }}"
|
|
type="text/css" />
|
|
<link rel="stylesheet"
|
|
href="{{ static_url('css/custom.css') }}"
|
|
type="text/css" />
|
|
{% endblock stylesheet %}
|
|
{% block favicon %}
|
|
<link rel="icon" href="{{ static_url('favicon.ico') }}" type="image/x-icon">
|
|
{% endblock favicon %}
|
|
{% block scripts %}
|
|
<script src="{{static_url("components/bootstrap/dist/js/bootstrap.bundle.min.js") }}"
|
|
type="text/javascript"
|
|
charset="utf-8"></script>
|
|
<script src="{{static_url("components/requirejs/require.js") }}"
|
|
type="text/javascript"
|
|
charset="utf-8"></script>
|
|
<script src="{{static_url("components/jquery/dist/jquery.min.js") }}"
|
|
type="text/javascript"
|
|
charset="utf-8"></script>
|
|
<script src="{{static_url("js/darkmode.js") }}"
|
|
type="text/javascript"
|
|
charset="utf-8"></script>
|
|
{% endblock scripts %}
|
|
{# djlint js formatting doesn't handle template blocks in js #}
|
|
{# djlint: off #}
|
|
<script type="text/javascript">
|
|
require.config({
|
|
{% if version_hash %}
|
|
urlArgs: "v={{version_hash}}",
|
|
{% endif %}
|
|
baseUrl: '{{static_url("js", include_version=False)}}',
|
|
paths: {
|
|
components: '../components',
|
|
jquery: '../components/jquery/dist/jquery.min',
|
|
moment: "../components/moment/moment",
|
|
},
|
|
});
|
|
|
|
window.jhdata = {
|
|
base_url: "{{base_url}}",
|
|
prefix: "{{prefix}}",
|
|
{% if user %}
|
|
{#- Autoescaping in templates is turned on in JupyterHub, #}
|
|
{#- need `| safe` to prevent escaping #}
|
|
{#- `https://github.com/pallets/markupsafe/blob/2.1.4/src/markupsafe/_native.py#L6` #}
|
|
user: "{{ user.json_escaped_name | safe }}",
|
|
{% endif %}
|
|
{% if admin_access %}
|
|
admin_access: true,
|
|
{% else %}
|
|
admin_access: false,
|
|
{% endif %}
|
|
{% if not no_spawner_check and user and user.spawner.options_form %}
|
|
options_form: true,
|
|
{% else %}
|
|
options_form: false,
|
|
{% endif %}
|
|
xsrf_token: "{{ xsrf_token }}",
|
|
};
|
|
|
|
</script>
|
|
{# djlint: on #}
|
|
{% block meta %}
|
|
<meta name="description" content="JupyterHub">
|
|
<meta name="keywords" content="Jupyter, JupyterHub">
|
|
{% endblock meta %}
|
|
</head>
|
|
<body>
|
|
<noscript>
|
|
<div id='noscript'>
|
|
JupyterHub requires JavaScript.
|
|
<br>
|
|
Please enable it to proceed.
|
|
</div>
|
|
</noscript>
|
|
{% block nav_bar %}
|
|
<nav class="navbar navbar-expand-sm bg-body-tertiary mb-4">
|
|
<div class="container-fluid">
|
|
{% block logo %}
|
|
<span id="jupyterhub-logo" class="navbar-brand">
|
|
<a href="{{ logo_url or base_url }}">
|
|
<img src='{{ base_url }}logo'
|
|
alt='JupyterHub logo'
|
|
class='jpy-logo'
|
|
title='Home' />
|
|
</a>
|
|
</span>
|
|
{% endblock logo %}
|
|
{% if user %}
|
|
<button class="navbar-toggler"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#thenavbar"
|
|
aria-controls="thenavbar"
|
|
aria-expanded="false"
|
|
aria-label="Toggle navigation">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
{% endif %}
|
|
<div class="collapse navbar-collapse" id="thenavbar">
|
|
<ul class="navbar-nav me-auto mb-0">
|
|
{% if user %}
|
|
{% block nav_bar_left_items %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}home">Home</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}token">Token</a>
|
|
</li>
|
|
{% if 'admin-ui' in parsed_scopes %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}admin">Admin</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}authorize">Authorize Users</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}activity">Activity</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}notifications">Notifications</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}settings">Settings</a>
|
|
</li>
|
|
{% endif %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ base_url }}change-password">Change Password</a>
|
|
</li>
|
|
{% if services %}
|
|
<li class="nav-item dropdown">
|
|
<a href="#"
|
|
class="nav-link dropdown-toggle"
|
|
data-bs-toggle="dropdown"
|
|
role="button"
|
|
aria-expanded="false">Services</a>
|
|
<ul class="dropdown-menu">
|
|
{% for service in services %}
|
|
{% block service scoped %}
|
|
<li>
|
|
<a class="dropdown-item" href="{{ service.href }}">{{ service.name }}</a>
|
|
</li>
|
|
{% endblock service %}
|
|
{% endfor %}
|
|
</ul>
|
|
</li>
|
|
{% endif %}
|
|
{% endblock nav_bar_left_items %}
|
|
{% endif %}
|
|
</ul>
|
|
<ul class="nav navbar-nav me-2">
|
|
{% block nav_bar_right_items %}
|
|
<li class="nav-item">
|
|
{% block theme_toggle %}
|
|
<button class="btn btn-sm"
|
|
id="dark-theme-toggle"
|
|
aria-label="Toggle dark mode"
|
|
title="Toggle dark mode">
|
|
<i aria-hidden="true" class="fa fa-circle-half-stroke"></i>
|
|
</button>
|
|
{% endblock theme_toggle %}
|
|
</li>
|
|
<li class="nav-item">
|
|
{% block login_widget %}
|
|
<span id="login_widget">
|
|
{% if user %}
|
|
<span class="me-1">{{ user.name }}</span>
|
|
<a id="logout"
|
|
role="button"
|
|
class="btn btn-sm btn-outline-contrast"
|
|
href="{{ logout_url }}"> <i aria-hidden="true" class="fa fa-sign-out"></i>Logout</a>
|
|
{% else %}
|
|
<a id="login"
|
|
role="button"
|
|
class="btn btn-sm btn-outline-contrast"
|
|
href="{{ login_url }}">Login</a>
|
|
{% endif %}
|
|
</span>
|
|
{% endblock login_widget %}
|
|
</li>
|
|
{% endblock nav_bar_right_items %}
|
|
</ul>
|
|
</div>
|
|
{% block header %}
|
|
{% endblock header %}
|
|
</div>
|
|
</nav>
|
|
{% endblock nav_bar %}
|
|
{% block announcement %}
|
|
{% if announcement %}
|
|
<div class="container text-center announcement alert alert-warning">{{ announcement | safe }}</div>
|
|
{% endif %}
|
|
{% endblock announcement %}
|
|
{% block main %}
|
|
{% endblock main %}
|
|
{% block footer %}
|
|
{% endblock footer %}
|
|
{% call modal('Error', btn_label='OK') %}
|
|
<div class="ajax-error alert-danger">The error</div>
|
|
{% endcall %}
|
|
{% block script %}
|
|
{% endblock script %}
|
|
</body>
|
|
</html>
|