Repository navigation
vscode: Backlog search — embed input inside the Backlog section (full WebviewView, replaces TreeView) #891
Description
Problem
The Codev sidebar's Backlog view can grow to hundreds of open GitHub issues in an active repo. Today, finding a specific issue by number, title fragment, area, or assignee requires either:
- Scrolling through the entire backlog (slow at this scale)
- Pressing
Cmd+Fwhile focused on the tree to invoke VSCode's built-in filter (matches visible label text only — doesn't seearea/*labels, assignees, or hidden metadata) - Clicking through to GitHub Issues web UI
The Builders view doesn't have the same problem — typical workflows have <10 active builders. Searching them is unnecessary, and the rewrite cost (loses per-builder changed-files tree, SCM color decorations, 10+ context menu actions, accordion auto-collapse) far exceeds the benefit.
What this issue ships — and what it explicitly does NOT
| Scope | Status |
|---|---|
| Backlog: gain embedded search input inside the section, items rendered below in the same unified view | ✅ in scope |
| Builders: gain a search input | ❌ explicitly out of scope (the rewrite cost isn't justified; will revisit only if a real need surfaces after Backlog ships) |
The Builders view ships unchanged from main by this issue — no new search section, no new toggle icon, no UI difference.
The required visual — matches VSCode's Source Control "CHANGES" pattern
The user wants the search input rendered INSIDE the Backlog section as its first element, with the items underneath, all in ONE collapsible section. Same architectural pattern as VSCode's Source Control view (which embeds the commit message input inside the CHANGES section).
┌─ CODEV ──────────────────────────────────────┐
│ ▾ Workspace │
│ ... │
│ ▾ Backlog (37) 🔍 ⟳ │ ← section header (with normal title-bar icons)
│ ┌──────────────────────────────────────┐ │
│ │ 🔍 Search backlog... │ │ ← input INSIDE the section, first element
│ └──────────────────────────────────────┘ │
│ showing 4 of 37 items │ ← summary line (when filter active)
│ │
│ #810 [implement] Builder row legibility │ ← items rendered BELOW the input, same section
│ #791 [plan] Startup CLI preflight ⏳ │
│ #828 [implement] test(dashboard-e2e)... │
│ #807 [implement] Reader View │
│ ▾ Builders (5) ⟳ │ ← Builders UNCHANGED, no search
│ ... │
│ ▾ Pull Requests │
│ ... │
└──────────────────────────────────────────────┘
This is not the visual of "a separate search section above the Backlog section" (the design that was tried and rejected mid-implementation). The input must visually live inside Backlog itself, not as a sibling section.
Why this requires full WebviewView replacement of the Backlog
Verified during this issue's design discussion: the TreeView API in vscode.d.ts (on main, post-1.121) has no primitive for embedding a text input inside a TreeView. Extensions have exactly two view types: tree (no input) and webview (custom HTML). VSCode's Source Control SCM view uses a built-in scm view type with the embedded input baked in — that type is not exposed to extensions.
Tracking issue microsoft/vscode#161753 ("TreeView search/filter input & api for customization") has been OPEN in MS's Backlog milestone since 2022 with no roadmap movement.
So: the only way to embed a real text input inside the Backlog section is to replace the Backlog TreeView with a WebviewView entirely. The webview's HTML renders both the input AND the item list.
Proposed implementation
View type change
packages/vscode/package.json — change codev.backlog from default type: "tree" to type: "webview". Register a BacklogWebviewViewProvider implements vscode.WebviewViewProvider instead of the current BacklogTreeDataProvider.
Webview HTML structure (rendered server-side, hydrated client-side)
<header>matches VSCode's section title bar styling — though VSCode draws the header outside the webview; this is just internal structure<input>for search — first child of the webview's content, styled to match VSCode's native input via--vscode-input-*CSS variables- Mode-toggle buttons next to the input (Aa case sensitive, ab whole word, .* regex) — small icon buttons matching VSCode's input-adornment idiom
- Summary line below:
"showing N of M"when filter active; hidden when empty - Item list rendered as
<div role="listitem">rows below — virtualized to handle hundreds of rows performantly
Theme integration (CSS via --vscode-* variables)
Required variable references:
--vscode-sideBar-background— webview background--vscode-foreground— text color--vscode-input-background/--vscode-input-foreground/--vscode-input-border— search input--vscode-focusBorder— focus rings--vscode-list-hoverBackground/--vscode-list-activeSelectionBackground/--vscode-list-activeSelectionForeground— row states--vscode-font-family/--vscode-font-size/--vscode-font-weight— typography--vscode-icon-foreground— codicons
Codicons rendered via @vscode/codicons package (load the CSS in the webview).
Behavioral parity targets
These behaviors exist in the current TreeView and MUST be preserved in the webview:
| Behavior | Implementation |
|---|---|
| Row click → primary action (current: opens issue / fires the row's bound command) | onclick handler on each row, postMessage to extension which invokes the existing command |
| Right-click → context menu with today's per-row actions (Reference Issue in Architect, View Issue, Spawn Builder, etc.) | Custom HTML/JS right-click menu in the webview, OR inline icon buttons per row. Implementer's call — don't drop the actions |
| Keyboard navigation: ↑/↓ moves selection, Enter fires primary action, Home/End jump, PgUp/PgDn page-scroll | JS handlers in the webview |
| Selection state survives overview SSE refreshes | Track selected row's id (issue number) in webview state, re-apply after re-render |
| Focus management — input focuses on toggle-expand of the section; rows focus on click | tabindex + JS focus calls |
ARIA accessibility — role="list" on container, role="listitem" on rows, aria-label on input |
Standard HTML semantics |
| Live theme changes (dark ↔ light) update colors without reload | CSS variables handle this automatically |
Performance — required, not optional
The backlog can have hundreds of items. Native browser scrolling 500 DOM nodes is sluggish; VSCode's TreeView virtualization isn't available to webviews.
Implementer must add virtualization (windowed rendering — only render visible rows + a buffer above/below). Options:
lit-virtualizer(small library, good fit)- Manual windowing via
IntersectionObserver+scrollevent - Implementer's call; whatever gets to smooth-scrolling with 500 rows
Filter behavior
- Live filter as user types (debounced ~150ms)
- Match scope: title + issue number +
area/*labels + label list + assignees - Substring match by default; regex when
.*toggle active; case-sensitive whenAaactive; whole-word whenabactive - Empty input → all items visible
- Summary line updates:
"showing N of M"when filter active; hidden when empty - Filter state is transient (not persisted across sessions) — avoids the "I opened VSCode and the backlog looks empty because I left a filter active months ago" footgun
Acceptance criteria
Visual unified-section requirement
- Backlog renders as a single section: input as first element, items below, all within one collapsible section header
- NO separate "Search" view above Backlog. NO
codev.backlogSearchview. NO Backlog title-bar 🔍 icon - Builders view unchanged from
main— no search, no toggle icon, no UI difference
Theme integration
- Input renders using
--vscode-input-*variables; matches VSCode's native input - Row colors, hover, selection use
--vscode-list-*variables - Font family/size from
--vscode-font-*variables - Theme changes (dark/light/HC) propagate to the webview live; no reload needed
Behavioral parity (vs today's Backlog TreeView)
- All existing Backlog row click actions still fire (open issue, etc.)
- All existing Backlog row context menu actions still accessible (right-click custom menu OR inline buttons — implementer's call)
- Keyboard navigation works: ↑/↓ moves selection, Enter fires primary action, Home/End/PgUp/PgDn scroll
- Selection state survives overview-cache SSE refreshes
- ARIA roles present: container has
role="list", rows haverole="listitem", input has descriptivearia-label
Filter
- Live filter on input changes (debounced ~150ms)
- Match scope: title + issue number +
area/*labels + label list + assignees - Mode toggles: Aa (case sensitive), ab (whole word), .* (regex)
- Empty input → all items visible
- Summary line
"showing N of M"appears when filter active; hidden when empty - Filter state transient — cleared on workspace reload
Performance
- Virtualized rendering: with 500 backlog items, only visible rows rendered to DOM (+ small buffer)
- Smooth scrolling with 500 items (no visible lag)
- Initial render under 200ms for 500 items
General
- e.labels iteration guard from commit
527c8f59preserved (Array.isArray check before any labels iteration in derived rendering) - Tests cover: filter logic, mode toggles, keyboard navigation events, accessibility roles. Webview DOM logic unit-testable in jsdom or via @vscode/test-electron's webview testing infrastructure
- Build + lint + tests green
- CMAP-2 unanimous before PR signal
Out of scope
- Builders search in any form — explicitly excluded; the rewrite cost (loses per-builder file tree + SCM decorations + 10+ context menu actions + accordion + the entire area-grouping work) far exceeds the benefit for the <10 typical active builders. Will be revisited as a separate issue only if real need surfaces post-Backlog
- Webview Backlog with grouping headers (the
area/*grouping from vscode: group backlog by area (area/* label namespace, predictable across views) #811) — port as-is from TreeView's BacklogProvider into the webview's HTML rendering. The grouping logic stays; only the rendering substrate changes - Persisting the filter query across sessions — explicitly rejected (footgun)
- Advanced search syntax like
area:auth assignee:me— substring + regex covers practical cases; advanced syntax is a separate issue - Replacing PullRequests / RecentlyClosed / Team / Status with webviews — only the Backlog view changes type
- Replicating every TreeView affordance pixel-perfectly — match the spirit (looks/feels native), accept that the implementer's effort puts a ceiling on fidelity (~80-95% of native, per VSCode's GitHub PR extension as a reference quality bar)
Scope warning
This is a multi-day rewrite. Estimated ~30-40 hours of careful CSS + JS work to reach native-feeling quality on top of the core search-input + tree-rendering logic. If the implementer hits walls or feels the scope creep is unmanageable, flag back to the architect early rather than push through quietly. Acceptable to break into phases:
- Phase 1: Backlog webview with basic styling + live filter + keyboard nav
- Phase 2 (separate PR): context menus + ARIA polish + virtualization tuning
But the unified-section visual (input INSIDE the section as first element, items below) is the load-bearing requirement — it's why we're doing this at all. The phase-1 PR must hit that visual; subsequent phases polish around it.
Why PIR
UI/UX change requiring visual confirmation in running VSCode (themed colors, hover/focus states, scroll feel, context menu interactions). PIR's dev-approval gate is the right surface — the architect must afx dev pir-891 (or equivalent) and confirm the look-and-feel before PR creation, not after. Plan-approval already happened in the original spec; if the implementer breaks this into Phase 1 + Phase 2, dev-approval applies to each phase.
Related
- TreeView search/filter input & api for customization microsoft/vscode#161753 — the upstream tracking issue for "TreeView search/filter input" (open since 2022 in MS Backlog milestone, no commitment)
packages/vscode/CHANGELOG.md— when this lands, a [Unreleased] What's new entry describes the unified search-and-list Backlog UX- vscode: group backlog by area (area/* label namespace, predictable across views) #811 + vscode: group builders in the tree by area (area/* label namespace, identical to backlog) #818 + vscode: capitalize area group header labels in backlog and builders trees #885 + vscode: UPPERCASE area group header labels in backlog and builders trees (supersedes #885's Capitalized form) #895 (all merged) — area grouping the Backlog webview must continue to support (group headers UPPERCASE, alphabetical with Uncategorized last)
Activity
amrmelsayed commentedon May 27, 2026
On it! Working on this with the PIR protocol (plan + dev-approval gates before PR).
[PIR #891] Plan draft
[PIR #891] Plan draft
[PIR #891] Plan: address post-rebase area-display change
[PIR #891] Plan revised: drop modes, add labels, conditional view
[PIR #891] Add labels[] to OverviewBacklogItem and OverviewBuilder
[PIR #891] Sidebar search webview filtering Backlog and Builders
[PIR #891] Thread: log implement phase complete
[PIR #891] Fix: guard labels iteration against stale wire payloads
[PIR #891] Thread: log dev-approval regression fix
[PIR #891] Split search into per-view independent inputs
[PIR #891] Thread: log per-view search split
[-]vscode: shared search webview above Backlog and Builders — embedded text input with live filter[/-][+]vscode: Backlog search — embed input inside the Backlog section (full WebviewView, replaces TreeView)[/+][PIR #891] Drop Builders search + stealth-merge Backlog search
amrmelsayed commentedon May 28, 2026
Closing as not doable in current scope
Multiple revision attempts on pir-891 didn't yield a satisfactory result against the user's actual UX intent (input embedded INSIDE the Backlog section as the first element, matching the SCM CHANGES pattern). The trajectory:
codev.backlogSearch+codev.buildersSearchas sibling sections above each tree) — closer but still wrong, the search section was a separate collapsible section above the items section, not visually unifiedThe architectural finding is solid (Path B / full WebviewView is the only path to the user's intended visual, since TreeView API has no embedded-input primitive — verified against
vscode.d.tsonmainpost-1.121 and tracking issue microsoft/vscode#161753). The execution on PIR-891 didn't land.Continued in #906
The builder filed #906 as a fresh start for the full-webview Backlog approach. That's the right place to carry the work forward — clean slate, scope-corrected from this issue's lessons:
The architect's design analysis from this issue's body (behavioral parity targets, theme integration via
--vscode-*variables, virtualization for hundreds of rows, etc.) should carry over to #906 as the spec baseline.Cleanup
.builders/pir-891/worktree removedbuilder/pir-891branch deletedafx cleanup -p 891)main