Skip to content

Feat: Live widget updates via SSE without full page reload - #1041

Open
Billypl wants to merge 13 commits into
glanceapp:devfrom
Billypl:feature/live-updates
Open

Feat: Live widget updates via SSE without full page reload#1041
Billypl wants to merge 13 commits into
glanceapp:devfrom
Billypl:feature/live-updates

Conversation

@Billypl

@Billypl Billypl commented Jul 22, 2026

Copy link
Copy Markdown
  1. A background ticker (per application instance) runs every 10 s and checks each widget's requiresUpdate - so widgets are never fetched more often than the widget's outerHTML in place. Events for the same widget within 500 ms are coalesced into a single fetch.

Enabling

server:
  live-updates: true

Default is false. With it off, no new goroutines start and the new endpoints are not registered - behaviour is identical to before.

Changes

  • Bug fix (prerequisite): widgets nested inside group / split-column containers were not added to the widget-by-ID map, making them unreachable by ID.
    Fixed with a recursive registration helper. Covered by a test.
  • internal/glance/events.go - in-memory event hub (field on application, not a global; closed on hot-reload)
  • internal/glance/ticker.go - background refresh loop with change detection
  • internal/glance/glance.go - two new endpoints (/api/events, /api/widgets/{id}/content/); hub/ticker wired into hot-reload cleanup
  • internal/glance/templates/widget-base.html - data-widget-id attribute added to every widget wrapper
  • internal/glance/static/js/page.js - EventSource client, 500 ms coalescing, scoped DOM re-init after widget swap
  • docs/configuration.md - server.live-updates documented including reverse proxy notes

Notes

  • Relative timestamps in rendered HTML (e.g. "3m ago") will trigger a spurious change event after each re-render because the text changes every minute regardless of the underlying data. This is a known limitation; comparing pre-render state instead of rendered HTML would require per-widget instrumentation.
  • Auth is enforced as the first statement in both new handlers (before any ID parsing or lookup), preventing widget ID enumeration.
  • The ticker and hub live on application and are cancelled/closed in server.stop(), so hot-reload does not leak goroutines.

@Billypl

Billypl commented Jul 22, 2026

Copy link
Copy Markdown
Author

references #1042

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant