Skip to content

feat(web): public custom page API - #66

Merged
thiagoesteves merged 3 commits into
mainfrom
thiagoesteves/public-page-api
Jul 17, 2026
Merged

feat(web): public custom page API#66
thiagoesteves merged 3 commits into
mainfrom
thiagoesteves/public-page-api

Conversation

@thiagoesteves

Copy link
Copy Markdown
Owner

What

Turns ObserverWeb into a platform: host applications can now add their own pages to the dashboard, following the same playbook that grew LiveDashboard's custom-page ecosystem.

  • Observer.Web.Page is now a documented public behaviour. use Observer.Web.Page pulls in Phoenix.LiveComponent plus overridable no-op defaults for every callback, so a minimal page is just render/1.
  • New pages: option on observer_dashboard/2: observer_dashboard "/observer", pages: [queue: MyApp.ObserverQueuePage] serves the page at /observer/queue and adds QUEUE to the nav (generic icon fallback for custom pages).
  • Page names that clash with built-in pillars are rejected with a compile-time ArgumentError; invalid shapes too.
  • Custom pages receive the standard dashboard assigns (@access, @user, @params, @theme), so they can honor read-only access like the built-ins.

Why

Part of the roadmap derived from comparing ObserverWeb against OTP observer, observer_cli and Phoenix LiveDashboard: a public page API lets the community fill niches (Ecto stats, Broadway, queues) without growing the core.

Risk assessment

  • Impact: additive; without :pages everything behaves exactly as before (defaults to [], nil-safe session read for live upgrades).
  • Blast radius: router option plumbing, IndexLive page resolution, nav component. Built-in resolution clauses are untouched and take precedence over custom names.
  • Regression risk: low - suite green (401 tests, 96.0% coverage), credo/sobelow/dialyzer/format clean; the test router now mounts a real custom page exercising the full flow.
  • Rollback plan: revert the commit; hosts using :pages drop the option.

Checklist

  • mix test green (401 tests)
  • mix coveralls 96.0% (threshold 95%)
  • mix credo --strict, mix sobelow, mix dialyzer, mix format --check-formatted clean
  • Small focused diff, no leftover debug output

🤖 Generated with Claude Code

Promote Observer.Web.Page from an internal contract to a documented
public behaviour, following LiveDashboard's PageBuilder playbook:

- `use Observer.Web.Page` pulls in Phoenix.LiveComponent and provides
  overridable defaults for every callback, so a minimal page only
  needs render/1.
- New `pages:` router option registers custom pages by route name,
  e.g. observer_dashboard "/observer", pages: [queue: MyPage]. Names
  clashing with built-in pillars are rejected at compile time.
- Custom pages are threaded through the session into page resolution
  and appended to the navigation bar with a generic icon fallback.

Risk assessment:
- Impact: additive API; dashboards without the :pages option behave
  exactly as before (option defaults to []).
- Blast radius: router option plumbing, IndexLive page resolution, nav
  component; built-in page resolution clauses are untouched and take
  precedence over custom names.
- Regression risk: low - session shape gains one key with a nil-safe
  read; suite green (401 tests, 96.0% coverage).
- Rollback plan: revert the commit; hosts using :pages would need to
  drop the option (compile error otherwise), no data involved.
@thiagoesteves
thiagoesteves force-pushed the thiagoesteves/public-page-api branch from f277a70 to 9e9206c Compare July 17, 2026 14:19
@thiagoesteves thiagoesteves self-assigned this Jul 17, 2026
…illar

The custom-pages validation predates the Logs pillar, so after rebasing
onto main a host could register pages: [logs: MyPage] and have it pass
validation while being silently shadowed by the built-in Logs page.
Add logs to @reserved_page_names with a matching validation test.

Risk assessment:
- Impact: registering a custom page named :logs now raises at compile
  time instead of being silently unreachable.
- Blast radius: one module attribute plus a test.
- Regression risk: low - suite green (420 tests, 95.9% coverage).
- Rollback plan: revert the commit.
@thiagoesteves

Copy link
Copy Markdown
Owner Author

Post-rebase integration check: everything from the Logs pillar carried through (page resolution, nav, icons, tests), with one gap - @reserved_page_names predates the Logs pillar, so pages: [logs: MyPage] would validate and then be silently shadowed by the built-in page. logs is now reserved with a matching validation test.

Add WebDev.DemoPage to dev.exs and register it through the new :pages
router option, so the public page API can be exercised locally end to
end: DEMO nav entry, the standard dashboard assigns (node, access,
theme) and a counter button proving the handle_parent_event flow. It
also doubles as a copy-pasteable example of a minimal page.

Risk assessment:
- Impact: dev.exs only; the published library is untouched.
- Blast radius: standalone dev server.
- Regression risk: low - verified by booting the dev server and
  fetching /observer/demo (nav entry, content and counter render).
- Rollback plan: revert the commit.
@thiagoesteves

Copy link
Copy Markdown
Owner Author

Added WebDev.DemoPage to dev.exs, registered via pages: [demo: WebDev.DemoPage], so the page API can be tested locally: a DEMO nav entry, chips showing the standard dashboard assigns (node/access/theme) and a counter button exercising handle_parent_event. Doubles as a minimal copy-pasteable example.

@thiagoesteves
thiagoesteves merged commit 817abbb into main Jul 17, 2026
3 checks passed
@thiagoesteves
thiagoesteves deleted the thiagoesteves/public-page-api branch July 17, 2026 14:38
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