Add themed widgets, calendar, and Open WebUI chat to the dashboard

- Apply GTK-like color scheme (dark greys, #f76b2f accent) across
  cards, buttons, glows and category colors
- Service cards use the official logo icons; Netbird card shows live
  reachability + latency instead of a separate top widget
- Top widgets: Today (calendar events with in-progress highlighting),
  Git activity (3 rows visible, scrollable), GPU with live ROCm stats
  and loaded Ollama models incl. GPU/CPU split
- Open WebUI card: inline prompt line with model selection
- Calendar section grouping events by day below the services
- data.json fetch with boot retry; GPU/Ollama poll every 5 s
- Today entries wrap long titles; README documents widgets,
  environment variables and the .env secrets pattern
This commit is contained in:
2026-09-04 14:07:22 +02:00
parent 55e871bd4f
commit e766fcd95c
4 changed files with 1158 additions and 46 deletions
+48 -3
View File
@@ -1,8 +1,9 @@
# Homelab Dashboard
A small, self-contained single-page dashboard that links all your homelab services.
Static site (HTML + CSS + JS), served by a lightweight **nginx** image. No backend, no
database, no build step — just static files.
Static site (HTML + CSS + JS), served by a lightweight **nginx** image. The optional
calendar widget needs the container backend to refresh Google/ICS feeds, but the
rest of the dashboard is pure static files.
## Services
@@ -13,10 +14,18 @@ External: gitlab-ixsol, gem360.
## Features
- Top widgets: **Today** (calendar events for today, with in-progress highlighting),
**Netbird** status (reachability + latency), **Git activity** (recent commits from
Gitea and GitLab — 3 rows visible, scroll for more), **GPU + Ollama** (live AMD
ROCm stats: utilization, VRAM, temperature, power; plus loaded Ollama models
with their GPU/CPU split)
- Inline **Open WebUI prompt line with model selection** in the Open WebUI card
(requires `OPENWEBUI_TOKEN`)
- Responsive grid of service cards with icons, categories and a live "Online" indicator
- **Open** (new tab) + **Copy URL** per service
- Live search / filter across names, categories and URLs
- Live local clock
- Calendar section aggregating multiple ICS feeds (refreshed every 15 min in the container)
- Dark, themeable design; respects `prefers-reduced-motion`
## Run with Docker
@@ -27,9 +36,43 @@ docker compose up -d --build
Then open <http://localhost:8888>.
The dashboard is static, but the widgets are populated by a small Node.js updater
(`api/update-data.js`) that runs inside the container and aggregates ICS feeds,
Netbird status, git activity and Open WebUI models every 15 minutes. A second
Node process (`api/server.js`) proxies chat prompts to Open WebUI.
### Environment variables
Secrets (API keys) live in **`.env`** (gitignored) — docker compose reads it
automatically. Non-secret settings go directly in `docker-compose.yml`:
| Variable | Purpose |
| --- | --- |
| `TZ` | Timezone used for the "Today" widget (e.g. `Europe/Vienna`) |
| `OPENWEBUI_TOKEN` | Open WebUI API key — enables the prompt line + model list (**set in `.env`**) |
| `GITEA_TOKEN` | Gitea API token — private repo stats (public repos work without it) |
| `GITLAB_TOKEN` | GitLab API token — private project stats (public projects work without it) |
| `GITEA_URL` / `GITLAB_URL` / `NETBIRD_URL` / `OPENWEBUI_URL` | Override the default service URLs |
| `GPU_STATS_URL` | GPU stats upstream (default: the `gpu-stats` compose service) |
| `OLLAMA_URL` | Ollama instance for loaded-model stats (default: `http://100.103.83.12:11435`) |
### GPU stats service
The `gpu-stats` compose service runs [`gpu_stats.py`](./gpu_stats.py), a tiny HTTP
server that queries `rocm-smi`. It needs the host's ROCm install and GPU device
nodes, so the compose file mounts `/opt/rocm` and passes `/dev/kfd` + `/dev/dri`.
Set `GPU_NAME` in `docker-compose.yml` to your card's name (rocm-smi can't read it
inside the container without `libdrm_amdgpu`). The widget polls it every 5 s
through `/api/gpu-stats`.
To run it on the host instead: `python3 gpu_stats.py`, set
`GPU_STATS_URL=http://host.docker.internal:9101/stats` on the dashboard service
and add `extra_hosts: ["host.docker.internal:host-gateway"]`.
### Without Docker (quick dev)
Any static file server works:
Any static file server works for the dashboard itself, but the widgets will
show errors because the data fetcher and chat proxy run server-side:
```bash
# from this directory
@@ -61,4 +104,6 @@ docker run -d --name homelab-dashboard -p 8888:80 --restart unless-stopped homel
- The "Online" badge is cosmetic (a static site can't probe your services from the browser
due to CORS). If you want real health checks later, a tiny backend that pings each URL
would be the next step.
- Calendar dependencies are bundled in `api/node_modules` so the Docker build works
offline. To update them, run `npm install` in the `api/` directory.
- Port 8888 is published by the Compose file; change it there if needed.