Files
stellars-jupyterhub-ds/doc/ui-template-customization.md
stellarshenson 12953ee4d6 feat: add optional volume descriptions for UI
Added VOLUME_DESCRIPTIONS config dict allowing optional user-friendly
descriptions for volumes shown in management UI.

Changes:
- Added VOLUME_DESCRIPTIONS dict in jupyterhub_config.py (optional, co-defined
  with DOCKER_SPAWNER_VOLUMES)
- Exposed volume_descriptions via c.JupyterHub.template_vars
- Updated home.html to conditionally display descriptions if defined
- If volume not in VOLUME_DESCRIPTIONS, no description shown (UI remains agnostic)

Configuration example:
VOLUME_DESCRIPTIONS = {
    'home': 'User home directory files, configurations',
    'workspace': 'Project files, notebooks, code',
    'cache': 'Temporary files, pip cache, conda cache'
}

Documentation:
- Updated .claude/CLAUDE.md with Manage Volumes implementation details
- Simplified Restart Server section for consistency
- Added template variables to doc/ui-template-customization.md

UI now shows volume name, Docker volume path, and optional description
(if configured). Fully backward compatible - descriptions are optional.
2025-11-09 22:50:13 +01:00

1.9 KiB

UI Template Customization

JupyterHub templates extended using Jinja2 to add custom UI features (server restart, volume management, notifications). Templates placed in services/jupyterhub/templates/ and copied to /srv/jupyterhub/templates/ during Docker build.

Key Technical Facts:

  • Templates extend base using {% extends "page.html" %}
  • Override blocks: {% block main %}, {% block script %}
  • Changes require Docker rebuild with --no-cache flag
  • JupyterHub 5.4.2 uses Bootstrap 5 (not Bootstrap 4)

Template Variables (via c.JupyterHub.template_vars):

  • user_volume_suffixes: List of volume suffixes from DOCKER_SPAWNER_VOLUMES
  • volume_descriptions: Optional dict mapping suffixes to descriptions

JavaScript Integration: All custom JavaScript wrapped in RequireJS to ensure library loading:

require(["jquery"], function($) {
  "use strict";
  // Custom code here
});

Bootstrap 5 Modal Syntax:

<button data-bs-toggle="modal" data-bs-target="#myModal">
  <i class="fa fa-rotate" aria-hidden="true"></i> Restart
</button>

CSRF Protection: All POST requests include XSRF token via X-XSRFToken header:

headers: { 'X-XSRFToken': getCookie('_xsrf') }

Custom Handlers (registered in jupyterhub_config.py):

c.JupyterHub.extra_handlers = [
    (r'/api/users/([^/]+)/manage-volumes', ManageVolumesHandler),
    (r'/api/users/([^/]+)/restart-server', RestartServerHandler),
    (r'/api/notifications/broadcast', BroadcastNotificationHandler),
    (r'/notifications', NotificationsPageHandler),
]

Font Awesome Icons:

  • Restart: fa fa-rotate
  • Volumes: fa fa-database
  • Stop: fa fa-stop
  • Start: fa fa-play

Build Process:

docker compose build --no-cache jupyterhub
docker stop stellars-jupyterhub-ds-jupyterhub && docker rm stellars-jupyterhub-ds-jupyterhub
docker compose up -d jupyterhub