Skip to content

feat: Simple Dashboard - #205

Merged
thushan merged 178 commits into
mainfrom
feature/simple-dashboard
Aug 4, 2026
Merged

feat: Simple Dashboard#205
thushan merged 178 commits into
mainfrom
feature/simple-dashboard

Conversation

@thushan

@thushan thushan commented Aug 4, 2026

Copy link
Copy Markdown
Owner

What started out as a 'simple front-end' for Olla has become a good exercise in making the backend more robust and APIs a bit more well rounded.

The UI is accesible at /internal/ui and is written in Svelte 5 + TailwindCSS built embedded into the binary. This does mean that go install breaks (and the UI shows an error status).

This is still experimental and would need a few iterations to make it work well across the board.

Config

New configuration to enable it (by default it is):

dashboard:
  enabled: true
  access_policy:
    allowed_cidrs:
      - "127.0.0.0/8"
      - "::1/128"
    allowed_hosts:
      - "localhost"

UI

Gives you an overview of:

  • Dashboard of important telemetry and metrics
  • Endpoints configured
  • Models available and known about
image image image image image

Changes

implements a lightweight, read-only dashboard for monitoring Olla at /internal/ui/.

  • Shows health, endpoints, models, traffic and process metrics
  • Adds live sparklines with outage and recovery indicators
  • Applies the dashboard access policy to its supporting API routes
  • Sanitises sensitive endpoint information
  • Adds dashboard configuration, documentation and release notes
  • Includes responsive and accessible desktop/mobile layouts

thushan added 30 commits July 30, 2026 11:35
TestWireShape_EndpointsStatusResponse and TestWireShape_ModelsStatusResponse
only pinned a subset of their structs' pre-existing fields, so a rename of
last_model_sync, health_check, response_time, issues, type, family, size,
params, quant or capabilities would pass silently. Seeded the fixture so the
omitempty fields actually appear (non-zero ConsecutiveFailures, model Size,
ModelDetails.Type) and pinned them. Also added the missing "url" pin to
TestWireShape_StatusResponse, which had the same gap.
kind="breaker" and its CB status map were leftovers from the abandoned
branch's circuit-breaker column, which never shipped in this branch. No
caller passes kind, so the whole prop and its map were dead weight.
FR-4's per-endpoint model list, the per_endpoint tooltip data, and the
breaker-not-wired-to-proxy-failures gap were all flagged in the spec as
things to record here, but none had made it into the findings file.
README.md and verification.md still pointed at docs/spec/admin-dashboard.md,
which doesn't exist in this repo, and cited WP numbers from the old spec that
don't line up with this one. Pointed both at simple-dashboard.md and its
actual section/work-package numbering, and corrected the If-None-Match note
to describe the dormant conditional-GET machinery accurately instead of
implying WP-2 wires it up.
build-web previously ran vite build then rm/cp/touch to move the output
into internal/app/handlers/dashboard/dist, which only works with GNU
coreutils. Vite now writes straight into that directory (emptyOutDir),
and a writeBundle plugin restores the .gitkeep sentinel the empty
wipes. Confirmed empirically that no .vite cache directory ever
appeared in outDir, so the old rm -rf .../.vite line was vestigial and
is dropped rather than ported.
Vite writes straight into the embed source now, so WEB_DIR/dist is
never created and cleaning it was a no-op. Git Bash coreutils stay as
they were - the maintainer runs make under Git Bash on Windows, so
rm/touch here are a supported prerequisite, not a defect.
Endpoint names differing only in punctuation (node.a / node-a) both
slugged to the same CSS-safe id, so the keyed each used a lossy,
non-unique value as the row identity. Svelte throws each_key_duplicate
in that case, and with no error boundary in the app the whole table
body rendered zero rows instead of just the colliding ones.

Key on the endpoint's exact name now; the slug is kept only for
generating DOM ids. Decoupled the same way in ModelsPanel for
consistency, since its flat fallback table has the identical shape.
OverviewPanel looked up the row by DOM id, but the generic row path
in SortableTable never set an id on its <tr>, so the lookup always
missed. The panel swap also unmounts OverviewPanel entirely, so the
clicked button was gone by the time (or even if) the lookup had
worked, leaving keyboard focus stranded on <body>.

SortableTable now accepts an optional rowDomId to set the id (and a
tabindex so it can receive focus) on jump-target rows. OverviewPanel
awaits a tick for the panel swap to land before scrolling to the row
and focusing it.
.goreleaser.yml's before.hooks run make build-web, which needs Node,
but release.yml never installed it - ci.yml gained setup-node steps
for the same reason and this workflow was simply missed. Today a tag
release only works because ubuntu-latest happens to ship Node.
Records two things discovered while fixing the build-pipeline defects,
neither introduced by this branch: main's pre-existing parse-time
awk/sed/date calls in the makefile (acknowledged, not planned - Git
Bash is a supported prerequisite), and the documented goreleaser
Docker verification command lacking Node, Go and make alike.

Also adds .github/workflows/release.yml to the mechanical scope gate's
allowlist - it was an oversight that ci.yml was allowlisted but its
release-pipeline equivalent wasn't, and this fix legitimately touches
it for the same reason ci.yml needed setup-node.
groups and flatRecent both derive to empty arrays on a first-load
failure (data stays null), so the panel fell through to "No models
discovered yet" right alongside the error banner - reading as "the
backends have no models" rather than "the request failed". Gate the
empty-state copy on the store's hasData getter instead.
…rkaround

Git Bash coreutils are a supported prerequisite per the maintainer, so
the earlier wording overstated why the copy step went away. It's gone
because writing straight into the embed source is fewer moving parts,
same reasoning already applied to install-web/test-web/lint-web.
thushan added 22 commits August 4, 2026 12:44
The ETag hash was widened to FNV-64 a few commits back but the docs still
said 32-bit, and nobody had written down the new Cache-Control: private,
no-cache header the status routes send on both 200 and 304.
@thushan thushan self-assigned this Aug 4, 2026
@thushan thushan added documentation Improvements or additions to documentation enhancement New feature or request experimental Experimental labels Aug 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 126 files, which is 26 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1191a572-9d7f-4a99-81db-b20022add8b9

📥 Commits

Reviewing files that changed from the base of the PR and between f4bde8d and e7fb333.

⛔ Files ignored due to path filters (10)
  • internal/app/handlers/dashboard/dist/.gitkeep is excluded by !**/dist/**
  • web/dashboard/bun.lock is excluded by !**/*.lock
  • web/dashboard/public/apple-touch-icon.png is excluded by !**/*.png
  • web/dashboard/public/favicon-16.png is excluded by !**/*.png
  • web/dashboard/public/favicon-32.png is excluded by !**/*.png
  • web/dashboard/public/favicon.ico is excluded by !**/*.ico
  • web/dashboard/src/assets/fonts/ibm-plex-sans-regular.woff2 is excluded by !**/*.woff2
  • web/dashboard/src/assets/fonts/jetbrains-mono-bold.woff2 is excluded by !**/*.woff2
  • web/dashboard/src/assets/fonts/jetbrains-mono-regular.woff2 is excluded by !**/*.woff2
  • web/dashboard/src/assets/logo/olla-thumb.png is excluded by !**/*.png
📒 Files selected for processing (126)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .gitignore
  • .goreleaser.yml
  • config/config.yaml
  • docs/content/about/release-notes.md
  • docs/content/api-reference/system.md
  • docs/content/configuration/dashboard.md
  • docs/content/configuration/endpoint-auth.md
  • docs/content/configuration/practices/monitoring.md
  • docs/content/development/setup.md
  • docs/content/getting-started/installation.md
  • docs/content/index.md
  • docs/mkdocs.yml
  • internal/adapter/discovery/repository.go
  • internal/adapter/discovery/repository_test.go
  • internal/adapter/discovery/repository_userinfo_test.go
  • internal/app/handlers/dashboard/access.go
  • internal/app/handlers/dashboard/access_test.go
  • internal/app/handlers/dashboard/embed.go
  • internal/app/handlers/dashboard/embed_test.go
  • internal/app/handlers/handler_routes_dashboard_test.go
  • internal/app/handlers/handler_status.go
  • internal/app/handlers/handler_status_endpoints.go
  • internal/app/handlers/handler_status_endpoints_test.go
  • internal/app/handlers/handler_status_etag_gzip_test.go
  • internal/app/handlers/handler_status_etag_test.go
  • internal/app/handlers/handler_status_fields_test.go
  • internal/app/handlers/handler_status_gzip_integration_test.go
  • internal/app/handlers/handler_status_id_consistency_test.go
  • internal/app/handlers/handler_status_models.go
  • internal/app/handlers/handler_status_models_test.go
  • internal/app/handlers/handler_status_race_test.go
  • internal/app/handlers/handler_status_sanitise_test.go
  • internal/app/handlers/handler_status_wire_shape_test.go
  • internal/app/handlers/handler_unified_models.go
  • internal/app/handlers/server_routes.go
  • internal/app/handlers/server_routes_test.go
  • internal/app/middleware/compression.go
  • internal/app/middleware/compression_test.go
  • internal/app/middleware/logging.go
  • internal/app/middleware/logging_gate_test.go
  • internal/app/middleware/logging_test.go
  • internal/app/services/http.go
  • internal/app/services/http_bind_test.go
  • internal/app/services/http_test.go
  • internal/config/config.go
  • internal/config/dashboard_test.go
  • internal/config/shipped_config_test.go
  • internal/config/types.go
  • makefile
  • pkg/format/format.go
  • pkg/format/format_test.go
  • readme.md
  • test/config_docs/dashboard_test.go
  • web/dashboard/.gitignore
  • web/dashboard/README.md
  • web/dashboard/index.html
  • web/dashboard/package.json
  • web/dashboard/src/App.jump-focus.test.ts
  • web/dashboard/src/App.svelte
  • web/dashboard/src/App.test.ts
  • web/dashboard/src/app.css
  • web/dashboard/src/components.css
  • web/dashboard/src/components/PctBar.svelte
  • web/dashboard/src/components/RangeBar.svelte
  • web/dashboard/src/components/RangeBar.test.ts
  • web/dashboard/src/components/SortableTable.grouped-fixture.svelte
  • web/dashboard/src/components/SortableTable.svelte
  • web/dashboard/src/components/SortableTable.test.ts
  • web/dashboard/src/components/SparkStrip.svelte
  • web/dashboard/src/components/SparkStrip.test.ts
  • web/dashboard/src/components/StatTile.svelte
  • web/dashboard/src/components/StatTile.test.ts
  • web/dashboard/src/components/StatusBanner.svelte
  • web/dashboard/src/components/StatusTag.svelte
  • web/dashboard/src/components/ThemeToggle.svelte
  • web/dashboard/src/layout/DashboardLayout.svelte
  • web/dashboard/src/layout/Header.svelte
  • web/dashboard/src/layout/Header.test.ts
  • web/dashboard/src/layout/NavTabs.svelte
  • web/dashboard/src/layout/StatusStrip.stale.test.ts
  • web/dashboard/src/layout/StatusStrip.svelte
  • web/dashboard/src/lib/clock.svelte.ts
  • web/dashboard/src/lib/contrast.test.ts
  • web/dashboard/src/lib/dom-id.ts
  • web/dashboard/src/lib/format.test.ts
  • web/dashboard/src/lib/format.ts
  • web/dashboard/src/lib/jump-to-endpoint.test.ts
  • web/dashboard/src/lib/jump-to-endpoint.ts
  • web/dashboard/src/lib/poll-scheduler.test.ts
  • web/dashboard/src/lib/poll-scheduler.ts
  • web/dashboard/src/lib/router.test.ts
  • web/dashboard/src/lib/router.ts
  • web/dashboard/src/lib/stores/endpoints.svelte.ts
  • web/dashboard/src/lib/stores/history.svelte.ts
  • web/dashboard/src/lib/stores/history.test.ts
  • web/dashboard/src/lib/stores/models.svelte.ts
  • web/dashboard/src/lib/stores/navigation.svelte.ts
  • web/dashboard/src/lib/stores/overview.svelte.ts
  • web/dashboard/src/lib/stores/poll-store.svelte.ts
  • web/dashboard/src/lib/stores/poll-store.test.ts
  • web/dashboard/src/lib/stores/theme.svelte.ts
  • web/dashboard/src/lib/stores/theme.test.ts
  • web/dashboard/src/lib/types.ts
  • web/dashboard/src/main.ts
  • web/dashboard/src/panels/ColumnAlignment.test.ts
  • web/dashboard/src/panels/EndpointsPanel.dup-names.test.ts
  • web/dashboard/src/panels/EndpointsPanel.keys.test.ts
  • web/dashboard/src/panels/EndpointsPanel.offline-bar.test.ts
  • web/dashboard/src/panels/EndpointsPanel.stable-id.test.ts
  • web/dashboard/src/panels/EndpointsPanel.svelte
  • web/dashboard/src/panels/EndpointsPanel.test.ts
  • web/dashboard/src/panels/EndpointsPanel.type-badge.test.ts
  • web/dashboard/src/panels/ModelsPanel.error-state.test.ts
  • web/dashboard/src/panels/ModelsPanel.lifecycle.test.ts
  • web/dashboard/src/panels/ModelsPanel.pill-jump.test.ts
  • web/dashboard/src/panels/ModelsPanel.svelte
  • web/dashboard/src/panels/ModelsPanel.test.ts
  • web/dashboard/src/panels/OverviewPanel.svelte
  • web/dashboard/src/panels/OverviewPanel.test.ts
  • web/dashboard/src/panels/SortableTable.collision.test.ts
  • web/dashboard/src/vite-env.d.ts
  • web/dashboard/svelte.config.js
  • web/dashboard/tsconfig.json
  • web/dashboard/vite.config.js

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thushan
thushan merged commit 7523a29 into main Aug 4, 2026
8 checks passed
@thushan
thushan deleted the feature/simple-dashboard branch August 4, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request experimental Experimental

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant