fix(web): checkouts without their own icon show their project's icon#31327

open3
main
fix/issue-31305
opened1d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

When a project has a second checkout (another clone of the same repository, grouped under one sidebar project), the checkout added later has no icon of its own. The sidebar group shows the project's custom icon, but the chat header breadcrumb, sidebar thread and draft rows, command palette entries, and the Project settings preview for that checkout show its automatic monogram instead.

Reproduction on main @ 67eebaca23 in the web app: add two clones with the same origin, give the first a Lucide icon in Settings > Projects, rename the group to "SlopSubs", then start a thread in the second checkout. The header shows "SS" instead of the rocket.

Change

  • resolveProjectIconSource in packages/client-runtime/src/state/projectGrouping.ts decides which icon a checkout shows. A checkout with no icon of its own (projectIcon and faviconPath both null) shows its group representative's custom icon. Otherwise it shows its own, so an icon set on one checkout still wins.
  • Lookup map: buildProjectIconSourceByKey builds that choice once per render, keyed by environmentId:projectId, the same way the existing display-name map is built.
    • The sidebar thread, search and draft rows use it.
    • So do the command palette's thread subtitles and project results.
    • Sidebar rows take a separate projectIcon prop, so their git working directory still comes from the checkout itself.
  • Chat header: it reads the group through useProjectIconSource. That hook shares the sidebar's unsorted group computation but does not subscribe to thread shells, so streaming does not re-render the header.
  • Project settings: the icon preview, its description and the icon picker's starting value use the same resolver, so a settings page scoped to that checkout shows what its other views show. What gets written on save is unchanged.

No persisted data, contracts or server code change.

Scope and approval

Fixes pingdotgg/t3code#31305

Triaged via the automated issue flow.

Verification

  • vp test run packages/client-runtime/src/state/projectGrouping.test.ts: 26 passed. New cases:

    • an iconless checkout inherits its group's icon;
    • a checkout with its own icon keeps it;
    • a group without a custom icon leaves the checkout unchanged;
    • an ungrouped project is returned unchanged.
  • vp test run apps/web/src/environmentGrouping.test.ts: 9 passed. The new case runs buildProjectIconSourceByKey over real buildSidebarProjectSnapshots output across two environments.

  • vp run check:changed: format, lint, knip, typecheck (7 packages), tests (14 files) and the React compiler check all pass.

  • Before/after captures were taken in the real web app on fresh databases, from 67eebaca23 and ce6c063b34. Each side was built from its own checkout, in Chrome on Linux at DPR 2, at 1440×900 and 390×844 in light and dark. ce6c063b34 differs from the head only in the open icon picker's starting value, which no capture shows.

    Diff counts are changed pixels at 0% / 2% fuzz:

    RowViewport / themeBefore 67eebaca23After ce6c063b34Diff0 / DiffT (px)
    Chat header, unsent draft in checkout B1440 light/dark, 390 light/darkSS monogramrocket399/367, 397/366, 761/753, 761/753
    Chat header and sidebar thread card, checkout B thread1440 light/darkSSrocket399/367, 397/366
    Sidebar draft row, checkout B1440 lightSSrocket621/560
    Command palette recent thread subtitle1440 lightSSrocket2072/956
    Command palette project result, "New thread in…"1440 lightSSrocket; checkout B path kept2162/1053
    Settings > Projects scoped to checkout B1440 lightSS, "Automatic"rocket, "rocket · blue"2923/1694
    Checkout B with its own icon (control)1440 lightheartheart0/0

    What else changed: nothing beyond the icons listed. The extra pixels in the palette and settings rows are the same icon change seen through the dialog's blurred backdrop. The screenshots will be attached to this PR.

  • Not checked: the desktop Electron shell (it renders the same web UI) and mobile, which this PR does not change.

AI-assisted; verified with the tests and tools listed above.

Checks

23 successful · 11 skipped · 1 neutral
All checks passed
8437451

Added 3 commits

  • fix(web): icon picker opens on the icon the checkout shows8437451
  • fix(web): project settings preview shows the inherited project iconce6c063
  • fix(web): checkouts without their own icon show their project's iconda61685
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Iconless checkouts now automatically display their project's icon across navigation, search, chat, and settings. Human confirmation is required for this change to the default icon presentation; explicit checkout icons remain unchanged.

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

Synced from GitHub

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

Project icon selection now falls back to a grouped checkout’s representative when the current checkout has no custom icon. Web surfaces use the resolved icon source for project favicons.

Changes: Grouped project icon resolution

Layer / File(s)Summary
Resolve icon sources
packages/client-runtime/src/state/projectGrouping.ts, packages/client-runtime/src/state/projectGrouping.test.ts
The resolver uses the representative checkout when the current project has no custom icon and the representative has one. Tests cover fallback and retention behavior.
Build grouped icon lookups
apps/web/src/sidebarProjectGrouping.ts, apps/web/src/hooks/useSidebarProjectGroups.ts, apps/web/src/environmentGrouping.test.ts
The lookup maps projects to their resolved icon sources using group membership. The hook also resolves the source for a project in its group.
Use resolved icons in web surfaces
apps/web/src/components/Sidebar.tsx, apps/web/src/components/sidebar/*, apps/web/src/components/CommandPalette*.tsx, apps/web/src/components/chat/ChatHeader.tsx, apps/web/src/components/settings/ProjectSettingsPanel.tsx
Sidebar rows and drafts, command palette items, the chat header, and project settings use resolved icon sources for favicon displays. The draft component test uses the updated icon lookup prop.

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

Change: Bug fix · Severity of issue fixed: Low

Possibly related issues

  • pingdotgg/t3code#11835: The issue describes different icons in project settings and the desktop sidebar for a grouped repository. This change resolves the displayed icon using the group representative when a checkout lacks its own custom icon.

Suggested reviewers: t3dotgg, maria-rcks

Merge Risk: External image Minimal · up to 84374

No merge-blocking risk was identified in the grouped icon changes.

Pre-merge checks: Passed 4

Check nameStatusExplanation
Title checkPassedThe title "fix(web): checkouts without their own icon show their project's icon" matches the main change. The PR makes a checkout with no icon of its own inherit its group representative's custom icon…
Description checkPassedThe description follows the template sections: Problem, Change, Scope and approval, and Verification. The Problem section gives the expected and actual behavior and a reproduction on main. The Change …
Linked Issues checkPassedIssue #31305 requires the chat header breadcrumb to show the group icon for a second checkout without its own icon. resolveProjectIconSource implements this fallback. useProjectIconSource applies …
Out of Scope Changes checkPassedThe changes stay within issue #31305. The lookup map, hook, settings updates, sidebar and command-palette updates, and related tests all support consistent project-icon resolution for grouped checkout…
Full details: Title check

Explanation

The title "fix(web): checkouts without their own icon show their project's icon" matches the main change. The PR makes a checkout with no icon of its own inherit its group representative's custom icon, across sidebar rows, command palette, chat header, and settings. The title uses a conventional commit prefix and a specific description, and it does not list files.

Full details: Description check

Explanation

The description follows the template sections: Problem, Change, Scope and approval, and Verification. The Problem section gives the expected and actual behavior and a reproduction on main. The Change section explains the resolver, the lookup map, the chat header hook, and the settings behavior. Scope cites issue #31305 and says it was triaged through an automated flow. Verification lists the test commands and results, a before/after table, and what was not checked. The description has two gaps. First, the Scope section does not include a maintainer approval comment or explain the exemption for a small fix of an obvious bug. Second, the before/after screenshots are described as attached later and are not embedded or linked in the description.

Full details: Linked Issues check

Explanation

Issue #31305 requires the chat header breadcrumb to show the group icon for a second checkout without its own icon. resolveProjectIconSource implements this fallback. useProjectIconSource applies it in ChatHeader. The added grouping tests cover inherited icons, checkout-specific icons, groups without custom icons, and ungrouped projects. The sidebar, command palette, and settings changes consistently apply the same resolver and support the reported issue scope.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #31305. The lookup map, hook, settings updates, sidebar and command-palette updates, and related tests all support consistent project-icon resolution for grouped checkouts. No unrelated product behavior, persisted data, contracts, or server code changes are shown.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info

External image Run configuration

External image Commits

Reviewing files that changed from the base of the PR and between 67eebaca23f8f7bc46e8817434087fc9c5acf8e3 and 8437451d942b1009a139bd06b53ae1db24bf5e7c.

External image Files selected for processing: 14

  • apps/web/src/components/CommandPalette.tsx
  • apps/web/src/components/CommandPaletteProjectItems.tsx
  • apps/web/src/components/CommandPaletteThreadItems.tsx
  • apps/web/src/components/Sidebar.tsx
  • apps/web/src/components/chat/ChatHeader.tsx
  • apps/web/src/components/settings/ProjectSettingsPanel.tsx
  • apps/web/src/components/sidebar/SidebarDraftBlock.browser.test.tsx
  • apps/web/src/components/sidebar/SidebarDraftBlock.tsx
  • apps/web/src/components/sidebar/SidebarThreadRow.tsx
  • apps/web/src/environmentGrouping.test.ts
  • apps/web/src/hooks/useSidebarProjectGroups.ts
  • apps/web/src/sidebarProjectGrouping.ts
  • packages/client-runtime/src/state/projectGrouping.test.ts
  • packages/client-runtime/src/state/projectGrouping.ts

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