Skip to content

feat(web): add an environment scope filter to the sidebar - #14997

Closed
ilyaliao wants to merge 4 commits into
pingdotgg:mainfrom
ilyaliao:feat/sidebar-environment-filter-v2
Closed

ilyaliao wants to merge 4 commits into
pingdotgg:mainfrom
ilyaliao:feat/sidebar-environment-filter-v2

Conversation

@ilyaliao

@ilyaliao ilyaliao commented Oct 3, 2026 •

Copy link
Copy Markdown

Problem

The web and desktop sidebar can only be scoped by project. A user connected to several environments sees every machine's projects and threads mixed together and has no way to narrow the list to one machine, even though mobile already offers an Environment filter in its list options. Closes #8948.

Change

Add an environment scope menu to the sidebar header, before the project scope:

  • Options. All environments plus each enabled environment. Offline ones stay listed and are marked Offline. Same-named machines are told apart by their address.
  • What it narrows. The thread list, draft rows, the server-side search fan-out, and the folder menu's project list.
  • Trigger. Swaps to the machine's glyph, so the active scope reads without opening the menu.
  • Persistence. Stored in the same local UI state as the project scope.
  • Single environment. The control is hidden when fewer than two environments are enabled, so single-machine setups are unchanged.

The two stored keys stay independent. One pure resolveSidebarScope narrows the project groups by environment before looking up the project key, so a project scope with no member on the chosen environment falls back to all projects. V2's filterSidebarV2VisibleThreads takes the resolved scope and shares the same sidebarScopeIncludes check as draft rows.

The resolver also carries the project-scope behavior from #17050. A saved scratch key from one machine reads as the merged "No project" group and is written back as that group's key. A stored value on either axis is cleared only after every enabled environment has both its project snapshot and its project config, because the config is what identifies a scratch project.

What changed relative to #12923 for V2:

  • The menu options come from V2's environment connection summary instead of useEnvironments(), so the sidebar does not re-render on provider updates or heartbeats.
  • The radio rows take a minimal EnvironmentScopeOption (id, label, machine, offline). Settings maps its full presentation to it; the sidebar maps the connection summary.
  • The environment label helper moves out of Settings into state/environments.ts, and the radio rows are shared by Settings, the Pull Requests server filter, and the sidebar, so the Pull Requests filter now disambiguates same-named servers too.

Scope and approval

This is a rebuild of #12923. It addresses #8948, which asks for a Remote environments filter on the desktop clients to match mobile.

Verification

Automated checks:

  • Tests. vp test run on the uiStateStore, environments, sidebarScope, settingsScopeAxis, settingsScope, and Sidebar.logic suites passes (6 files, 214 tests). The fix(client): merge No project filters across environments #17050 suites that cover the same code, settingsScopeRetention and environmentGrouping, also pass (2 files, 29 tests).
  • Types. tsc --noEmit for apps/web is clean.
  • Lint. The finding set on touched files is identical to base.

Manual run in the web dev app with three environments, two of which have a "No project" thread:

  • The control appears once a second environment is added.
  • Picking one narrows the thread list and the folder menu.
  • Reloading keeps the choice.
  • Switching back to All restores every thread.
  • Stopping a server keeps it listed as Offline without dropping the selection, also across a reload.
  • With "No project" scoped, switching between the two environments that have one keeps the project scope and shows that machine's thread. Switching to the environment without one falls back to all projects.
  • A stored scratch key from another machine survives a reload as "No project" and is rewritten to the merged key.
  • Stored values that name nothing fall back to All and are cleared.

Mobile is unchanged (it already has this filter).

The screenshots come from a separate run with seeded demo data across three environments: Moonbase Terminal (this machine), Suspense Station, and Kernel Cabin.

One environment: control hidden, as before Three environments: the new menu Scoped to Suspense Station: folder menu lists only its projects
Sidebar header with search, folder, new project and new thread, no environment control Environment menu listing All environments, Moonbase Terminal, Suspense Station, and Kernel Cabin Environment trigger shows the machine glyph and the folder menu lists only React

Model: Claude Opus 5.5. Harness: Claude Code (T3 Code).

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Oct 3, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a new persisted environment-scope feature and changes sidebar filtering, project menus, draft visibility, search fan-out, and related settings/server labels across multiple production components. The cross-cutting user-facing behavior and broad runtime surface warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e7610405-4e40-4c20-b9a6-18442d3b3150




📥 Commits

Reviewing files that changed from the base of the PR and between b24ddda and a52d880.





📒 Files selected for processing (2)
  • apps/web/src/components/EnvironmentScopeRadioItems.tsx
  • apps/web/src/components/sidebar/SidebarEnvironmentScopeMenu.tsx




Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.






📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough

Walkthrough

The sidebar now stores an environment scope alongside the project scope. The effective scopes filter threads and drafts, and environment-scoped search targets the selected connected environment. Environment options and selection menus also appear in the sidebar and settings controls.

Changes

Sidebar Environment Scoping

Layer / File(s) Summary
Environment options and menu rows
apps/web/src/state/environments.ts, apps/web/src/state/environments.test.ts, apps/web/src/test/environmentPresentation.ts, apps/web/src/components/EnvironmentScopeRadioItems.tsx, apps/web/src/components/settings/SettingsScopeSentence.tsx, apps/web/src/components/settings/settingsScopeAxis.ts, apps/web/src/components/settings/settingsScopeAxis.test.ts, apps/web/src/components/sidebar/SidebarEnvironmentScopeMenu.tsx, apps/web/src/routes/_chat.pull-requests.tsx
Environment options include disambiguated labels, machine types, and offline status. Shared radio rows serve settings and sidebar controls, and pull-request environment labels use the disambiguation helper.
Persisted environment scope
apps/web/src/uiStateStore.ts, apps/web/src/uiStateStore.test.ts
UI state stores and persists the selected environment ID. Parsing sanitizes invalid values, and tests cover updates and persistence.
Combined scope resolution and filtering
apps/web/src/components/sidebar/sidebarScope.ts, apps/web/src/components/sidebar/sidebarScope.test.ts, apps/web/src/components/Sidebar.logic.ts, apps/web/src/components/Sidebar.logic.test.ts, apps/web/src/components/Sidebar.tsx
The sidebar resolves environment and project selections together. Thread and draft filters use both scope axes; search and paging respond to the effective scope.
Sidebar scope controls and display
apps/web/src/components/sidebar/SidebarThreadHeader.tsx, apps/web/src/components/Sidebar.tsx
The sidebar header renders the environment scope menu before project controls. Project-filter display and empty-state text reflect the resolved scope.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant SidebarEnvironmentScopeMenu
  participant UiStateStore
  participant Sidebar
  participant sidebarScopeIncludes
  User->>SidebarEnvironmentScopeMenu: Select an environment
  SidebarEnvironmentScopeMenu->>UiStateStore: Save the environment scope ID
  UiStateStore->>Sidebar: Provide the persisted scope
  Sidebar->>sidebarScopeIncludes: Check environment and project scope
  sidebarScopeIncludes-->>Sidebar: Return whether the reference matches
Loading







Merge Risk: ⚪ Minimal · up to a52d8

The sidebar can filter to one environment as intended. Selecting several environments remains a follow-up for issue #8948; no actionable merge-blocking risk is established.

Security Architecture Review

Security architecture risk: 🔵 Low · up to a52d8

The inspected changes narrow existing sidebar content and search without granting new access. An unavailable saved selection can fall back to all environments, so this filter should not be treated as a privacy or access-control boundary. Remaining uncertainty limits the assessment.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The traced exposure is sidebar presentation and search over already configured environments. The change can reduce search targets but does not introduce a target outside the existing connected-environment set or grant new credential authority in these paths.

Trust Boundaries and Controls

  • observed — Environment labels are rendered as React text rather than interpreted markup. Radio values are matched against supplied environment options before entering sidebar state; these UI controls perform selection, not authentication or authorization.

Resilience and Maintainability Implications

  • observed — Persistence cleanup waits for a ready, nonempty catalog, required primary discovery, and live snapshots for enabled environments. Connection loss alone does not remove an enabled environment from the menu, reducing premature loss of a valid saved selection.





Pre-merge checks | Passed 3 | Failed 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check Warning Issue #8948 asks users to select one or more remote environments. This PR adds environment scoping for projects and threads, but the menu uses radio items and stores one EnvironmentId | null. It the… Allow users to select multiple environments, persist the selected set, apply it to project and thread filtering, and add tests for multi-environment selection and clearing the selection.
Docstring Coverage Warning Docstring coverage is 28.13% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 32 functions across 17 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check Passed The scope persistence, resolution, and project/thread filtering support issue #8948. The shared environment labels and radio rows support the new environment selector. Updating the Pull Requests serve…
Title check Passed The title is concise, specific, and accurately describes the primary change: adding an environment scope filter to the web sidebar.
Description check Passed The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the behavior, links the related issue, provides detailed automated and manual verifica…

Full details: Linked Issues check

Explanation

Issue #8948 asks users to select one or more remote environments. This PR adds environment scoping for projects and threads, but the menu uses radio items and stores one EnvironmentId | null. It therefore supports one environment or all environments, not a multi-environment selection. The other requested filtering behavior is implemented.


  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR







  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@ilyaliao
ilyaliao force-pushed the feat/sidebar-environment-filter-v2 branch 2 times, most recently from b24ddda to a52d880 Compare October 4, 2026 08:31
@ilyaliao
ilyaliao force-pushed the feat/sidebar-environment-filter-v2 branch from a52d880 to e65a32e Compare October 7, 2026 13:17
HannoKruger added a commit to HannoKruger/t3code that referenced this pull request Oct 10, 2026
Backport onto v0.0.45 of upstream pull request pingdotgg#14997 at head e65a32e
(feat(web): add an environment scope filter to the sidebar), squashed
from its four commits.

With two or more enabled environments, the sidebar header gets an
environment menu before the project menu. Picking one narrows threads,
draft rows and their count, the project menu, and the server-side
search fan-out to that environment. "All environments" resets it. The
choice is persisted in the UI state store next to the project scope.

v0.0.45 predates the environment summary atoms and the Sidebar V2
thread filter the pull request builds on, so three places differ:
- state/environments.ts: sidebarEnvironmentScopeOptions reads the
  environment presentations from useEnvironments() instead of
  connection summaries, and the hooks for those summaries are left out.
  Its tests build presentations instead of summaries.
- Sidebar.tsx: the visible-thread filter and the search fan-out keep
  v0.0.45's inline code and apply sidebarScopeIncludes and the scoped
  environment to it.
- Sidebar.logic.ts and its test keep v0.0.45's version, since
  filterSidebarV2VisibleThreads does not exist there. sidebarScope.test.ts
  covers the shared visibility rule.

Carried-Pull-Request: 14997
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ilyaliao
ilyaliao force-pushed the feat/sidebar-environment-filter-v2 branch 2 times, most recently from 4ecac04 to c1111ff Compare October 11, 2026 03:48
ilyaliao and others added 4 commits October 12, 2026 03:28
…ettings, pull requests, and sidebar

Settings rendered its environment radio rows inline and labeled duplicate
machine names with a helper only Settings could reach, while the Pull
Requests server filter showed bare labels, so two same-named machines
read as one row there. Move the label rule to state/environments, make it
also tell apart machines that share an address, and render the rows from
a small EnvironmentScopeOption shape any menu can build. The "All
environments" value becomes the empty string, which no EnvironmentId can
be, so an environment whose id is "all" no longer collides with it.
Add sidebarEnvironmentScopeId beside sidebarProjectScopeKey: same
localStorage layer, no key bump (old payloads decode to null, old builds
ignore the field). The id is decoded at the parse boundary into an Option
rather than through EnvironmentId.make, since readPersistedState wraps the
whole parse in one try/catch and a throw would discard every other field;
the decode also trims, so a padded id hydrates and a blank one is dropped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The sidebar could only be scoped by project. Add the pure model for an
environment axis next to it: the menu options come from the catalog's
enabled environments, built from connection summaries so provider and
config refreshes do not churn them, and resolveSidebarScope narrows the
project groups to the chosen environment before looking up the project
key. A project scope with no member there reads as all projects, and a
stored value is only cleared once every enabled environment has a live
project snapshot, the gate the project axis already uses.
A user connected to several environments saw every machine's projects
and threads mixed in one sidebar, with no way to narrow it to one machine
even though mobile offers that filter. Add an environment menu before the
project scope whenever two or more environments are enabled. Picking one
narrows the thread list, draft rows and count, the folder menu's project
list, and the server-side search fan-out to that environment. The trigger
shows the machine's glyph, and "All environments" is one click away.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@ilyaliao
ilyaliao force-pushed the feat/sidebar-environment-filter-v2 branch from c1111ff to 1a28085 Compare October 11, 2026 19:29

Copy link
Copy Markdown
Member

Note

This comment is posted by Julius' dot

This adds a new persisted sidebar filtering workflow across threads, drafts, project menus and search. #8948 has no maintainer approval, and the V2 rebuild invitation on #12923 did not approve this direction or scope. Closing under the prior-approval rule. Please agree on the desktop environment-filter behavior with maintainers in an Ideas discussion and link that approval for reconsideration.

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

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add Remote environments filtering to desktop clients

2 participants