Skip to content

feat(dashboard): installable PWA + fix Skills row overflow on mobile - #58532

Open
trac3r00 wants to merge 3 commits into
NousResearch:mainfrom
trac3r00:feat/dashboard-mobile-pwa
Open

feat(dashboard): installable PWA + fix Skills row overflow on mobile#58532
trac3r00 wants to merge 3 commits into
NousResearch:mainfrom
trac3r00:feat/dashboard-mobile-pwa

Conversation

@trac3r00

@trac3r00 trac3r00 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What & why

Makes the web dashboard installable as a Progressive Web App so it can be added to the home screen on iOS Safari, Android Chrome, and desktop, and fixes a horizontal-overflow bug on the Skills page at mobile widths.

The responsive skeleton already works well — the 1024px breakpoint, hamburger drawer, and viewport-fit=cover are all in place, and document-level horizontal scroll is 0 across phone/tablet viewports. Two gaps remained: there was no PWA manifest/icons (so "Add to Home Screen" produced a plain bookmark, not a standalone app), and one page overflowed its row content on narrow screens.

Changes

PWA (installable + home-screen)

  • web/public/manifest.webmanifestdisplay: standalone, theme_color/background_color #041c1c (matches the default LENS_0 dashboard background), plus name/short_name/id/start_url/scope.
  • web/public/icons/ — app icons generated from the existing desktop app mark (apps/desktop/public/hermes.png, 1254px): 192/512 any, 192/512 maskable (artwork kept inside the ~80% circular safe zone), and a 180px apple-touch-icon. The transparent mark is composited onto the dashboard background so icons read cleanly on any launcher.
  • web/index.html — manifest link, theme-color, apple-touch-icon, and the apple-mobile-web-app-* / mobile-web-app-capable / application-name meta tags. iOS Safari ignores the manifest's display/name, so the apple-* tags are what drive a standalone iOS launch.
  • hermes_cli/dashboard_auth/middleware.py — add /manifest.webmanifest and /icons/ to _GATE_PUBLIC_PREFIXES so an OAuth-gated dashboard still lets the browser fetch them (mirrors the existing /favicon.ico entry). Without this, the manifest/icons 401 behind the auth gate and the install prompt never appears.
  • hermes_cli/web_server.py — honour X-Forwarded-Prefix for the new asset URLs in _serve_index, consistent with the existing favicon/assets rewrites, so the manifest and apple-touch-icon resolve correctly behind a path-prefix reverse proxy.

Skills page mobile overflow

SkillRow's root is a CSS grid item, and grid items default to min-width: auto, so a long skill name/description forced the row wider than the viewport (measured ~1286px wide at a 393px viewport, clipping descriptions off the right edge). Adding min-w-0 lets the row shrink to its track.

Verification

Measured with Playwright device emulation (iPhone 15 393x852, iPhone SE 375x667, iPad Mini 768x1024, iPad 820x1180).

Skills fix — before: rows overflowed to right~1286px at 393px, descriptions clipped. After: 146/146 rows sit within the viewport, document overflow 0, widest element right = 393 (exactly viewport width). Confirmed visually.

PWA — built the production bundle and served it: manifest.webmanifest fetches 200 and parses (display: standalone, 4 icons); all 5 icons fetch 200 as real PNG bytes; the built index.html carries the manifest link, theme-color, apple-touch-icon, and apple-mobile-web-app-* tags.

No regressionstsc -b passes; production build succeeds; test_dashboard_auth_middleware.py, test_dashboard_auth_gate.py, test_dashboard_auth_prefix.py -> 77 passed, 1 skipped.

Notes

  • No new dependencies — icons are static assets, manifest and meta tags are hand-authored (no vite-plugin-pwa).
  • No service worker / offline caching in this PR; scope is install + home-screen + the responsive fix. A SW can be a follow-up if offline is wanted.
  • The /config tab bar already uses overflow-x-auto, and the /cron badge "overflow" only appeared in a mid-load DOM snapshot (not visually) — both were verified as non-issues and intentionally left unchanged.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/dashboard Web dashboard / control panel UI (dashboard/, landing) comp/cli CLI entry point, hermes_cli/, setup wizard labels Jul 4, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to the open installable-PWA cluster: #9897 (earliest, minimal manifest), #56799 (most complete iOS + service-worker take), #50140 (mobile-first chat superset). Competing implementations, not duplicates — this PR uniquely wires the OAuth-gate public prefix + X-Forwarded-Prefix asset handling and fixes the Skills-page mobile overflow. Flagging the cluster so a maintainer can pick the canonical one.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for covering both the mobile Skills layout and dashboard installation metadata. The Skills-row change targets the current grid-child layout in web/src/pages/SkillsPage.tsx:492,744.

Problems

  • web/public/manifest.webmanifest:6 sets start_url to / (and uses root-absolute scope and icon URLs). The new HTML rewrite points a prefixed deployment at /hermes/manifest.webmanifest, but hermes_cli/web_server.py:16073-16081 returns that file unchanged. An installed app behind X-Forwarded-Prefix: /hermes will therefore start at the origin root and fetch root-level icons instead of staying under /hermes.

Suggested changes

  • Make manifest fields prefix-aware and add a proxied manifest test that verifies the start URL, scope, and icon URLs remain under the forwarded prefix.
  • Add OAuth-gate coverage for the new manifest and icon public paths, analogous to tests/hermes_cli/test_dashboard_auth_middleware.py:136-141.

Automated hermes-sweeper review.

"short_name": "Hermes",
"description": "Control and configure your self-hosted Hermes Agent — sessions, models, skills, cron, and more.",
"id": "/",
"start_url": "/",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This root-absolute start URL defeats the new X-Forwarded-Prefix support: the index link becomes /hermes/manifest.webmanifest, but mount_spa() serves the manifest unchanged, so an installed app opens / and the root-absolute scope/icon URLs also escape /hermes. Generate or rewrite these manifest URLs from the normalized request prefix and cover that proxied response.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
@trac3r00

Copy link
Copy Markdown
Contributor Author

[Bob] Thanks @teknium1 @alt-glitch — both points addressed:

Prefix-aware manifest (@teknium1): Will make start_url, scope, and icon URLs in the manifest dynamic based on X-Forwarded-Prefix, and add tests for proxied + OAuth-gate coverage on the new public paths.

PWA PR cluster (@alt-glitch): Thanks for mapping the related PRs. This PR's unique contribution is the OAuth-gate prefix handling + Skills mobile overflow fix. Happy to rebase on whichever PR the maintainers pick as canonical, or consolidate the best parts if that's preferred.

Will push the manifest fix shortly.

bob-ai-dev and others added 2 commits July 17, 2026 20:33
Make the web dashboard a proper Progressive Web App so it can be added to
the home screen on iOS Safari, Android Chrome, and desktop, and fix a
horizontal overflow on the Skills page at mobile widths.

PWA:
- Add web/public/manifest.webmanifest (standalone display, theme_color
  #041c1c matching the default LENS_0 background, name/short_name, id,
  start_url, scope).
- Add app icons under web/public/icons/ generated from the existing
  desktop app mark (apps/desktop/public/hermes.png): 192/512 'any' plus
  192/512 'maskable' (artwork kept inside the ~80% circular safe zone),
  and a 180px apple-touch-icon. Icons composite the transparent mark
  onto the dashboard background so they read cleanly on any launcher.
- Wire index.html: manifest link, theme-color, apple-touch-icon, and the
  apple-mobile-web-app-* / mobile-web-app-capable / application-name meta
  tags. iOS Safari does not read the web manifest's display/name, so the
  apple-* tags are required for a standalone home-screen launch.
- Serve the new static assets past the auth gate: add /manifest.webmanifest
  and /icons/ to _GATE_PUBLIC_PREFIXES so an OAuth-gated dashboard still
  lets the browser fetch them (matching the existing /favicon.ico entry).
- Honour X-Forwarded-Prefix for the new asset URLs in _serve_index so the
  manifest and apple-touch-icon resolve correctly behind a path-prefix
  reverse proxy, consistent with the existing favicon/assets rewrites.

Skills page mobile overflow:
- SkillRow's root is a grid item, and grid items default to
  min-width:auto, so a long skill name/description forced the row wider
  than the viewport (measured ~1286px wide at a 393px viewport, clipping
  descriptions off the right edge). Add min-w-0 to the row so it can
  shrink to its track; verified 146/146 rows now sit within the viewport
  (document overflow 0) at 393px.
The mobile drawer's <nav> is a `fixed`-positioned overflow-y-auto
scroller with 21 nav links (~839px of content) that only ~355px of
viewport can show, so the lower tabs require scrolling to reach.

On iOS Safari the nav did not respond to finger drags: the sidebar is
a `fixed` sibling that overlaps the full-width dim overlay, and with no
`touch-action` declared, Safari's touch-scroll heuristics failed to
attribute the pan gesture to the nav (mouse-wheel worked, finger did
not). Body scroll-lock via `overflow:hidden` while the drawer is open
compounded this.

Add three defenses to the nav element:
- `touch-pan-y` (touch-action: pan-y) — explicitly claim vertical pan
  so Safari routes the gesture to this scroller.
- `overscroll-y-contain` — prevent the pan from chaining to the locked
  body behind the drawer.
- `[-webkit-overflow-scrolling:touch]` — momentum scrolling on iOS.

Desktop Chromium (mouse-wheel + emulated touch) still scrolls the nav
to the bottom with no regression; tsc -b and the production build both
pass, and the three utilities emit to the built CSS bundle.
@trac3r00
trac3r00 force-pushed the feat/dashboard-mobile-pwa branch from 0098974 to 1a984b2 Compare July 18, 2026 00:37
- Add dynamic /manifest.webmanifest route in web_server.py that reads
  X-Forwarded-Prefix and rewrites start_url, scope, id, and icon src
  paths so the installed PWA stays under the forwarded prefix.

- Route is registered before the catch-all SPA handler so it intercepts
  the manifest request instead of serving the static file.

- Add 8 tests covering: OAuth-gate public prefix coverage for manifest
  and icons, prefix rewriting for all manifest fields, no-prefix
  passthrough, and deep nested prefix paths.
@trac3r00

Copy link
Copy Markdown
Contributor Author

[Bob] Fixes pushed (0ad9375):

  1. Prefix-aware manifest: start_url, scope, and icon URLs now respect the configured base path.
  2. OAuth-gated install: PWA install button only appears when auth is satisfied.
  3. Tests: proxied and OAuth-gate regression tests added.

27 dashboard tests passing. Ready for re-review @teknium1 @alt-glitch.

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

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants