Expand homepage widgets and info panels (#81)

## Summary
- Add greeting and datetime info widgets to homepage header
- Add Miniflux widget showing unread/read counts (via existing API key in 1Password)
- Add Grafana widget showing dashboards/datasources/alerts (via existing credentials in 1Password)
- Add ArgoCD to bookmarks section
- Add TODO comments for widgets needing additional setup (Forgejo, Caddy, UniFi, Glances, Navidrome, Transmission, Immich)

## Deployment and Testing
- [ ] Sync homepage app to deploy new ExternalSecrets
- [ ] Verify greeting and datetime appear in header
- [ ] Verify Miniflux widget shows unread/read counts
- [ ] Verify Grafana widget shows dashboard stats
- [ ] Check that services without credentials still display (just without widgets)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/81
This commit is contained in:
Erich Blume 2026-02-02 16:11:20 -08:00
commit 4d97ac4c26
10 changed files with 191 additions and 2 deletions

View file

@ -16,6 +16,10 @@ metadata:
gethomepage.dev/description: "Metrics dashboards"
gethomepage.dev/href: "https://grafana.ops.eblu.me"
gethomepage.dev/pod-selector: "app.kubernetes.io/name=grafana"
gethomepage.dev/widget.type: "grafana"
gethomepage.dev/widget.url: "https://grafana.ops.eblu.me"
gethomepage.dev/widget.username: "{{HOMEPAGE_VAR_GRAFANA_USERNAME}}"
gethomepage.dev/widget.password: "{{HOMEPAGE_VAR_GRAFANA_PASSWORD}}"
spec:
ingressClassName: tailscale
defaultBackend:

View file

@ -0,0 +1,20 @@
# ExternalSecret for Forgejo API key
# Used by Homepage Forgejo widget (via Gitea widget type)
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: homepage-forgejo
namespace: homepage
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: homepage-forgejo
creationPolicy: Owner
data:
- secretKey: apikey
remoteRef:
key: Forgejo Secrets
property: eblume-homepage-access-token

View file

@ -0,0 +1,24 @@
# ExternalSecret for Grafana credentials
# Used by Homepage Grafana widget
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: homepage-grafana
namespace: homepage
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: homepage-grafana
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: Grafana (blumeops)
property: username
- secretKey: password
remoteRef:
key: Grafana (blumeops)
property: password

View file

@ -0,0 +1,20 @@
# ExternalSecret for Miniflux API key
# Used by Homepage Miniflux widget
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: homepage-miniflux
namespace: homepage
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: homepage-miniflux
creationPolicy: Owner
data:
- secretKey: apikey
remoteRef:
key: miniflux
property: eblume-api-key

View file

@ -0,0 +1,28 @@
# ExternalSecret for Navidrome Subsonic API credentials
# Used by Homepage Navidrome widget
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: homepage-navidrome
namespace: homepage
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: homepage-navidrome
creationPolicy: Owner
data:
- secretKey: user
remoteRef:
key: dj (navidrome)
property: username
- secretKey: salt
remoteRef:
key: dj (navidrome)
property: salt
- secretKey: token
remoteRef:
key: dj (navidrome)
property: salted_pw

View file

@ -27,16 +27,57 @@ ingress:
env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: "go.tail8d86e.ts.net,go.ops.eblu.me"
# Weather widget
- name: HOMEPAGE_VAR_OPENWEATHERMAP_API_KEY
valueFrom:
secretKeyRef:
name: homepage-openweathermap
key: apikey
# Jellyfin widget
- name: HOMEPAGE_VAR_JELLYFIN_API_KEY
valueFrom:
secretKeyRef:
name: homepage-jellyfin
key: apikey
# Miniflux widget
- name: HOMEPAGE_VAR_MINIFLUX_API_KEY
valueFrom:
secretKeyRef:
name: homepage-miniflux
key: apikey
# Grafana widget
- name: HOMEPAGE_VAR_GRAFANA_USERNAME
valueFrom:
secretKeyRef:
name: homepage-grafana
key: username
- name: HOMEPAGE_VAR_GRAFANA_PASSWORD
valueFrom:
secretKeyRef:
name: homepage-grafana
key: password
# Forgejo widget
- name: HOMEPAGE_VAR_FORGEJO_API_KEY
valueFrom:
secretKeyRef:
name: homepage-forgejo
key: apikey
# Navidrome widget
- name: HOMEPAGE_VAR_NAVIDROME_USER
valueFrom:
secretKeyRef:
name: homepage-navidrome
key: user
- name: HOMEPAGE_VAR_NAVIDROME_SALT
valueFrom:
secretKeyRef:
name: homepage-navidrome
key: salt
- name: HOMEPAGE_VAR_NAVIDROME_TOKEN
valueFrom:
secretKeyRef:
name: homepage-navidrome
key: token
config:
# Host services (non-k8s, on indri or LAN)
@ -46,6 +87,10 @@ config:
href: https://forge.ops.eblu.me
icon: forgejo
description: Git forge
widget:
type: gitea
url: https://forge.ops.eblu.me
key: "{{HOMEPAGE_VAR_FORGEJO_API_KEY}}"
- Registry:
href: https://registry.ops.eblu.me
icon: docker
@ -92,6 +137,14 @@ config:
key: "{{HOMEPAGE_VAR_JELLYFIN_API_KEY}}"
enableBlocks: true
enableNowPlaying: true
# TODO: Add Caddy widget when admin API is enabled (currently admin off)
# - Caddy:
# href: https://indri.tail8d86e.ts.net
# icon: caddy
# description: Reverse proxy
# widget:
# type: caddy
# url: http://indri.tail8d86e.ts.net:2019
# External bookmarks
bookmarks:
@ -105,10 +158,21 @@ config:
- Pulumi:
- href: https://app.pulumi.com/eblume/blumeops-tailnet
icon: pulumi
- ArgoCD:
- href: https://argocd.ops.eblu.me
icon: argocd
# Widgets on the page
# Note: Kubernetes widget disabled - requires metrics-server
# Widgets on the page (info bar at top)
widgets:
- greeting:
text_size: xl
text: Welcome to Blue Mops
- datetime:
text_size: lg
format:
dateStyle: long
timeStyle: short
hour12: true
- openweathermap:
label: Camano
latitude: 48.18235
@ -117,6 +181,15 @@ config:
provider: openweathermap
apiKey: "{{HOMEPAGE_VAR_OPENWEATHERMAP_API_KEY}}"
cache: 15
# TODO: Add UniFi widget when controller is set up
# - unifi_console:
# url: https://192.168.1.1
# username: homepage
# password: "{{HOMEPAGE_VAR_UNIFI_PASSWORD}}"
# TODO: Add Glances widget when Glances is deployed
# - glances:
# url: http://indri.tail8d86e.ts.net:61208
# metric: cpu
# Kubernetes autodiscovery
kubernetes:

View file

@ -15,6 +15,12 @@ metadata:
gethomepage.dev/description: "Photo management"
gethomepage.dev/href: "https://photos.ops.eblu.me"
gethomepage.dev/pod-selector: "app.kubernetes.io/name=server"
# TODO: Add Immich widget - requires API key from Account Settings > API Keys
# See: https://gethomepage.dev/widgets/services/immich/
# gethomepage.dev/widget.type: "immich"
# gethomepage.dev/widget.url: "https://photos.ops.eblu.me"
# gethomepage.dev/widget.key: "{{HOMEPAGE_VAR_IMMICH_API_KEY}}"
# gethomepage.dev/widget.version: "2"
spec:
ingressClassName: tailscale
rules:

View file

@ -12,6 +12,9 @@ metadata:
gethomepage.dev/description: "RSS reader"
gethomepage.dev/href: "https://feed.ops.eblu.me"
gethomepage.dev/pod-selector: "app=miniflux"
gethomepage.dev/widget.type: "miniflux"
gethomepage.dev/widget.url: "https://feed.ops.eblu.me"
gethomepage.dev/widget.key: "{{HOMEPAGE_VAR_MINIFLUX_API_KEY}}"
spec:
ingressClassName: tailscale
defaultBackend:

View file

@ -13,6 +13,11 @@ metadata:
gethomepage.dev/description: "Music streaming server"
gethomepage.dev/href: "https://dj.ops.eblu.me"
gethomepage.dev/pod-selector: "app=navidrome"
gethomepage.dev/widget.type: "navidrome"
gethomepage.dev/widget.url: "https://dj.ops.eblu.me"
gethomepage.dev/widget.user: "{{HOMEPAGE_VAR_NAVIDROME_USER}}"
gethomepage.dev/widget.token: "{{HOMEPAGE_VAR_NAVIDROME_TOKEN}}"
gethomepage.dev/widget.salt: "{{HOMEPAGE_VAR_NAVIDROME_SALT}}"
spec:
ingressClassName: tailscale
defaultBackend:

View file

@ -13,6 +13,12 @@ metadata:
gethomepage.dev/description: "Torrent client"
gethomepage.dev/href: "https://torrent.ops.eblu.me"
gethomepage.dev/pod-selector: "app=transmission"
# TODO: Add Transmission widget - requires username/password setup in Transmission
# See: https://gethomepage.dev/widgets/services/transmission/
# gethomepage.dev/widget.type: "transmission"
# gethomepage.dev/widget.url: "https://torrent.ops.eblu.me"
# gethomepage.dev/widget.username: "{{HOMEPAGE_VAR_TRANSMISSION_USER}}"
# gethomepage.dev/widget.password: "{{HOMEPAGE_VAR_TRANSMISSION_PASSWORD}}"
spec:
ingressClassName: tailscale
defaultBackend: