- "Measured X ago" now updates every second (shows 5s ago, 3min ago, etc.)
- Last Active column left-aligned and shows rounded times (5min, 2h, 3d)
- Removed redundant minutes/hours from time display
- ActivityMonitor now uses /data/activity_samples.sqlite instead of
JupyterHub's main database to avoid SQLite locking conflicts
- Fixes "database is locked" errors that prevented login when both
JupyterHub and ActivityMonitor wrote simultaneously
- Added "Last Active" column to activity table showing relative time
- Redesign activity bar as thin continuous bar (80x8px) with subtle dividers
- Fix inconsistent timestamp text ("Last updated" vs "Measured")
- Fix sample cleanup to always run on record_sample(), not just on inserts
- Ensures samples older than RETENTION_DAYS are properly pruned
- 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
- user.last_activity updates on Hub page access (causes timer reset on refresh)
- server.last_activity only updates on actual JupyterLab activity
- Matches what jupyterhub-idle-culler uses for culling decisions
- Truncate requested hours to max available instead of returning error
- Add 'truncated' flag in API response with detailed message
- UI shows warning alert (yellow) when truncated, success (green) otherwise
- Warning displays 4 seconds vs 2 seconds for normal success
- Fixed extend button re-enable after successful extension
Session Extension Feature:
- Add JUPYTERHUB_IDLE_CULLER_MAX_EXTENSION env var (default 24h)
- Add SessionInfoHandler and ExtendSessionHandler API endpoints
- Add Session Status card to home page with countdown timer
- Extension tracking in spawner state (resets on server restart)
- Color-coded warnings (yellow <1h, red <30min)
Environment Settings Harmonization:
- Add all ENV defaults to Dockerfile
- Add idle culler settings to compose.yml
- Standardize logo as JUPYTERHUB_LOGO_URI with file:// prefix
- Update NVIDIA_IMAGE to nvidia/cuda:13.0.2-base-ubuntu24.04
- Add optional CIFS mount support via compose_cifs.yml and .env
- Create install_cert.sh for Linux (multi-distro support)
- Enhance install_cert.bat with folder argument and help flags
- Fix compose_override.yml stray quote, add idle culler defaults
- Enhance generate-certs.sh with generic CN and verification
- Update start.sh/stop.sh to support ENABLE_CIFS from .env
- Update README with CIFS and certificate installation docs
HomeHandler doesn't pass server_version to templates (only AdminHandler does).
Added jupyterhub.__version__ to c.JupyterHub.template_vars for global access.
- Move settings_dictionary.yml to services/jupyterhub/conf/
- Replace hardcoded word list with xkcdpass library
- Add JUPYTERHUB_AUTOGENERATED_PASSWORD_WORDS (default: 4)
- Add JUPYTERHUB_AUTOGENERATED_PASSWORD_DELIMITER (default: "-")
- Fix ENABLE_SIGNUP to JUPYTERHUB_SIGNUP_ENABLED in Dockerfile
- Add config/settings_dictionary.yml with category-based structure
- Categories as top-level keys (JupyterHub Core, Docker Spawner, etc.)
- Each setting has name, description, default, optional empty_display
- Update SettingsPageHandler to load from YAML file
- Add pyyaml to Dockerfile pip dependencies
- Refactor pip install to heredoc format with echo message
Add ability to send notifications to selected servers instead of all.
- New ActiveServersHandler at GET /api/notifications/active-servers
- BroadcastNotificationHandler accepts optional recipients array
- UI with "Send to all" checkbox and server selection list
- Select All/Deselect All buttons, dynamic button text
- Backward compatible - sends to all if recipients not specified