Place the Qwen brand mark to the left of the sidebar's New chat button.
The artwork is the same SVG used for the browser-tab favicon (and the
QwenLM GitHub avatar), inlined rather than hot-linked because the Web
Shell CSP is `img-src 'self' data: blob:`, which blocks remote images.
When the sidebar is collapsed there is no room beside the compact
button, so the mark is hidden and only the New chat button remains.
Add an Archive quick action and a "..." overflow menu (Rename / Archive / Delete) to each session row in the web-shell sidebar, plus a collapsible "Archived" section that lazily lists archived sessions with Restore / Delete. Thread the daemon's existing archiveState filter and archive/unarchive endpoints through the webui workspace facade and the useDaemonSessions hook; rename stays limited to the current live session.
* feat(web-shell): show the qwen-code version in the sidebar footer
The Web Shell had no visible version. Show the running qwen-code version (from the daemon capabilities) in the sidebar footer, inline with the Settings button so it stays visible without taking its own row.
Render the version consistently wherever it appears:
- Prefix "v" only for a real semver release; a non-semver fallback such as "unknown" is shown as-is, so we never render a bogus "vunknown". Applied to the Web Shell badge and the TUI header.
- Dev builds (scripts/dev.js) now report the real package version instead of the "dev" sentinel, matching scripts/start.js, so the UI shows the actual version (e.g. v0.19.4). DEV=true / NODE_ENV=development remain the signals that mark a dev build.
* test: add readFileSync to node:fs mock in dev.test.js
scripts/dev.js now reads package.json via readFileSync at module load to
report the real CLI_VERSION, but the node:fs mock in dev.test.js did not
export readFileSync, causing vitest to throw "No readFileSync export is
defined on the node:fs mock" and failing the suite.
* feat(web-shell): add mobile sidebar drawer with session list
Replace the display:none behavior at viewport <=760px with an overlay
drawer pattern. A hamburger menu button appears on mobile, tapping it
slides the existing WebShellSidebar in as a fixed overlay with a
semi-transparent backdrop. Selecting or creating a session auto-closes
the drawer. Desktop layout (>=761px) is unaffected.
Closes#6000
* fix(web-shell): address review feedback for mobile sidebar drawer
- Use display:contents for desktop wrapper transparency (Critical: sidebar was hidden)
- Fix z-index stacking so sidebar renders above backdrop in drawer
- Force sidebar expand when mobile drawer is open (collapsed state)
- Hide resizeHandle on mobile to prevent touch scroll conflicts
- Reset drawer state on viewport resize via matchMedia listener
- Add role=dialog, aria-modal, Escape key dismissal, body scroll lock
- Add aria-expanded to hamburger button
- Close drawer when opening Settings or resuming sessions
* fix(web-shell): address second round of review feedback
- Remove dead :global(.sidebar) selector (CSS Modules hash class names)
- Fix Escape key capture-phase handler to not intercept sidebar inputs
- Conditionally apply role=dialog/aria-modal only when drawer is open
- Stop toggling collapsed prop on drawer open/close to preserve sidebar state
- Add closeMobileDrawer() for bare /resume command path
- Fix hamburger button vertical centering in empty chat state on mobile
* fix(web-shell): fix stacking context and escape handler in mobile drawer
* fix(web-shell): prevent iOS Safari background scroll when drawer is open
* chore: remove accidentally committed .qwen-session and gitignore it
The .qwen-session file is a developer-local session UUID generated by
qwen serve. It was accidentally committed to the repo and should never
be tracked.
* fix(web-shell): address review feedback for mobile drawer
- Don't preventDefault touchmove inside the drawer so the session list
can scroll natively; only block scrolling on the page behind it.
- Defer Escape to a pending tool/permission approval (reject) instead of
closing the drawer when a prompt is visible.
- Reuse isEditableTarget from utils/dom and only bail out for editable
targets outside the drawer, so the drawer search input still closes on
the first Escape.
- Close the drawer before awaiting loadSession so it doesn't linger over
the old transcript, matching the other session-switch paths.
- Keep the drawer panel visible until the backdrop finishes fading out to
avoid a one-frame flicker on close.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(web-shell): mobile drawer ignores collapsed rail + block backdrop scroll
- collapsed: a user who collapsed the desktop sidebar got a mobile drawer that
still rendered as the icon rail (no session list — the whole point of the
drawer). Force the expanded layout while the drawer is open.
- touchmove: the allowlist matched the outer [data-mobile-drawer] wrapper, which
also contains the full-screen backdrop, so a touchmove starting on the dim
backdrop skipped preventDefault and let iOS Safari scroll the page behind.
Exclude the backdrop so only the panel keeps native scroll.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(web-shell): harden mobile drawer collapse, error path, and width cap
- Hide the sidebar collapse button while the mobile drawer is open so its
no-op toggle can no longer silently persist desktop collapsed state.
- Close the drawer before awaiting createSession() so a failed create no
longer leaves the drawer stuck open with page scroll locked.
- Drop redundant width/min-width/position from .sidebar.mobileOpen and cap
it with max-width:100vw so a wide persisted width can't overflow phones.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
---------
Co-authored-by: pomelo-nwu <czynwu@gmail.com>
Co-authored-by: Qwen-Coder <noreply@qwen.ai>