Show project icons in status-grouped sidebar rows (#2416)

* feat: show project icons in sidebar status view

* test(sidebar): keep status icon regression active

The ten-second mock can finish during app startup, removing the Working bucket before the icon assertion. Keep the seeded workspace active for the full scenario.

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
nikuscs
2026-07-31 14:44:31 +02:00
committed by GitHub
co-authored by Mohamed Boudra
parent d9b72e1c76
commit 87ef631ac4
6 changed files with 207 additions and 22 deletions
@@ -114,7 +114,7 @@ import { useClearWorkspaceAttention } from "@/hooks/use-clear-workspace-attentio
import type { PrHint } from "@/git/use-pr-status-query";
import {
buildSidebarProjectRowModel,
resolveSidebarProjectIconTarget,
resolveSidebarProjectIconTargets,
resolveSidebarProjectLocalPath,
type SidebarProjectHostTarget,
} from "@/utils/sidebar-project-row-model";
@@ -1952,6 +1952,16 @@ export function SidebarWorkspaceList({
const supportsPinningByServerId = useHostFeatureMap(serverIds, "workspacePinning");
const onToggleWorkspacePin = useSidebarWorkspacePinController();
const showHostLabels = useMemo(() => shouldShowSidebarHostLabels(projects), [projects]);
// Status mode drops the project grouping, so its rows carry their own project
// icon. Project mode fetches the same icons inside ProjectModeList for its
// project headers, so only the active mode requests them.
const statusProjectIconTargets = useMemo(
() => (groupMode === "status" ? resolveSidebarProjectIconTargets(projects) : []),
[groupMode, projects],
);
const statusProjectIconByProjectKey = useProjectIconDataByProjectKey({
projects: statusProjectIconTargets,
});
const content =
groupMode === "status" ? (
@@ -1960,6 +1970,7 @@ export function SidebarWorkspaceList({
pinnedGroups={pinnedGroups}
workspaceEntriesByKey={workspaceEntriesByKey}
projectNamesByKey={projectNamesByKey}
projectIconByProjectKey={statusProjectIconByProjectKey}
shortcutIndexByWorkspaceKey={shortcutIndexByWorkspaceKey}
onWorkspacePress={onWorkspacePress}
hostLabelByServerId={hostLabelByServerId}
@@ -1998,6 +2009,7 @@ function SidebarStatusModeWrapper({
pinnedGroups,
workspaceEntriesByKey,
projectNamesByKey,
projectIconByProjectKey,
shortcutIndexByWorkspaceKey: _projectShortcutIndex,
onWorkspacePress,
hostLabelByServerId,
@@ -2010,6 +2022,7 @@ function SidebarStatusModeWrapper({
pinnedGroups: PinnedSidebarGroups;
workspaceEntriesByKey: ReadonlyMap<string, SidebarWorkspaceEntry>;
projectNamesByKey: Map<string, string>;
projectIconByProjectKey: ReadonlyMap<string, string | null>;
shortcutIndexByWorkspaceKey: Map<string, number>;
onWorkspacePress?: () => void;
hostLabelByServerId: ReadonlyMap<string, string>;
@@ -2028,6 +2041,7 @@ function SidebarStatusModeWrapper({
return entry ? [entry] : [];
})}
projectNamesByKey={projectNamesByKey}
projectIconByProjectKey={projectIconByProjectKey}
shortcutIndexByWorkspaceKey={_projectShortcutIndex}
showShortcutBadges={showShortcutBadges}
onWorkspacePress={onWorkspacePress}
@@ -2099,14 +2113,7 @@ function ProjectModeList({
canToggle: canTogglePinnedChats,
toggleExpanded: togglePinnedChatsExpanded,
} = useLimitedSidebarGroup(pinnedChats);
const projectIconTargets = useMemo(
() =>
projects.flatMap((project) => {
const target = resolveSidebarProjectIconTarget(project);
return target ? [{ projectKey: project.projectKey, ...target }] : [];
}),
[projects],
);
const projectIconTargets = useMemo(() => resolveSidebarProjectIconTargets(projects), [projects]);
const nativeScrollGestureProps = useMemo(
() =>
parentGestureRef