Skip to content

UI refresh: composer-centric controls, Hermes control center, and dialog polish - #242

Closed
aronprins wants to merge 23 commits into
nesquena:masterfrom
aronprins:feat/ui-improvements-round1
Closed

UI refresh: composer-centric controls, Hermes control center, and dialog polish#242
aronprins wants to merge 23 commits into
nesquena:masterfrom
aronprins:feat/ui-improvements-round1

Conversation

@aronprins

Copy link
Copy Markdown
Contributor

Summary

This branch is a focused UI pass that reorganises the main chrome around the composer and consolidates all settings/session tools behind a single "Hermes Control Center" surface. It also replaces the scattered activity bar + native confirm/prompt calls with a consistent status+dialog system, and does a sweeping pixel/icon cleanup across the UI.

No server-side behaviour changes — everything lives in static/ plus a couple of new static-asset sanity tests.

What changed

Composer becomes the control hub (inspired by Theo / T3 Code)

  • Model selector, profile chip, and workspace chip now all live in the composer footer instead of the sidebar/topbar. Each is a pill button with its own dropdown positioned relative to the footer.
  • The linear context-usage pill is replaced by a compact circular context ring with a hover tooltip that breaks out % used, token counts, auto-compress threshold, and estimated cost.
  • Cancel button moves next to Send in the composer-right cluster.
  • Topbar model/profile/clear chips are gone; the topbar keeps only the title, meta line, and a Files toggle.

Hermes Control Center replaces the old Settings modal

  • Sidebar bottom is now a single "Hermes WebUI" launch button (with the Hermes mark icon) that opens the control center.
  • Control center is an 860px tabbed modal with Conversation / Preferences / System tabs, fixed-height panes (no more outer resize on tab switch), and always opens on the Conversation tab.
  • Conversation tab hosts Transcript / JSON export / Import / Clear actions (previously crowded into the sidebar footer).
  • System tab houses the version badge, access password, and sign-out/disable-auth buttons.
  • Control center always resets to the Conversation tab when closed — covered by tests/test_sprint34.py.

Activity bar removed, status rerouted

  • The standalone activity bar above the composer is gone.
  • Turn-scoped status (thinking, cancelling, etc.) now renders inline in the composer footer via setComposerStatus.
  • Non-chat/system messages go through toasts via setStatus.
  • Live tool cards + the message timeline remain the primary progress UI.

Shared app dialogs replace confirm() / prompt()

  • New showConfirmDialog / showPromptDialog helpers in ui.js, backed by #appDialogOverlay markup and a themed .app-dialog-* CSS block.
  • All remaining native confirm() / prompt() callsites across panels.js, sessions.js, ui.js (delete session, delete cron, delete project, clear conversation, remove workspace, new file/folder prompts, project rename, etc.) now go through the shared dialog, with proper focus trap, Esc/Enter handling, and danger styling.
  • tests/test_sprint33.py locks this in by grepping the static bundle for any remaining confirm( / prompt( calls.

Session list: hover actions → single dropdown

  • Per-row pin/move/archive/duplicate/trash buttons are replaced with a single `⋯` trigger that opens a shared `.session-action-menu` dropdown (with descriptive meta text per option and a dedicated danger state for Delete).
  • Session rows are now fully rounded with 2px vertical spacing; the left border indicator for active/CLI/project rows is dropped (each state already has a distinct cue — gold fill, CLI badge, project dot).
  • Session search input gets a taller tap target.

Workspace panel behaviour

  • New explicit `_workspacePanelMode` state ('closed' / 'browse' / 'preview') in `boot.js` with a collapse button on the panel header and a topbar "Files" toggle chip.
  • Workspace switch now guards against in-flight agent runs and dirty preview edits (confirming discard via the new dialog) before calling `/api/session/update`.
  • Adds a "Choose workspace path" action in the workspace dropdown that prompts for an absolute path, adds it via `/api/workspaces/add`, and switches the session to it.

Icon and emoji cleanup

  • Replaces remaining emoji glyphs throughout the UI with Lucide `li()` icons for consistency (paperclip, copy, pencil, rotate-ccw, shuffle, lightbulb, check, square, loader, x, settings, clock, play, pause, trash-2, arrow-right, plus, folder).
  • Adds missing Lucide paths (`paperclip`, `copy`, `rotate-ccw`, `pencil`, `save`, `chevron-right`, `arrow-right`, `pause`, `user`) to `static/icons.js`.
  • `CHANGELOG.md` entries referencing emoji glyphs updated to match.

Pixel normalisation pass

  • Snaps padding, gap, and border-radius values across composer chips, sidebar panels, cron list, settings, approval buttons, dropdowns, and inline message edit to the `2/4/6/8/10/12` grid — removing the assorted 5/7/9/11px drift that made sibling elements feel subtly misaligned.
  • Light-theme overrides updated for the new session-action trigger and the context ring (dropping the old `.ctx-bar-wrap` rules).

Tests

  • `tests/test_sprint33.py` (new, 5 tests): verifies the shared dialog markup, CSS, helpers, and the absence of native confirm/prompt.
  • `tests/test_sprint34.py` (new, 2 tests): verifies the control center reset-on-close helpers exist and are the only code path for hiding the modal.
  • Adjustments to `tests/test_sprint16.py`, `test_regressions.py`, `test_sprint6.py`, and `conftest.py` to account for the moved/renamed selectors.

Docs

  • `ARCHITECTURE.md`, `ROADMAP.md`, `SPRINTS.md`, `TESTING.md`, and `CHANGELOG.md` touched to document the new layout and sprint scope.

Test plan

  • `pytest tests/test_sprint33.py tests/test_sprint34.py` (new)
  • `pytest tests/test_sprint16.py tests/test_regressions.py tests/test_sprint6.py` (adjusted)
  • Full `pytest` run
  • Manual: open the app, verify the composer footer shows profile / workspace / model chips with working dropdowns and that the context ring tooltip renders % + tokens + cost
  • Manual: open Hermes control center, cycle through Conversation / Preferences / System tabs, close and reopen — should always land on Conversation, outer shell should not resize
  • Manual: trigger each migrated dialog path (delete session, delete cron, clear conversation, new file, new folder, remove workspace, switch workspace with dirty preview, project delete/rename) and confirm the shared modal handles focus + Esc + Enter
  • Manual: streaming turn — verify cancel button appears in composer footer, status text renders inline, and toasts carry non-chat status
  • Manual: session list hover — `⋯` trigger opens the dropdown, danger Delete option styled correctly, pin/archive/duplicate work
  • Manual: toggle workspace panel via topbar Files chip and collapse button, both desktop and <=900px viewport
  • Visual sweep across dark / light / slate / solarized / monokai / nord / oled themes for the new components

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Thanks for this PR, @aronprins — this is a substantial UI overhaul and the description is detailed enough to review clearly.

What stands out

Composer as control hub — moving model/profile/workspace selectors into the composer footer is a coherent design choice. It reduces the number of places users need to look for controls and aligns with how other modern chat interfaces handle context. The circular context ring replacing the linear pill is a good space trade-off.

Hermes Control Center — consolidating the old settings modal into a tabbed 860px surface with fixed-height panes solves the "pane resizes on tab switch" issue that's been a friction point. Resetting to the Conversation tab on close is the right default.

Shared dialogs replacing confirm()/prompt() — this is overdue. Native browser dialogs are unstyled, non-themeable, and break the UX contract. The showConfirmDialog/showPromptDialog approach with focus trap and Esc/Enter handling is the right replacement.

Session list: dropdown — collapsing the per-row action buttons into a single trigger is a real improvement for long session lists. The meta text per option is a good addition.

Things to verify before merging

1. Composer footer overflow — with model selector, profile chip, workspace chip, context ring, cancel button, and send button all in the footer, this may get cramped on narrower viewports (e.g., 320–480px wide). Does the footer have a defined minimum width and a graceful collapse strategy?

2. Topbar-less navigation — removing the model/profile chips from the topbar is fine on desktop, but on mobile where the composer may be offscreen during scrolling, users lose access to those controls mid-conversation. Is there a fallback for narrow viewports?

3. _workspacePanelMode state persistence — is this state persisted across page reloads, or does it always reset to 'closed'? If users typically want the panel open, resetting it on reload would be annoying.

4. Test coverage — the PR adds test_sprint33.py and test_sprint34.py and adjusts four existing test files. Given the scope of JS changes (boot.js, panels.js, sessions.js, ui.js, icons.js), are the new tests primarily checking DOM structure and the absence of native confirm()/prompt(), or do they also cover the dialog behavior and composer state transitions?

5. Theme coverage — the PR mentions a visual sweep across 7 themes. Were these manual checks, or is there automated theme validation?


The scope is large but the description is well-organized and the design decisions are well-reasoned. The main pre-merge question is how the composer footer degrades at narrow viewports. Everything else looks like it's been thought through.

nesquena-hermes pushed a commit that referenced this pull request Apr 11, 2026
Adds showConfirmDialog() and showPromptDialog() helpers to ui.js, backed
by a themed #appDialogOverlay element in index.html. Replaces all 11
native browser confirm()/prompt() call sites across panels.js, sessions.js,
ui.js, and workspace.js.

The new dialogs support:
  - Themed styling matching the app's dark/light themes
  - Keyboard navigation (Esc=cancel, Enter=confirm, Tab=focus trap)
  - Danger mode (red confirm button) for destructive actions
  - focusCancel option for destructive prompts
  - Mobile-responsive layout (full-width stacked buttons at 640px)
  - ARIA roles and accessible labelling
  - i18n keys for all labels (en, de, zh, zh-Hant)

New test: tests/test_sprint33.py (5 tests) verifying the markup,
CSS selectors, helper functions, and that no native confirm/prompt
calls remain in any static JS file.

Extracted from PR #242 (feat/ui-improvements-round1) by @aronprins.
Full PR #242 is under review; this self-contained piece is safe to
merge independently.
nesquena-hermes pushed a commit that referenced this pull request Apr 11, 2026
…rom #242)

Replaces the five per-row hover action buttons (pin, move, archive, duplicate,
trash) with a single ⋯ trigger button that opens a positioned dropdown menu.

Changes:
  - static/sessions.js: adds _openSessionActionMenu(), closeSessionActionMenu(),
    _positionSessionActionMenu(), _buildSessionAction() with full keyboard
    (Escape), click-outside, scroll, and resize handling. Menu uses
    position:fixed to avoid sidebar clipping.
  - static/style.css: replaces .session-actions overlay CSS with new
    .session-actions-trigger and .session-action-menu rules.
  - tests/test_sprint16.py: updates test_sessions_js_active_skips_project_border
    → test_sessions_js_uses_action_menu_not_per_row_buttons, asserting the new
    ⋯ trigger and menu functions exist and old per-row buttons are gone.

The dropdown menu includes:
  - Pin / Unpin conversation
  - Move to project
  - Archive / Unarchive conversation
  - Duplicate conversation
  - Delete conversation (danger style)

Each action item has a label and a descriptive subtitle. The menu closes on
Escape, outside click, scroll, and resize-repositions to stay in viewport.

Browser tested: menu opens, correct 5 items with icons and subtitles, no JS
errors, Escape closes cleanly.

Extracted from PR #242 (feat/ui-improvements-round1) by @aronprins.
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Thanks for this PR, @aronprins — we did a thorough end-to-end review of the full diff and want to share where things stand and what the path to merge looks like.

What we did

We read the entire PR, audited all JS and CSS changes, verified every onclick= handler, ran the full test suite on the branch, and ran desktop and mobile browser QA. The code quality is genuinely high — the dialog system is well-implemented with proper focus management and ARIA, the session menu has solid click-outside/scroll/escape/resize handling, and the control center modal is clean.

Two self-contained pieces already extracted and submitted as standalone PRs

Rather than hold all of #242 on the same timeline, we extracted the two pieces that are fully self-contained and low-risk:

Both have passed full QA (629 and 624 tests respectively, zero JS errors in browser). They're ready for review.

What remains in #242 (the larger chunk)

The rest of the PR — composer footer restructure, Hermes Control Center modal, activity bar removal, workspace panel state machine — is more involved and carries more mobile risk. Specifically:

Issues to fix before this part can merge:

  1. One failing test (test_sprint16.py::test_sessions_js_active_skips_project_border) — this was already resolved in PR feat: session ⋯ action dropdown replaces per-row buttons (extracted from #242) #252, so a rebase onto master after feat: session ⋯ action dropdown replaces per-row buttons (extracted from #242) #252 merges will fix it automatically.

  2. Profile dropdown max-width.profile-dropdown in the composer footer lacks max-width: min(260px, calc(100vw - 32px)). The workspace dropdown already has this guard. Without it, the profile dropdown can clip off-screen at very narrow viewports. One CSS line to add.

  3. t('create') missing from i18n.js — the prompt dialog confirm button falls back to the raw key string. Minor but should be explicit. Already included in PR feat: shared app dialogs replace native confirm()/prompt() (extracted from #242) #251.

  4. Rebase onto master — the branch was cut before PRs fix: cancel button now interrupts agent and cleans up UI state #244 (cancel fix), security: redact credentials from API responses and fix credential file permissions #243 (security redaction), and [Docker] Add the ability to run with the same user id/gid as the hermes installing user #237 (Docker UID/GID) merged. After rebasing, test_cancel_interrupt.py and test_security_redaction.py will appear and the test count will align.

Mobile considerations:

The composer footer restructure moves model/profile/workspace controls out of the topbar and into the composer footer. Desktop looks great. On mobile, when users scroll a long conversation, those controls scroll out of view with the composer — which is a UX trade-off worth documenting. The @media(max-width:640px) rules you added (horizontal chip scrolling via overflow-x:auto) handle the narrow viewport adequately, but a 375px explicit test pass would be good to confirm.

We've also added PR #254 — a 14-test mobile layout regression suite that will now run on every QA pass, so future PRs (including this one) have automated coverage for mobile CSS regressions.

Suggested next steps for the larger chunk

  1. Rebase onto master (picks up PRs feat: shared app dialogs replace native confirm()/prompt() (extracted from #242) #251 and feat: session ⋯ action dropdown replaces per-row buttons (extracted from #242) #252 if merged, plus the security/cancel fixes)
  2. Add max-width: min(260px, calc(100vw - 32px)) to .profile-dropdown in the composer
  3. Run pytest tests/ -q and confirm 0 failures
  4. Do a 375px browser pass — specifically: scroll a long conversation to confirm the composer footer (and its chips) is still reachable, and that the profile/workspace dropdowns open and are fully visible at narrow widths

Once those are addressed, the remaining chunk is in good shape and we'll run the full QA gate (desktop + mobile browser sanity, full pytest, QA harness) before merge.

Thanks again for the detailed PR — this is solid work and we want to get it across the line.

nesquena-hermes pushed a commit that referenced this pull request Apr 11, 2026
Adds showConfirmDialog() and showPromptDialog() helpers to ui.js, backed
by a themed #appDialogOverlay. Replaces all 11 native browser confirm/prompt
call sites across panels.js, sessions.js, ui.js, workspace.js.

Supports: danger mode, keyboard focus trap (Tab/Escape/Enter), focus restore,
ARIA roles, mobile-responsive stacked buttons at 640px. i18n for en/de/zh/zh-Hant.
5 new tests in test_sprint33.py verify markup, CSS, helpers, and absence of
native dialog calls.

Extracted from PR #242.
nesquena-hermes pushed a commit that referenced this pull request Apr 11, 2026
Replaces the 5 per-row hover action buttons (pin/move/archive/duplicate/trash)
with a single ⋯ trigger that opens a positioned dropdown menu. Menu has full
keyboard (Escape), click-outside, scroll, and resize-reposition handling.
Position:fixed prevents sidebar clipping.

5 actions: Pin/Unpin, Move to project, Archive/Unarchive, Duplicate, Delete
(danger style). Each with icon and descriptive subtitle.

Updated test_sprint16.py: test_sessions_js_uses_action_menu_not_per_row_buttons
asserts the new trigger and menu functions exist, old per-row classes are gone.

Extracted from PR #242.
nesquena-hermes added a commit that referenced this pull request Apr 11, 2026
* fix: custom provider with slash model name no longer rerouted to OpenRouter (#255)

When base_url is configured in config.yaml, resolve_model_provider() now
trusts the configured provider/base_url entirely and skips the slash-based
OpenRouter heuristic. Fixes google/gemma-4-26b-a4b with provider:custom
being silently routed to OpenRouter, resulting in 401 errors.

Fixes #230

* test: mobile layout regression suite — 14 tests for every QA run (#254)

Adds tests/test_mobile_layout.py with 14 static regression tests that run
on every QA pass to catch mobile layout breakage before it reaches prod.
Covers: breakpoints at 900px/640px, right panel slide-over CSS, mobile
overlay, bottom nav, files button, profile dropdown z-index, chip overflow,
workspace close, 100dvh, 44px touch targets, 16px font-size on textarea.

* feat: /skills slash command lists and filters available Hermes skills (#257)

Adds /skills [query] command to commands.js. Fetches from /api/skills,
groups by category (alphabetically sorted), displays as a formatted
assistant message. Optional query filters by name, description, or category.
i18n keys added for en, de, zh, zh-Hant. 1 regression test added.

Fixes #248

* feat: shared app dialogs replace native confirm()/prompt() calls (#251)

Adds showConfirmDialog() and showPromptDialog() helpers to ui.js, backed
by a themed #appDialogOverlay. Replaces all 11 native browser confirm/prompt
call sites across panels.js, sessions.js, ui.js, workspace.js.

Supports: danger mode, keyboard focus trap (Tab/Escape/Enter), focus restore,
ARIA roles, mobile-responsive stacked buttons at 640px. i18n for en/de/zh/zh-Hant.
5 new tests in test_sprint33.py verify markup, CSS, helpers, and absence of
native dialog calls.

Extracted from PR #242.

* fix: Android Chrome mobile — workspace panel close + profile dropdown (#256)

Fix #247: toggleMobileFiles() now shows/hides the mobile overlay when
toggling the right workspace panel. New closeMobileFiles() helper closes
the panel with correct overlay state tracking. Overlay onclick calls both
closeMobileSidebar() and closeMobileFiles(). Mobile-only close button (x)
added to workspace panel header.

Fix #246: profile dropdown uses position:fixed;top:56px;right:8px at
max-width:900px, escaping the overflow-x:auto stacking context that was
clipping it on Android Chrome.

Fix applied during review: closeMobileSidebar() now checks if the right
panel is still open before hiding the overlay, preventing the overlay from
disappearing when only the sidebar is closed.

Fixes #247 Fixes #246

* feat: session ⋯ action dropdown replaces per-row buttons (#252)

Replaces the 5 per-row hover action buttons (pin/move/archive/duplicate/trash)
with a single ⋯ trigger that opens a positioned dropdown menu. Menu has full
keyboard (Escape), click-outside, scroll, and resize-reposition handling.
Position:fixed prevents sidebar clipping.

5 actions: Pin/Unpin, Move to project, Archive/Unarchive, Duplicate, Delete
(danger style). Each with icon and descriptive subtitle.

Updated test_sprint16.py: test_sessions_js_uses_action_menu_not_per_row_buttons
asserts the new trigger and menu functions exist, old per-row classes are gone.

Extracted from PR #242.

* docs: v0.47.0 release notes, bump version, update test counts (645)

---------

Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Hi @aronprins — big update since the last review. Here's a complete status of where things stand and exactly what your branch needs to get the remaining work merged.


What's already been merged (you can remove these from your branch)

Since our last comment, we extracted and merged three self-contained pieces from your PR into master. Your branch still carries all of them — rebasing will eliminate the overlap, but here's what's now in master so you can also surgically remove them if you prefer a clean rebase:

Merged in v0.47.0

Shared app dialogs (your showConfirmDialog/showPromptDialog system)
Everything from your tests/test_sprint33.py, the #appDialogOverlay HTML block, the .app-dialog-* CSS rules, and all 11 confirm()/prompt() call site replacements in panels.js, sessions.js, ui.js, workspace.js are now in master. The i18n.js keys (dialog_confirm_title, dialog_prompt_title, dialog_confirm_btn, discard, clear, create, remove, project_name_prompt) are in master for en, de, zh, and zh-Hant.

Session action dropdown
The closeSessionActionMenu(), _openSessionActionMenu(), _positionSessionActionMenu(), _buildSessionAction() functions, the ICONS additions (pin, unpin, archive, unarchive, dup, trash, more), and the session-actions-trigger/session-action-menu CSS are all in master. test_sprint16.py was updated — the old test_sessions_js_active_skips_project_border is now test_sessions_js_uses_action_menu_not_per_row_buttons.

Mobile QA regression suite
tests/test_mobile_layout.py (14 tests) is in master.


The one failing test — easy fix

Your branch currently fails 1 test:

FAILED tests/test_sprint16.py::test_sessions_js_active_skips_project_border
AssertionError: borderLeftColor not found in sessions.js

This test was already updated in master as part of the session menu merge. After rebasing onto master, the test will be gone and replaced with test_sessions_js_uses_action_menu_not_per_row_buttons which passes against your sessions.js. You don't need to do anything beyond rebase.

Quick check: after rebasing, run:

python -m pytest tests/test_sprint16.py -v --tb=short

All tests in that file should pass.


What's left to merge — the real work

After rebasing, your PR's remaining delta is the core UI redesign. This is the piece worth focusing on. Here's exactly what it contains and what it needs:

What remains (genuine new work not in master)

  1. Composer footer restructure — model selector, profile chip, workspace chip move from topbar/sidebar into the composer footer. setComposerStatus() replaces the activity bar for turn-scoped status. The circular context ring (ctx-ring) replaces the linear progress pill.

  2. Hermes Control Center — the 860px tabbed modal (Conversation / Preferences / System) replacing the old gear-icon settings panel. The sidebar bottom becomes a single "Hermes WebUI" launcher button. tests/test_sprint34.py (2 tests) verifies tab reset on close.

  3. Activity bar removal — the standalone activity bar above the composer is gone; status is rerouted through setComposerStatus() in the composer footer.

  4. Workspace panel state machine_workspacePanelMode ('closed' / 'browse' / 'preview') in boot.js, syncWorkspacePanelState(), _setWorkspacePanelMode(), and the workspace-switch guard (prompts for discard via the new dialog before switching).

  5. Icon cleanup and icons.js additionssave, chevron-right, arrow-right, pause, paperclip, copy, rotate-ccw, user added to icons.js.


Step-by-step path to merge

Step 1 — Rebase onto current master

git fetch origin
git rebase origin/master

This will pick up all the merged pieces (dialogs, session menu, mobile tests, the mobile overlay fix, the profile dropdown fix). There should be zero conflicts — we verified with git merge-tree and got clean. If anything conflicts, it will be in the overlapping areas (sessions.js, ui.js, style.css) and the resolution is almost always "keep both, yours on top."

After rebasing, run:

python -m pytest tests/ -q --tb=short 2>&1 | tail -5
# Should show: 645 passed (or more with your test_sprint34.py additions)

Step 2 — Fix the three remaining issues

These were flagged in the original review comment and are still needed:

2a. Profile dropdown max-width guard
In the composer footer, .profile-dropdown (the one positioned relative to the composer, not the topbar) is missing a viewport width constraint. The workspace dropdown already has max-width: min(420px, calc(100vw - 32px)). Add the same to .profile-dropdown in your CSS:

.profile-dropdown {
    /* existing rules... */
    max-width: min(260px, calc(100vw - 32px));
}

Without this, on very narrow viewports the 260px dropdown can clip off the right edge of the screen.

2b. t('create') i18n key
This was already added to master as part of the dialog merge (it's in all 4 locales). After rebasing you'll have it automatically — just verify t('create') resolves to 'Create' in English rather than falling back to the key string.

2c. test_sprint33.py will conflict or duplicate
After rebase, tests/test_sprint33.py in your branch and master will be identical content. Git may auto-resolve this. Verify it's not duplicated. If rebase gives you a conflict there, just accept master's version — it's the same file.

Step 3 — Mobile QA pass (the most important new requirement)

We've added a mobile regression test suite (tests/test_mobile_layout.py) but there's no automated browser testing of the composer footer at mobile widths. Your PR moves the model/profile/workspace chips into the composer, which is a significant layout change. We need you to do (or document) a manual mobile QA pass specifically for:

375px viewport (iPhone SE / smallest common phone):

  • Is the composer footer visible and usable? Can the user tap model/profile/workspace chips?
  • Do the composer chips scroll horizontally (via overflow-x:auto) without breaking the layout?
  • Does the profile dropdown open fully visible (not clipped) when tapped from inside the composer footer? (This is different from the topbar dropdown — the composer footer may have different overflow context)
  • After scrolling a long conversation, can the user still reach the composer footer and its chips?

414px viewport (iPhone 12/13):

  • Same as above — the wider phone is usually fine, but verify

Suggested approach: Open the browser at http://localhost:8787, use DevTools or browser responsive mode to set 375px width, test all three dropdowns (model, profile, workspace) in the composer footer.

If any of these fail, add CSS at @media(max-width:640px) to handle them. The pattern we used for the topbar profile dropdown (position:fixed; top:56px; right:8px) can be adapted for composer footer dropdowns — they'd need position:fixed; bottom:calc(70px + env(safe-area-inset-bottom)); left:8px or similar.

Step 4 — Run the full gate

# Full test suite (must be 645+ passed, 0 failed)
fuser -k 8788/tcp 2>/dev/null; sleep 1
python -m pytest tests/ -q --tb=short

# QA harness (if you have the private qa/ tests)
# If not, skip — we run this gate before merging

# Browser sanity — desktop:
# - Load app, new session, 3 messages, all sidebar panels
# - Open the Control Center (sidebar launcher button)
# - Switch tabs: Conversation / Preferences / System
# - Close and reopen — verify it resets to Conversation tab
# - Check the gear icon is gone from topbar
# - Verify model/profile/workspace chips are in composer footer
# - Click each — verify dropdowns open and work

# Zero JS console errors throughout

Suggested approach: merge whole vs. split

Given that the remaining work is a cohesive set of interconnected changes (you can't easily ship the Control Center without also shipping the "launcher" button that replaced the gear, and you can't remove the activity bar without setComposerStatus() being in place), we recommend merging whole once the above steps are done.

The only real complexity is the mobile composer footer QA — everything else is clean, tested, and architecturally sound based on our earlier audit.

If you'd rather split further, the cleanest seam would be:

  • Chunk A (lower risk): workspace panel state machine + icons.js additions + test_sprint34.py — these don't touch the topbar or composer layout
  • Chunk B (main PR): composer footer restructure + Control Center + activity bar removal

But splitting at this point would create significant merge complexity since the Control Center and composer chips share CSS tokens and the boot.js state machine. Merging whole after the mobile QA pass is cleaner.


Summary of what to do

  1. git rebase origin/master — picks up all merged pieces, resolves the failing test
  2. Fix the profile dropdown max-width guard in the composer footer CSS
  3. Do a 375px mobile browser pass on the composer footer (chips, dropdowns, scroll)
  4. Run python -m pytest tests/ -q — should be 645+ passed, 0 failed
  5. Push and let us know — we'll run the full gate (pytest + QA harness + browser sanity) before merging

The code quality in this PR is genuinely solid. We're looking forward to getting the full Control Center experience merged.

@aronprins
aronprins force-pushed the feat/ui-improvements-round1 branch from 415787b to 4333303 Compare April 11, 2026 19:35
@aronprins aronprins closed this Apr 12, 2026
@aronprins
aronprins deleted the feat/ui-improvements-round1 branch April 12, 2026 08:07
aronprins and others added 14 commits April 12, 2026 10:14
Move the model selector into the composer footer, replace the linear context pill with a compact circular badge plus tooltip, and remove the redundant topbar model pill.

Design credit and inspiration: Theo / T3 Code.
Reference implementation: https://github.com/pingdotgg/t3code/
Drop the old activity bar, keep turn-scoped state in the composer footer, and route remaining non-chat status messages through toasts.

This leaves live tool cards and the message timeline as the primary progress UI, with the composer owning stop/cancel and brief turn status.
Widen the modal to 860px, simplify the tab list to icon+label rows,
stretch the tab column's divider to full height, lock the panel to a
fixed height so switching tabs no longer resizes the outer shell, and
always open on the Conversation tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the left-border accent used for active, CLI, and project rows —
each state already has a dedicated cue (gold fill, cli badge, project
dot), so the border was redundant. Fully round the row, add 2px
bottom spacing between rows, and strip the matching JS/CSS overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Snap padding, gap, and border-radius values to the 2/4/6/8/10/12 grid
across composer chips, sidebar panels, cron list, settings, approval
buttons, dropdowns, and inline message edit — eliminating the 7/9/11px
drift that was making sibling elements feel subtly misaligned.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ile QA suite)

The mobile layout regression suite (test_mobile_layout.py) requires:
- #btnMobileFiles onclick=toggleMobileFiles() in topbar chips
- .mobile-files-btn CSS rules for responsive show/hide at 640/900px breakpoints

Also adds max-width guard to .profile-dropdown to prevent clipping at narrow viewports.
@aronprins
aronprins restored the feat/ui-improvements-round1 branch April 12, 2026 08:17
@aronprins

Copy link
Copy Markdown
Contributor Author

Still working on this - closed accidentally <3

@aronprins aronprins reopened this Apr 12, 2026
aronprins and others added 8 commits April 12, 2026 10:38
- Collapse composer chips to icon-only at <=400px viewports
- Add model chip icon (CPU) so it remains tappable when labels are hidden
- Show send button always (disabled state when empty, hidden during streaming)
- Show context usage indicator on session load, not just after streaming
- Add cancel status fallback timeout to prevent stale "Cancelling..." text
- Update tests to match new send button and busy state behavior
Remove redundant #btnMobileFiles button that duplicated #btnWorkspacePanelToggle
in the mobile topbar. Fix workspace panel close button calling undefined
closeMobileFiles() — now calls closeWorkspacePanel().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove mobile-files-btn class from #btnWorkspacePanelToggle — its
display:none!important rule was overriding workspace-toggle-btn visibility
on non-mobile viewports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Always show the session actions trigger on mobile (no hover state on
touch devices) and restore right padding so text truncates with
ellipsis before the dots icon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The "Manage profiles" and "Manage workspaces" links in the composer
footer dropdowns called switchPanel() which only changes the active
panel content but doesn't open the sidebar. Replaced with
mobileSwitchPanel() which also opens the sidebar so the panel is
actually visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the icon-only chip styling up into the existing max-width:768px
media query so chips collapse to icon-only on tablets too, preventing
composer footer overflow on mid-size screens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When overflow-x is set to auto, the CSS spec implicitly changes
overflow-y from visible to auto, allowing a vertical scrollbar to
appear from slight chip padding/border overflow. Explicitly set
overflow-y:hidden to prevent this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aronprins
aronprins force-pushed the feat/ui-improvements-round1 branch from 4333303 to ef015db Compare April 12, 2026 09:13
@aronprins

Copy link
Copy Markdown
Contributor Author

All reviewer feedback has been addressed. Latest push includes two additional fixes:

  1. Icon-only composer chips at 768px — moved the icon-only chip breakpoint from 400px up to 768px so chips collapse earlier, preventing composer footer overflow on mid-size screens.
  2. Composer-left vertical scrollbar fix — added overflow-y: hidden to .composer-left to prevent an unintended vertical scrollbar (CSS spec implicitly sets overflow-y: auto when overflow-x is non-visible).

Ready for review 🙏

@nesquena

Copy link
Copy Markdown
Owner

Full Independent Review: PR #242 — UI refresh (rebased on pr-242-review)

Complete end-to-end review: rebased onto latest master, resolved all conflicts, ran full test suite, security audit, code review.


Rebase Status

Successfully rebased all 23 commits onto current master (7556ea0). Resolved 4 conflicts:

  1. static/workspace.js — kept master's renderFileBreadcrumb() function (added after the PR branched)
  2. static/boot.js — kept both: master's breadcrumb render call + PR's workspace panel state management (closeWorkspacePanel/syncWorkspacePanelUI)
  3. static/index.html — PR removes the sidebar header (replaced by control center launcher); resolved by accepting PR's intent
  4. tests/test_sprint34.py — add/add conflict (master has OAuth tests, PR has control center tests). Kept both. Fixed test assertions to match actual implementation (_settingsSection not _controlSection, settings-tabs not cc-tab)

Test Results

677 passed, 0 failed, 48 skipped — clean run.

Security Audit

Clean. Reviewed all innerHTML assignments across the diff:

  • static/ui.js: all user data passed through esc(). Icon calls use static li() SVG strings.
  • static/panels.js: static HTML strings only, no user data in innerHTML
  • static/sessions.js: user data (session.title, project.name) passed through esc()
  • static/messages.js: consistent with existing patterns
  • static/boot.js: no innerHTML with user data
  • No new external resources (CDNs, fonts, URLs)
  • No eval, exec, document.write, or shell injection patterns
  • Profile dropdown has max-width: min(260px, calc(100vw - 32px)) guard — viewport overflow issue addressed

Code Review

What this PR adds (after rebase drops already-merged work):

  1. Composer footer restructure — model selector, profile chip, workspace chip move from topbar into composer footer. setComposerStatus() replaces standalone activity bar. Circular context ring (ctx-ring) replaces linear progress pill. Well-implemented with overflow-x:auto on the chip container for mobile scrolling.

  2. Hermes Control Center — 860px tabbed modal with Conversation / Preferences / System sections, replacing the old gear-icon settings panel. _settingsSection state machine with switchSettingsSection(). Clean tab navigation with ARIA roles. _resetSettingsPanelState() correctly resets to 'conversation' on close.

  3. Workspace panel state machine_workspacePanelMode (closed/browse/preview) in boot.js with _setWorkspacePanelMode() and syncWorkspacePanelState(). Handles the close-preview-on-navigate and discard-unsaved-on-switch flows correctly.

  4. Icon additionssave, chevron-right, arrow-right, pause, paperclip, copy, rotate-ccw, user added to icons.js. Consistent with the existing li() pattern.

  5. i18n additions — 6 new keys across en/de/zh/zh-Hant for control center sections.

No issues found. The code is clean, well-structured, and consistent with the codebase style.

What Needs Manual Browser Testing

The automated test suite can't verify visual layout. An agent or human should verify:

  • Composer footer renders correctly at desktop width (chips inline, context ring visible)
  • Composer footer at 768px (chips collapse to icon-only mode)
  • Composer footer at 375px (chips scroll horizontally, no overflow)
  • Control center opens/closes correctly (tabbed layout, section switching)
  • Control center: Escape closes, backdrop click closes
  • Workspace panel state transitions: closed → browse → preview → closed
  • Profile dropdown at mobile widths (position:fixed, not clipped)
  • No JS console errors during normal use

Review Branch

Branch: pr-242-review on origin

Contains all 23 original commits rebased onto latest master + 1 fix commit for test assertions. This is the branch to merge (or apply these changes back to Aaron's fork branch).

Verdict

Approved pending browser QA. The code is clean, tests pass, security is good. The main risk is layout regressions at mobile widths from the composer restructure — that needs visual verification that automated tests can't provide.

@nesquena

Copy link
Copy Markdown
Owner

Second sweep complete — pr-242-review updated

Re-rebased onto latest master (28354a9, v0.49.4), resolved 3 new conflicts from recent merges, re-ran full test suite.

Rebase conflicts resolved (this pass)

  1. boot.js cancel function (commit 4/24) — master added guaranteed-cleanup pattern; PR uses setComposerStatus. Merged: kept master's guaranteed cleanup with setComposerStatus fallback.
  2. index.html sidebar header (commit 8/24) — same as before, PR removes header for control center launcher.
  3. boot.js mobile responsiveness (commit 16/24) — another cancel-function conflict from master's latest cancel cleanup merge. Same resolution: guaranteed cleanup + setComposerStatus.

Test Results

686 passed, 0 failed, 48 skipped. +2 from last sweep (new tests merged to master).

Second-pass verification

  • All critical functions verified present: toggleSettings, renderMessages, send, loadSession, renderSessionList, loadDir, populateModelDropdown, showApprovalCard, hideApprovalCard, showToast, setStatus, setBusy, syncTopbar, toggleMobileSidebar, closeMobileSidebar, toggleMobileFiles
  • CSS brace balance: 774/774 (perfect)
  • No leftover conflict markers in any file
  • All PR features confirmed present: composer footer (5 CSS rules), setComposerStatus (2 refs), workspace state machine (10 refs), context ring (10 CSS rules), control center tabs (3 refs)
  • i18n keys all resolve correctly
  • Key test files all pass: test_sprint34 (21 pass), test_regressions, test_sprint16, test_mobile_layout

Branch

pr-242-review on origin — 24 commits ahead of master, force-pushed with latest rebase. Ready for browser QA and merge.

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Merge ready — pr-242-review branch

Full end-to-end review complete. Merging via pr-242-review (26 commits, rebased onto current master v0.49.4).

Review summary:

  • Code review: clean — all innerHTML uses esc(), setComposerStatus uses textContent, no XSS vectors, CSS balanced 774/774
  • Security: no new eval/document.write, no CDN additions, no shell injection patterns
  • Tests: 742/742 pass (all passing, zero flaky)
  • Theme sweep: all 7 themes (Dark/Light/Slate/Solarized/Monokai/Nord/OLED) render correctly
  • Browser QA: 16 checks — all pass, zero JS errors throughout
    • Desktop layout, composer chips with labels, icon-only at ≤640px
    • Control Center: open/tabs/ESC/backdrop-close/reset
    • Workspace panel state machine: closed→browse→preview→closed with breadcrumb
    • Profile dropdown viewport guard confirmed
    • Session ⋯ dropdown: all options, ESC+click-outside close
    • All sidebar panels, settings save, concurrent chat, CSP inline handlers

One fix pushed to branch: version badge in System tab v0.45.1v0.50.0.

README and CHANGELOG updated for v0.50.0. Ready to merge.

nesquena-hermes pushed a commit that referenced this pull request Apr 12, 2026
Major UI overhaul by @aronprins, rebased and reviewed on pr-242-review.

- Composer becomes control hub: model/profile/workspace chips in footer
- Hermes Control Center replaces gear settings modal (tabbed, 3 sections)
- Activity bar removed; status inline in composer footer
- Session ⋯ dropdown replaces inline pin/archive/trash buttons
- Workspace panel state machine (closed/browse/preview)
- Circular context ring (token count, cost, % used)
- OLED theme (7th built-in theme)
- Mobile: icon-only chips at ≤640px, composer overflow-x:auto
- 742 tests pass; README + CHANGELOG updated for v0.50.0

Co-authored-by: Aron Prins <pwf.aron@gmail.com>
nesquena-hermes added a commit that referenced this pull request Apr 12, 2026
…loses #242)

* Polish workspace panel behavior and app dialogs

* Replace remaining emoji UI glyphs with Lucide icons

* Redesign composer footer around model and context controls

Move the model selector into the composer footer, replace the linear context pill with a compact circular badge plus tooltip, and remove the redundant topbar model pill.

Design credit and inspiration: Theo / T3 Code.
Reference implementation: https://github.com/pingdotgg/t3code/

* Remove obsolete activity bar

Drop the old activity bar, keep turn-scoped state in the composer footer, and route remaining non-chat status messages through toasts.

This leaves live tool cards and the message timeline as the primary progress UI, with the composer owning stop/cancel and brief turn status.

* Move workspace and model switching into composer footer

* Move profile switching into composer footer

* Refactor Hermes control center UI

* Redesign control center settings modal layout

Widen the modal to 860px, simplify the tab list to icon+label rows,
stretch the tab column's divider to full height, lock the panel to a
fixed height so switching tabs no longer resizes the outer shell, and
always open on the Conversation tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Put session item actions in a dropdown

* Use Hermes mark in sidebar control button

* Reset control center section on close

* Drop session-item left border indicator

Remove the left-border accent used for active, CLI, and project rows —
each state already has a dedicated cue (gold fill, cli badge, project
dot), so the border was redundant. Fully round the row, add 2px
bottom spacing between rows, and strip the matching JS/CSS overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Increase session search input vertical padding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Normalise odd pixel values across UI

Snap padding, gap, and border-radius values to the 2/4/6/8/10/12 grid
across composer chips, sidebar panels, cron list, settings, approval
buttons, dropdowns, and inline message edit — eliminating the 7/9/11px
drift that was making sibling elements feel subtly misaligned.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add missing #btnMobileFiles button and .mobile-files-btn CSS (for mobile QA suite)

The mobile layout regression suite (test_mobile_layout.py) requires:
- #btnMobileFiles onclick=toggleMobileFiles() in topbar chips
- .mobile-files-btn CSS rules for responsive show/hide at 640/900px breakpoints

Also adds max-width guard to .profile-dropdown to prevent clipping at narrow viewports.

* Improve composer footer mobile responsiveness and UX

- Collapse composer chips to icon-only at <=400px viewports
- Add model chip icon (CPU) so it remains tappable when labels are hidden
- Show send button always (disabled state when empty, hidden during streaming)
- Show context usage indicator on session load, not just after streaming
- Add cancel status fallback timeout to prevent stale "Cancelling..." text
- Update tests to match new send button and busy state behavior

* Fix duplicate files button and broken workspace close on mobile

Remove redundant #btnMobileFiles button that duplicated #btnWorkspacePanelToggle
in the mobile topbar. Fix workspace panel close button calling undefined
closeMobileFiles() — now calls closeWorkspacePanel().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix model chip icon vertical alignment in composer footer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix workspace toggle button hidden on desktop by conflicting CSS class

Remove mobile-files-btn class from #btnWorkspacePanelToggle — its
display:none!important rule was overriding workspace-toggle-btn visibility
on non-mobile viewports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix session actions dots button inaccessible on mobile sidebar

Always show the session actions trigger on mobile (no hover state on
touch devices) and restore right padding so text truncates with
ellipsis before the dots icon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix composer footer manage links not opening sidebar panel

The "Manage profiles" and "Manage workspaces" links in the composer
footer dropdowns called switchPanel() which only changes the active
panel content but doesn't open the sidebar. Replaced with
mobileSwitchPanel() which also opens the sidebar so the panel is
actually visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Widen icon-only composer chips breakpoint from 400px to 768px

Move the icon-only chip styling up into the existing max-width:768px
media query so chips collapse to icon-only on tablets too, preventing
composer footer overflow on mid-size screens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix composer-left vertical scrollbar by setting overflow-y:hidden

When overflow-x is set to auto, the CSS spec implicitly changes
overflow-y from visible to auto, allowing a vertical scrollbar to
appear from slight chip padding/border overflow. Explicitly set
overflow-y:hidden to prevent this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve rebase conflicts and fix control center test assertions

- Resolved 4 conflicts during rebase onto master (workspace.js,
  boot.js, index.html, test_sprint34.py)
- Fixed test_sprint34.py: _controlSection -> _settingsSection,
  cc-tab -> settings-tabs (matching actual implementation)
- Fixed quoting syntax error in test assertion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update version badge in System tab to v0.49.4

* docs: update README and CHANGELOG for v0.50.0 UI refresh, bump version badge

---------

Co-authored-by: Aron Prins <pwf.aron@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

🎉 Merged — thank you, @aronprins!

v0.50.0 is live. Your UI overhaul is the biggest single contribution to the project and it shows — the composer footer layout, the Control Center, the context ring, the session menu, the workspace state machine. It's genuinely a better product because of this work.

We've added a Contributors section to the README that calls out your contribution specifically. We'd love to see more PRs from you.

JKJameson pushed a commit to JKJameson/hermes-webui that referenced this pull request Apr 25, 2026
* fix: custom provider with slash model name no longer rerouted to OpenRouter (nesquena#255)

When base_url is configured in config.yaml, resolve_model_provider() now
trusts the configured provider/base_url entirely and skips the slash-based
OpenRouter heuristic. Fixes google/gemma-4-26b-a4b with provider:custom
being silently routed to OpenRouter, resulting in 401 errors.

Fixes nesquena#230

* test: mobile layout regression suite — 14 tests for every QA run (nesquena#254)

Adds tests/test_mobile_layout.py with 14 static regression tests that run
on every QA pass to catch mobile layout breakage before it reaches prod.
Covers: breakpoints at 900px/640px, right panel slide-over CSS, mobile
overlay, bottom nav, files button, profile dropdown z-index, chip overflow,
workspace close, 100dvh, 44px touch targets, 16px font-size on textarea.

* feat: /skills slash command lists and filters available Hermes skills (nesquena#257)

Adds /skills [query] command to commands.js. Fetches from /api/skills,
groups by category (alphabetically sorted), displays as a formatted
assistant message. Optional query filters by name, description, or category.
i18n keys added for en, de, zh, zh-Hant. 1 regression test added.

Fixes nesquena#248

* feat: shared app dialogs replace native confirm()/prompt() calls (nesquena#251)

Adds showConfirmDialog() and showPromptDialog() helpers to ui.js, backed
by a themed #appDialogOverlay. Replaces all 11 native browser confirm/prompt
call sites across panels.js, sessions.js, ui.js, workspace.js.

Supports: danger mode, keyboard focus trap (Tab/Escape/Enter), focus restore,
ARIA roles, mobile-responsive stacked buttons at 640px. i18n for en/de/zh/zh-Hant.
5 new tests in test_sprint33.py verify markup, CSS, helpers, and absence of
native dialog calls.

Extracted from PR nesquena#242.

* fix: Android Chrome mobile — workspace panel close + profile dropdown (nesquena#256)

Fix nesquena#247: toggleMobileFiles() now shows/hides the mobile overlay when
toggling the right workspace panel. New closeMobileFiles() helper closes
the panel with correct overlay state tracking. Overlay onclick calls both
closeMobileSidebar() and closeMobileFiles(). Mobile-only close button (x)
added to workspace panel header.

Fix nesquena#246: profile dropdown uses position:fixed;top:56px;right:8px at
max-width:900px, escaping the overflow-x:auto stacking context that was
clipping it on Android Chrome.

Fix applied during review: closeMobileSidebar() now checks if the right
panel is still open before hiding the overlay, preventing the overlay from
disappearing when only the sidebar is closed.

Fixes nesquena#247 Fixes nesquena#246

* feat: session ⋯ action dropdown replaces per-row buttons (nesquena#252)

Replaces the 5 per-row hover action buttons (pin/move/archive/duplicate/trash)
with a single ⋯ trigger that opens a positioned dropdown menu. Menu has full
keyboard (Escape), click-outside, scroll, and resize-reposition handling.
Position:fixed prevents sidebar clipping.

5 actions: Pin/Unpin, Move to project, Archive/Unarchive, Duplicate, Delete
(danger style). Each with icon and descriptive subtitle.

Updated test_sprint16.py: test_sessions_js_uses_action_menu_not_per_row_buttons
asserts the new trigger and menu functions exist, old per-row classes are gone.

Extracted from PR nesquena#242.

* docs: v0.47.0 release notes, bump version, update test counts (645)

---------

Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
JKJameson pushed a commit to JKJameson/hermes-webui that referenced this pull request Apr 25, 2026
…loses nesquena#242)

* Polish workspace panel behavior and app dialogs

* Replace remaining emoji UI glyphs with Lucide icons

* Redesign composer footer around model and context controls

Move the model selector into the composer footer, replace the linear context pill with a compact circular badge plus tooltip, and remove the redundant topbar model pill.

Design credit and inspiration: Theo / T3 Code.
Reference implementation: https://github.com/pingdotgg/t3code/

* Remove obsolete activity bar

Drop the old activity bar, keep turn-scoped state in the composer footer, and route remaining non-chat status messages through toasts.

This leaves live tool cards and the message timeline as the primary progress UI, with the composer owning stop/cancel and brief turn status.

* Move workspace and model switching into composer footer

* Move profile switching into composer footer

* Refactor Hermes control center UI

* Redesign control center settings modal layout

Widen the modal to 860px, simplify the tab list to icon+label rows,
stretch the tab column's divider to full height, lock the panel to a
fixed height so switching tabs no longer resizes the outer shell, and
always open on the Conversation tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Put session item actions in a dropdown

* Use Hermes mark in sidebar control button

* Reset control center section on close

* Drop session-item left border indicator

Remove the left-border accent used for active, CLI, and project rows —
each state already has a dedicated cue (gold fill, cli badge, project
dot), so the border was redundant. Fully round the row, add 2px
bottom spacing between rows, and strip the matching JS/CSS overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Increase session search input vertical padding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Normalise odd pixel values across UI

Snap padding, gap, and border-radius values to the 2/4/6/8/10/12 grid
across composer chips, sidebar panels, cron list, settings, approval
buttons, dropdowns, and inline message edit — eliminating the 7/9/11px
drift that was making sibling elements feel subtly misaligned.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add missing #btnMobileFiles button and .mobile-files-btn CSS (for mobile QA suite)

The mobile layout regression suite (test_mobile_layout.py) requires:
- #btnMobileFiles onclick=toggleMobileFiles() in topbar chips
- .mobile-files-btn CSS rules for responsive show/hide at 640/900px breakpoints

Also adds max-width guard to .profile-dropdown to prevent clipping at narrow viewports.

* Improve composer footer mobile responsiveness and UX

- Collapse composer chips to icon-only at <=400px viewports
- Add model chip icon (CPU) so it remains tappable when labels are hidden
- Show send button always (disabled state when empty, hidden during streaming)
- Show context usage indicator on session load, not just after streaming
- Add cancel status fallback timeout to prevent stale "Cancelling..." text
- Update tests to match new send button and busy state behavior

* Fix duplicate files button and broken workspace close on mobile

Remove redundant #btnMobileFiles button that duplicated #btnWorkspacePanelToggle
in the mobile topbar. Fix workspace panel close button calling undefined
closeMobileFiles() — now calls closeWorkspacePanel().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix model chip icon vertical alignment in composer footer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix workspace toggle button hidden on desktop by conflicting CSS class

Remove mobile-files-btn class from #btnWorkspacePanelToggle — its
display:none!important rule was overriding workspace-toggle-btn visibility
on non-mobile viewports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix session actions dots button inaccessible on mobile sidebar

Always show the session actions trigger on mobile (no hover state on
touch devices) and restore right padding so text truncates with
ellipsis before the dots icon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix composer footer manage links not opening sidebar panel

The "Manage profiles" and "Manage workspaces" links in the composer
footer dropdowns called switchPanel() which only changes the active
panel content but doesn't open the sidebar. Replaced with
mobileSwitchPanel() which also opens the sidebar so the panel is
actually visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Widen icon-only composer chips breakpoint from 400px to 768px

Move the icon-only chip styling up into the existing max-width:768px
media query so chips collapse to icon-only on tablets too, preventing
composer footer overflow on mid-size screens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix composer-left vertical scrollbar by setting overflow-y:hidden

When overflow-x is set to auto, the CSS spec implicitly changes
overflow-y from visible to auto, allowing a vertical scrollbar to
appear from slight chip padding/border overflow. Explicitly set
overflow-y:hidden to prevent this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve rebase conflicts and fix control center test assertions

- Resolved 4 conflicts during rebase onto master (workspace.js,
  boot.js, index.html, test_sprint34.py)
- Fixed test_sprint34.py: _controlSection -> _settingsSection,
  cc-tab -> settings-tabs (matching actual implementation)
- Fixed quoting syntax error in test assertion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update version badge in System tab to v0.49.4

* docs: update README and CHANGELOG for v0.50.0 UI refresh, bump version badge

---------

Co-authored-by: Aron Prins <pwf.aron@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
SysAdminDoc pushed a commit to SysAdminDoc/hermes-webui that referenced this pull request Jun 26, 2026
* fix: custom provider with slash model name no longer rerouted to OpenRouter (nesquena#255)

When base_url is configured in config.yaml, resolve_model_provider() now
trusts the configured provider/base_url entirely and skips the slash-based
OpenRouter heuristic. Fixes google/gemma-4-26b-a4b with provider:custom
being silently routed to OpenRouter, resulting in 401 errors.

Fixes nesquena#230

* test: mobile layout regression suite — 14 tests for every QA run (nesquena#254)

Adds tests/test_mobile_layout.py with 14 static regression tests that run
on every QA pass to catch mobile layout breakage before it reaches prod.
Covers: breakpoints at 900px/640px, right panel slide-over CSS, mobile
overlay, bottom nav, files button, profile dropdown z-index, chip overflow,
workspace close, 100dvh, 44px touch targets, 16px font-size on textarea.

* feat: /skills slash command lists and filters available Hermes skills (nesquena#257)

Adds /skills [query] command to commands.js. Fetches from /api/skills,
groups by category (alphabetically sorted), displays as a formatted
assistant message. Optional query filters by name, description, or category.
i18n keys added for en, de, zh, zh-Hant. 1 regression test added.

Fixes nesquena#248

* feat: shared app dialogs replace native confirm()/prompt() calls (nesquena#251)

Adds showConfirmDialog() and showPromptDialog() helpers to ui.js, backed
by a themed #appDialogOverlay. Replaces all 11 native browser confirm/prompt
call sites across panels.js, sessions.js, ui.js, workspace.js.

Supports: danger mode, keyboard focus trap (Tab/Escape/Enter), focus restore,
ARIA roles, mobile-responsive stacked buttons at 640px. i18n for en/de/zh/zh-Hant.
5 new tests in test_sprint33.py verify markup, CSS, helpers, and absence of
native dialog calls.

Extracted from PR nesquena#242.

* fix: Android Chrome mobile — workspace panel close + profile dropdown (nesquena#256)

Fix nesquena#247: toggleMobileFiles() now shows/hides the mobile overlay when
toggling the right workspace panel. New closeMobileFiles() helper closes
the panel with correct overlay state tracking. Overlay onclick calls both
closeMobileSidebar() and closeMobileFiles(). Mobile-only close button (x)
added to workspace panel header.

Fix nesquena#246: profile dropdown uses position:fixed;top:56px;right:8px at
max-width:900px, escaping the overflow-x:auto stacking context that was
clipping it on Android Chrome.

Fix applied during review: closeMobileSidebar() now checks if the right
panel is still open before hiding the overlay, preventing the overlay from
disappearing when only the sidebar is closed.

Fixes nesquena#247 Fixes nesquena#246

* feat: session ⋯ action dropdown replaces per-row buttons (nesquena#252)

Replaces the 5 per-row hover action buttons (pin/move/archive/duplicate/trash)
with a single ⋯ trigger that opens a positioned dropdown menu. Menu has full
keyboard (Escape), click-outside, scroll, and resize-reposition handling.
Position:fixed prevents sidebar clipping.

5 actions: Pin/Unpin, Move to project, Archive/Unarchive, Duplicate, Delete
(danger style). Each with icon and descriptive subtitle.

Updated test_sprint16.py: test_sessions_js_uses_action_menu_not_per_row_buttons
asserts the new trigger and menu functions exist, old per-row classes are gone.

Extracted from PR nesquena#242.

* docs: v0.47.0 release notes, bump version, update test counts (645)

---------

Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
SysAdminDoc pushed a commit to SysAdminDoc/hermes-webui that referenced this pull request Jun 26, 2026
…loses nesquena#242)

* Polish workspace panel behavior and app dialogs

* Replace remaining emoji UI glyphs with Lucide icons

* Redesign composer footer around model and context controls

Move the model selector into the composer footer, replace the linear context pill with a compact circular badge plus tooltip, and remove the redundant topbar model pill.

Design credit and inspiration: Theo / T3 Code.
Reference implementation: https://github.com/pingdotgg/t3code/

* Remove obsolete activity bar

Drop the old activity bar, keep turn-scoped state in the composer footer, and route remaining non-chat status messages through toasts.

This leaves live tool cards and the message timeline as the primary progress UI, with the composer owning stop/cancel and brief turn status.

* Move workspace and model switching into composer footer

* Move profile switching into composer footer

* Refactor Hermes control center UI

* Redesign control center settings modal layout

Widen the modal to 860px, simplify the tab list to icon+label rows,
stretch the tab column's divider to full height, lock the panel to a
fixed height so switching tabs no longer resizes the outer shell, and
always open on the Conversation tab.


* Put session item actions in a dropdown

* Use Hermes mark in sidebar control button

* Reset control center section on close

* Drop session-item left border indicator

Remove the left-border accent used for active, CLI, and project rows —
each state already has a dedicated cue (gold fill, cli badge, project
dot), so the border was redundant. Fully round the row, add 2px
bottom spacing between rows, and strip the matching JS/CSS overrides.


* Increase session search input vertical padding


* Normalise odd pixel values across UI

Snap padding, gap, and border-radius values to the 2/4/6/8/10/12 grid
across composer chips, sidebar panels, cron list, settings, approval
buttons, dropdowns, and inline message edit — eliminating the 7/9/11px
drift that was making sibling elements feel subtly misaligned.


* Add missing #btnMobileFiles button and .mobile-files-btn CSS (for mobile QA suite)

The mobile layout regression suite (test_mobile_layout.py) requires:
- #btnMobileFiles onclick=toggleMobileFiles() in topbar chips
- .mobile-files-btn CSS rules for responsive show/hide at 640/900px breakpoints

Also adds max-width guard to .profile-dropdown to prevent clipping at narrow viewports.

* Improve composer footer mobile responsiveness and UX

- Collapse composer chips to icon-only at <=400px viewports
- Add model chip icon (CPU) so it remains tappable when labels are hidden
- Show send button always (disabled state when empty, hidden during streaming)
- Show context usage indicator on session load, not just after streaming
- Add cancel status fallback timeout to prevent stale "Cancelling..." text
- Update tests to match new send button and busy state behavior

* Fix duplicate files button and broken workspace close on mobile

Remove redundant #btnMobileFiles button that duplicated #btnWorkspacePanelToggle
in the mobile topbar. Fix workspace panel close button calling undefined
closeMobileFiles() — now calls closeWorkspacePanel().


* Fix model chip icon vertical alignment in composer footer


* Fix workspace toggle button hidden on desktop by conflicting CSS class

Remove mobile-files-btn class from #btnWorkspacePanelToggle — its
display:none!important rule was overriding workspace-toggle-btn visibility
on non-mobile viewports.


* Fix session actions dots button inaccessible on mobile sidebar

Always show the session actions trigger on mobile (no hover state on
touch devices) and restore right padding so text truncates with
ellipsis before the dots icon.


* Fix composer footer manage links not opening sidebar panel

The "Manage profiles" and "Manage workspaces" links in the composer
footer dropdowns called switchPanel() which only changes the active
panel content but doesn't open the sidebar. Replaced with
mobileSwitchPanel() which also opens the sidebar so the panel is
actually visible.


* Widen icon-only composer chips breakpoint from 400px to 768px

Move the icon-only chip styling up into the existing max-width:768px
media query so chips collapse to icon-only on tablets too, preventing
composer footer overflow on mid-size screens.


* Fix composer-left vertical scrollbar by setting overflow-y:hidden

When overflow-x is set to auto, the CSS spec implicitly changes
overflow-y from visible to auto, allowing a vertical scrollbar to
appear from slight chip padding/border overflow. Explicitly set
overflow-y:hidden to prevent this.


* fix: resolve rebase conflicts and fix control center test assertions

- Resolved 4 conflicts during rebase onto master (workspace.js,
  boot.js, index.html, test_sprint34.py)
- Fixed test_sprint34.py: _controlSection -> _settingsSection,
  cc-tab -> settings-tabs (matching actual implementation)
- Fixed quoting syntax error in test assertion


* fix: update version badge in System tab to v0.49.4

* docs: update README and CHANGELOG for v0.50.0 UI refresh, bump version badge

---------

Co-authored-by: Aron Prins <pwf.aron@gmail.com>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants