WebShell Sidebar — Guia de Personalização
O WebShellSidebar é o painel de navegação e lista de sessões renderizado
dentro do componente App do web-shell. Este documento mapeia cada área
visual para sua capacidade atual de personalização e identifica áreas sem
ponto de injeção externo.
Ativando a sidebar
A sidebar está desativada por padrão. Passe a prop sidebar para ativar:
import { WebShellWithProviders } from '@qwen-code/web-shell';
<WebShellWithProviders
baseUrl="http://localhost:4170"
sidebar={true} // simple enable
// or with fine-grained options:
// sidebar={{ enabled: true, defaultCollapsed: false, ... }}
/>;Visão geral do layout
┌─────────────────────────────────────┐
│ ① Branding (topRow) │ ✅ customizable
├─────────────────────────────────────┤
│ ② Primary navigation │ ✅ customizable
│ [+ New task] [🧩 Plugins] │
│ [📅 Scheduled] [🎯 Goals] │
│ [custom render...] │
├─────────────────────────────────────┤
│ ③ Project header │ ✅ show/hide
│ 📁 Projects ▼ [🔍] [+] │
│ Session list entries... │
│ 📦 Archived sessions │
├─────────────────────────────────────┤
│ ④ Footer action bar │ ✅ customizable
│ [⚙ Settings] v0.19 [☀] [▦] [◧] │
├─────────────────────────────────────┤
│ ⑤ Resize handle │ ❌ not customizable
└─────────────────────────────────────┘Áreas personalizáveis
① Branding — branding
interface WebShellSidebarBranding {
render?: () => ReactNode; // replace the entire branding row
hideWhenCompact?: boolean; // hide when sidebar is collapsed (default: true)
}| Valor | Efeito |
|---|---|
undefined (padrão) | Logo do Qwen + texto “Qwen Code” |
false | Linha de branding oculta completamente |
{ render: () => <MyHeader /> } | Substituição completa com conteúdo personalizado |
{ hideWhenCompact: false } | Manter branding visível no modo icon-rail recolhido |
sidebar={{
branding: {
render: () => (
<div style={{ display: 'flex', gap: 8 }}>
<img src="/my-logo.svg" alt="" width={24} />
<span>My App</span>
</div>
),
},
}}② Navegação Primária — primaryNav
type WebShellSidebarPrimaryNavItem =
| 'newTask' // ✏️ New Task button
| 'plugins' // 🧩 Plugins button
| 'scheduledTasks' // 📅 Scheduled Tasks button
| 'goals'; // 🎯 Goals button
interface WebShellSidebarPrimaryNavOptions {
items?: readonly WebShellSidebarPrimaryNavItem[]; // which built-in buttons to show (default: all)
render?: () => ReactNode; // additional custom content after built-in buttons
}A área de navegação primária contém botões integrados controlados por items:
- Todos os botões são exibidos por padrão quando
itemsnão é especificado - Apenas os botões listados são exibidos quando
itemsé fornecido - Conteúdo personalizado pode ser adicionado via
render()após os botões integrados
| Valor | Efeito |
|---|---|
undefined (padrão) | Todos os botões integrados exibidos |
{ items: ['plugins'] } | Apenas o botão Plugins |
{ items: ['plugins', 'scheduledTasks'] } | Plugins + Scheduled Tasks |
{ items: [], render: () => ... } | Oculta todos os integrados, apenas conteúdo custom |
sidebar={{
primaryNav: {
items: ['plugins', 'scheduledTasks'], // hide newTask and goals
render: () => (
<button onClick={() => console.log('custom action')}>
🔗 Data Sync
</button>
),
},
}}④ Rodapé — footer
type WebShellSidebarFooterItem =
| 'settings' // ⚙ Settings panel
| 'version' // version label (e.g. "v0.19.10")
| 'theme' // ☀/🌙 light/dark toggle
| 'sessionsOverview' // ▦ session overview panel (large screens only)
| 'splitView' // ◧ split view (large screens only)
| 'daemonStatus' // 📊 daemon status panel
| 'collapse'; // ◁/▷ collapse/expand toggle
interface WebShellSidebarFooterOptions {
items?: readonly WebShellSidebarFooterItem[]; // which built-in items to show (default: all)
render?: () => ReactNode; // custom content rendered on the left side, before built-in items
}| Valor | Efeito |
|---|---|
undefined (padrão) | Todos os itens exibidos |
false | Rodapé oculto completamente |
{ items: ['settings', 'theme', 'collapse'] } | Apenas os itens listados |
O rodapé se adapta automaticamente a larguras reduzidas: os rótulos são ocultos e a versão é removida abaixo de certos limites.
sidebar={{
footer: { items: ['theme', 'collapse'] }, // minimal footer
}}Conteúdo personalizado via render() aparece no lado esquerdo do rodapé,
antes dos itens integrados:
sidebar={{
footer: {
items: ['collapse'],
render: () => (
<button onClick={() => openHelpCenter()}>
❓ Help
</button>
),
},
}}Nota: 'scheduledTasks' e 'goals' foram movidos para a área de
navegação primária (②) e são exibidos por padrão. São controlados por
primaryNav.items em vez de footer.items.
Outras opções de nível superior
interface WebShellSidebarOptions {
enabled?: boolean; // show/hide sidebar (default: true when passed)
defaultCollapsed?: boolean; // initial collapsed state (persisted in localStorage)
showCompactToggle?: boolean; // show the collapse button in the chat area (default: true)
branding?: false | WebShellSidebarBranding;
primaryNav?: WebShellSidebarPrimaryNavOptions;
hideProjectHeader?: boolean; // hide "Projects" header row (default: false = shown)
sessionActions?: WebShellSidebarSessionActionsOptions;
footer?: false | WebShellSidebarFooterOptions;
}③ Cabeçalho do Projeto — hideProjectHeader
Controla a visibilidade da linha de cabeçalho “Projects” (a linha com o
toggle de recolhimento, ícone de busca e botão de adicionar workspace).
O padrão é false (exibido).
sidebar={{
hideProjectHeader: true, // hide the "项目 ▼ [🔍] [+]" row
}}Quando oculto, as entradas da lista de sessões e as sessões arquivadas continuarão sendo exibidas — a linha de cabeçalho com seus botões de ação e a barra de busca de sessões são removidas.
Ações de Linha da Sessão — sessionActions
type WebShellSidebarSessionActionItem =
| 'details' // 📝 Details (dropdown sub-menu)
| 'rename' // ✏️ Rename (dropdown menu)
| 'group' // 📁 Group/Move to folder (dropdown menu)
| 'export' // 📤 Export chat history (dropdown menu)
| 'delete' // 🗑 Delete session (dropdown menu)
| 'pin' // 📌 Pin/Unpin (inline button)
| 'archive'; // 📦 Archive (inline button)
/** Subset with working inline (hover-button) handlers. */
type WebShellSidebarSessionInlineActionItem =
| 'pin'
| 'archive'
| 'rename'
| 'export'
| 'delete';
interface WebShellSidebarSessionActionsOptions {
items?: readonly WebShellSidebarSessionActionItem[]; // which actions to show (default: all)
inlineItems?: readonly WebShellSidebarSessionInlineActionItem[]; // which items appear as inline buttons (default: ['pin', 'archive'])
}Controla quais botões de ação aparecem nas linhas de sessão:
items: Controle mestre para todas as ações (inline e dropdown). Se um item não está emitems, ele é oculto em todos os lugares.inlineItems: Controla quais itens aparecem como botões inline (ao passar o mouse). O padrão é['pin', 'archive']. Apenas itens com handlers inline funcionais podem ser usados:'pin','archive','rename','export','delete'.'details'e'group'são apenas dropdown.
Prioridade de visibilidade: Tanto items quanto a condição integrada do item quanto inlineItems devem ser atendidos para que o botão inline apareça. Por exemplo, delete como inline requer que items inclua 'delete' E inlineItems inclua 'delete'.
| Valor | Efeito |
|---|---|
undefined (padrão) | Todas as ações exibidas, pin + archive como inline |
{ inlineItems: ['pin', 'delete'] } | Pin + delete como botões inline |
{ inlineItems: [] } | Nenhum botão inline |
{ inlineItems: ['archive', 'export'] } | Archive + export como botões inline |
O trigger do dropdown (⋮) é automaticamente oculto quando nenhum item de
dropdown está habilitado. Os botões inline (pin, archive) só são
exibidos quando tanto sua condição de capability quanto items os incluem.
sidebar={{
sessionActions: {
items: ['details', 'rename', 'export', 'delete', 'pin'], // which actions to show (master control)
inlineItems: ['pin', 'delete'], // pin + delete as inline buttons
},
}}Áreas não personalizáveis
Projects / Workspaces (dentro da lista de sessões)
Quando a lista de sessões está visível, as seguintes subáreas são renderizadas, mas não são personalizáveis individualmente:
| Aspecto | Detalhe |
|---|---|
| Fonte de dados | Hook useSessions() → daemon API (endpoint /sessions) |
| Ordenação da lista | Por data de criação, descendente |
| Renderização da linha | useCallback interno renderSessionRow — não injetável |
| Busca / filtro | Barra de busca integrada com matching de texto no client |
| Grupos de sessão | Componente SessionGroupSection com 6 cores preset + hex custom |
| Seções de workspace | WorkspaceSection por workspace do daemon, não substituível |
| Diálogo de workspace | AddWorkspaceDialog integrado |
⑤ Resize handle
- Handle de arrasto na borda direita para redimensionar a largura da sidebar
- A largura é persistida no localStorage
- Não é configurável
Props de comportamento em runtime
Estas WebShellProps afetam o comportamento da sidebar indiretamente:
| Prop | Efeito |
|---|---|
onNewSession | Substitui o handler de nova sessão |
onLoadSession | Substitui a lógica de carregamento de sessão |
onSessionIdChange | Reage a trocas de sessão |
splitSessionIds | Controla sessões do split view externamente |
theme / onThemeChange | Controla / observa o tema |
language / onLanguageChange | Controla / observa o idioma da UI |
Estados recolhido e mobile
| Estado | Comportamento |
|---|---|
| Expandido | Sidebar completa com rótulos de texto |
| Recolhido | Modo icon-rail (logo, ícone de caneta, ícones de ação) |
| Mobile | Drawer desliza da esquerda com overlay de backdrop |
O estado de recolhimento é persistido no localStorage sob a chave
qwen-code-web-shell-sidebar-collapsed.
Localizações do código-fonte
| Componente | Arquivo |
|---|---|
| WebShellSidebar | packages/web-shell/client/components/sidebar/WebShellSidebar.tsx |
| SessionGroupSection | packages/web-shell/client/components/sidebar/SessionGroupSection.tsx |
| WorkspaceSection | packages/web-shell/client/components/sidebar/WorkspaceSection.tsx |
| Estilos da sidebar | packages/web-shell/client/components/sidebar/WebShellSidebar.module.css |
| Integração no App | packages/web-shell/client/App.tsx (buscar WebShellSidebar) |
| Entry point (dev) | packages/web-shell/client/main.tsx (sidebar: true) |