Skip to content

feat(dashboard): redesign, mobile UI, runtime provider/fallback/pool management - #3

Closed
entitybtw wants to merge 79 commits into
aurorallm:mainfrom
entitybtw:main
Closed

entitybtw wants to merge 79 commits into
aurorallm:mainfrom
entitybtw:main

Conversation

@entitybtw

@entitybtw entitybtw commented Aug 17, 2026 •

Copy link
Copy Markdown

Dashboard redesign

  • Complete visual redesign in Catppuccin
  • Fully mobile-responsive
  • Fixed compact sizes, touch-friendly targets, clean auth/logo/sidebar
  • Shared SearchInput fixing placeholder/icon overlap in audit logs & usage

Provider management (new)

  • Full CRUD for providers from the dashboard (base URL, API key, models, type)
  • Overrides persisted to configs/provider-overrides.json and loaded at startup
  • Per-provider bind_ip, pool_only, runtime enable/disable, live rename, duplicate protection
  • Provider status shows whether a key is set without exposing it
  • OpenRouter models: list now acts as an allowlist
  • vLLM provider type now available in the dashboard (previously only via .env)

Fallback chains (new)

  • Manage fallback rules from the UI, applied at runtime without restart
  • Chains callable by name and exposed in /v1/models
  • Rule order preserved across toggle/edit/delete

Provider pools (new)

  • Create / edit / delete pools with member selection and weighted/round-robin strategies directly in the UI
  • Health-aware members, pool_only models, live registry rebuild after every change

Response headers (new)

  • Configurable X-Actual-Provider/Model/Requested/Fallback-Chain headers
  • Per-header toggles, custom headers, success/error/always modes, headers on 429/401 errors

Persistence

Dashboard-managed state survives restarts: configs/provider-overrides.json, configs/pool-overrides.json, configs/fallback.json (paths overridable via env). Docker volumes keep overrides across container recreation.

auroraix and others added 30 commits July 22, 2026 20:17
- Restyle palette from green Forest Canopy to warm amber (#d4a574)
- Replace DM Sans/Serif with Unbounded (display) + system-ui (body) + JetBrains Mono
- Flatten glass/blur effects to solid surfaces with borders (quackey style)
- Set border-radius to 2px throughout
- Add animated draw-in logo SVG from aurorallm.online
- New Fallback Chains page for managing model fallback chains
- Add Fallback entry to sidebar navigation
- Remove @fontsource/dm-sans, @fontsource/dm-serif-display, @fontsource/inter
- SidebarLogo: replace inline SVG with <img src='/navbar-logo.svg'> for
  proper responsive rendering of the actual logo image
- Fallback page: load rules from dashboard config fallback.manual_rules
  instead of combos API; page is now read-only since fallback.json is
  config-managed
- Remove broken toggle switch and create/edit dialog (no write API)
- Sidebar: remove bg-accent from logo container, use plain <img>
- Fallback page: two sections - config rules (read-only from
  fallback.json) + combo chains (create/edit/delete/toggle via API)
- Dialog with model chain builder, reorder, enabled checkbox
- SidebarLogo: inline SVG with currentColor fill instead of <img>
  (avoids auth error from gateway proxy)
- Fallback page: single editable section using combos API, full CRUD
  (create/edit/delete/toggle) with model chain builder dialog
- Remove read-only config rules section
- Color scheme: Catppuccin Mocha (dark) / Latte (light) throughout
- New Go handler: GET/PUT /admin/api/v1/fallback for direct
  fallback.json read/write (reads file on every request)
- Frontend API layer: fetchFallback/updateFallback with polling
  (10s interval) so changes to fallback.json are always reflected
- Fallback page: fully editable rules with source→target chain
  builder, auto-refresh, add/edit/delete
- Dark: Base #303446, Surface #414559, Mauve accent #ca9ee6
- Light: Base #eff1f5, Surface #ccd0da, Mauve accent #8839ef
- Softer than Mocha, not as light as Latte — balanced middle ground
- Surface: #e6e9ef (lighter, cleaner)
- Elevated: #ffffff (pure white cards)
- Border: #dce0e8 (softer)
- Muted text: #7c7f93 (better contrast)
- Glass: white with subtle shadow
- Reduced opacity on semantic backgrounds for cleaner look
- Dark theme: revert to Catppuccin Mocha (#1e1e2e base, #cba6f7 accent)
- Sidebar: slide-out drawer on mobile with backdrop overlay
- Hamburger menu button (md:hidden) in AppShell
- Close button (X) in sidebar header on mobile
- Nav links close sidebar on mobile click
- Login page: responsive form, 44px touch targets
- Main content: padding adjusted for mobile hamburger
- CSS: font-size 16px on mobile inputs to prevent zoom
- BottomNav component: 5-tab bottom navigation (Home, Models, Fallback,
  Console, Settings) visible only on mobile (< 768px)
- Sidebar: larger touch targets (py-3), active indicator border-left,
  smoother mobile drawer experience
- Hamburger: larger 48px button with active:scale-95 feedback
- Login: larger logo container, prominent on mobile
- CSS: iOS zoom prevention (16px inputs), 44px min touch targets,
  smooth scrolling
- Main content: bottom padding for bottom nav clearance
- Add mobile navigation with burger menu (BottomNav component)
- Make all pages mobile-friendly with responsive breakpoints
- Optimize login page for mobile devices
- Update all UI components with mobile-first approach
- Add responsive tables, dialogs, buttons, and inputs
- Improve touch targets and spacing for mobile
- Hide sidebar on mobile, show bottom nav instead
- Make models page fully responsive with horizontal scroll
- Update page headers with responsive typography
- Replace Menu icon with animated CSS burger (3 lines → X on open)
- Remove BottomNav component from mobile layout
- AuthDialog: mobile-friendly sizing, larger touch targets, error banners
- Remove unused BottomNav import
- Mobile header: inline SVG logo + 'Aurora' text instead of plain text
- Sidebar: logo always shown (both mobile and desktop)
- Remove collapse functionality (sidebar always expanded on desktop)
- MobileThemeButton: full-width row with icon + label text
- AuthDialog: mobile-friendly sizing, larger touch targets
- Remove unused SidebarCollapseButton and isCollapsed state
- Clean up unused imports (PanelLeftClose, PanelLeftOpen)
… fallback inline edit

- Sidebar: 'Aurora Gateway' → 'Aurora' everywhere
- Mobile theme toggle: 3-button row (Light/[System icon]/Dark) with Smartphone icon
- Desktop theme toggle: keeps Monitor icon
- Light theme: cleaner whites (#f8f9fc bg, #ffffff surface), better contrast
- Fallback page: inline editing (click card to edit), stable order, no shuffling on poll
- Remove unused toggleTheme import
…ean theme toggle

- Fallback: explicit Edit3 button on each card (not click-on-card)
- Fallback: targets are editable inline (input fields in edit mode)
- Fallback: Save/Cancel buttons prominent in edit mode
- Mobile theme toggle: icons only in 3-column grid, no text overflow
- Mobile theme toggle: grid with dividers instead of flex with labels
…act theme toggle

- Fallback: sort rules alphabetically by source (stable order, no shuffling)
- Fallback: edit/create in Dialog with proper model selector dropdowns
- Fallback: source and each target selectable from model list
- Mobile theme toggle: compact h-8 grid, icons only, matches desktop style
- Verified admin key block already compact on mobile
- EditDialog: max-w-[calc(100vw-2rem)] on mobile, h-12 touch targets
- Dialog: scrollable body, larger selects, proper footer layout
- Sidebar nav: py-2 + gap-2.5 (compact rectangles, not tall squares)
- Nav icons: h-4 w-4 consistent size on mobile and desktop
- ProviderOverrideStore: persist to configs/provider-overrides.json
- Providers survive docker restart (loaded on startup, saved on upsert/remove)
- UI dropdown: sync with Go backend types (vllm, gemini, groq, minimax, ollama, oracle, zai, reranker)
- Remove unsupported UI types (google, aws-bedrock, mistral, cohere, jina, togetherai)
…gistry

The override merge loop appended to names without checking if the name
was already present from the runtime registry, causing UI duplicates.
…onses

- Add Mode field to ResponseHeadersConfig: 'success' (default), 'error', 'always'
- Response headers middleware adds headers based on Mode and status code
- Update admin snapshot, overlay, and UI with Mode selector
- Headers now work on error responses (429, 401, etc.) when Mode='error' or 'always'
…) and fix config loading

- Add response headers to error responses via handleErrorWithHeaders in rate limit middleware
- Fix config package imports (configpkg alias for aurora/configuration)
- Fix batchstore -> batch.Store references
- Update tests for new middleware signature

Now 429/401/500 responses include X-Request-ID and custom headers when mode=error or always
Add BindIP to RawProviderConfig, ProviderConfig, ProviderOptions, and
ProviderOverride so each provider can bind its outbound connections to a
specific local IP. This fixes upstream rate limiting that is keyed by
source IP (e.g. opencode.ai FreeUsageLimitError), where the provider's
requests must leave from a specific host IP instead of the default.

- http_client: NewHTTPClientWithBindIP creates a client with a LocalAddr dialer
- llmclient: Config.BindIP + httpClientForConfig
- All provider constructors pass opts.BindIP through
- Admin API: bind_ip in provider update/create and override store
- UI: Bind IP field in provider modal
- docs: config example
Previously response headers were only added on successful responses
(applyResponseHeaders needs ExecutionMeta) and on auth-key rate limit
errors via handleErrorWithHeaders. Provider errors like upstream 429
(rate limit) went through plain handleError without any headers.

Add handleErrorWithResponseHeaders on translatedInferenceService which
derives X-Actual-Provider and X-Requested-Model from the request workflow
(before execution metadata exists) and adds headers when mode is
'error' or 'always'. Wire it into chat completions, responses, and
streaming error paths.

Add tests for always/error/success/disabled modes on error responses.
The Mode field (success/error/always) was missing from dashboardSettingsSnapshot
in app.go, so the dashboard API returned mode: "" and the UI always showed the
default 'success' selector after reload even though the overlay file had the
correct value. Populate it from cfg.ResponseHeaders.Mode.
Do not overwrite an existing API key with an empty string on provider
update (PUT). A blank api_key in the payload now means 'keep existing'.
Expose api_key_set flag in SanitizedProviderConfig so the dashboard UI
shows 'Leave empty to keep existing key' when editing a provider that
already has a key configured.
Expose the configured API key (masked in admin UI status) and bind_ip in
SanitizedProviderConfig so the provider edit modal can prefill existing
values instead of showing empty fields. Provider changes (including
bind_ip) already apply without restart via runtime refresh rebuild.
After any runtime refresh (provider edit/save from the dashboard), sync
the admin handler's configured-providers snapshot with the rebuilt
inventory so api_key, bind_ip, and model changes appear immediately in
the UI without a restart. Store adminHandler on App and update it in
RefreshRuntime.
The provider status response rebuilt UI-override configs from the
override store without carrying over api_key/bind_ip, so the dashboard
always showed empty key/bind fields when editing. Populate them from
ProviderOverride so the edit modal prefills existing values.
- Fallback rules can now be addressed by a chain name (alias) instead of
  a source model, so clients request model=<chain-name> and get the
  ordered fallback chain
- Expose fallback chain names as selectable models in GET /v1/models
  (owned_by: fallback-chain) via ExposedModelLister
- Fallback editor: replace 'Source model' select with a free-form Chain
  name input
- Add resolver test for chain-by-alias resolution
…pear in /v1/models

Replace internal provider/model names in tests with neutral placeholders.
Replace ad-hoc inline switch+label rows with a reusable ToggleField
component (label left, iOS-style switch pinned right, full-width tappable
row with a 44px touch target and truncating label). Applied across the
settings tabs (General/Caching/Networking), workflow feature grid, and the
models/combos dialog toggles so toggles look correct on mobile everywhere.
… usage

The audit logs and usage search fields stacked pl-12 over the Input
component's md:px-3, so on desktop the padding-left collapsed to 12px and
the placeholder text rendered on top of the search icon. Replaced with a
plain-input SearchInput (left-3 icon, pl-9 text) matching the models page,
and applied it to audit logs, usage, guardrails, and workflows.
…diately

Rate-limited providers (429) were retried up to max_retries+1 times with
exponential backoff on the SAME provider before the error surfaced to the
fallback chain, so a chain of rate-limited free providers burned ~7s per
provider before switching. 429 is now treated as a fail-fast signal: the
client returns the rate-limit error right away and the fallback chain
moves to the next provider/model immediately. 503/502/504 stay retryable.
…dels are used

OpenRouter exposes a huge multi-vendor catalog, so an explicit models:
list on an openrouter provider is now always treated as an allowlist:
only the operator-listed models are exposed and routed, never the full
upstream catalog. Other provider types keep the configured global mode.
…obile

Tailwind min-h-0 generates calc(var(--spacing)*0) but --spacing is not
defined in this project's @theme inline block, so the value was invalid
and the global button{min-height:44px} always won. Inline style
minHeight:0 bypasses all CSS layers and guarantees the switch stays at
its designed track height.
Add create/edit/delete of provider pools from the dashboard with no restart
required. Pool definitions persist to configs/pool-overrides.json and are merged
over static config at runtime. Pools remain callable as models.

- pool: support weighted strategy, per-member weights, health_aware in snapshot
- admin: persist full RawPoolConfig overrides; add POST/PUT/DELETE /pools and
  GET /pools/options; validate members (same type, known providers)
- ui: rewrite pools page with full CRUD, member picker, weights, mobile layout
- docs: document dashboard pool management and override file
apiFetch only sets Content-Type: application/json when the json option is
used; a raw body caused echo to reject pool create/update with 415.
A per-provider pool_only setting hides the provider's models from the public
model list; it becomes reachable only through a pool that lists it as a member.
Wired through config, provider runtime, router model list, admin inventory, and
the providers UI toggle.
Edit a provider's name from the dashboard to rename it. The rename applies at
runtime: the new name gets the provider config, the old name is disabled, and
UI-managed pools that listed the provider are updated to the new name. Static
config pool references must be edited manually.
The status response rebuilt SanitizedProviderConfig from UI overrides without
the pool_only flag, so the dashboard toggle appeared off after a reload even
though the flag was saved. Copy PoolOnly through so the edit dialog reflects
the persisted value.
@entitybtw

Copy link
Copy Markdown
Author

I might reopen a pull request after all, but for now, it’ll remain a fork - that’s more convenient for me.

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.

2 participants