| ... | ... | @@ -276,6 +276,7 @@ function terminalProcessLabel(count: number): string { |
| 276 | 276 | function SidebarThreadTooltip({ |
| 277 | 277 | thread, |
| 278 | 278 | projectTitle, |
| 279 | projectDisplayName, |
| 279 | 280 | projectCwd, |
| 280 | 281 | projectFaviconPath, |
| 281 | 282 | projectIcon, |
| ... | ... | @@ -291,6 +292,7 @@ function SidebarThreadTooltip({ |
| 291 | 292 | }: { |
| 292 | 293 | thread: SidebarThreadSummary; |
| 293 | 294 | projectTitle: string | null; |
| 295 | projectDisplayName: string | null; |
| 294 | 296 | projectCwd: string | null; |
| 295 | 297 | projectFaviconPath: string | null; |
| 296 | 298 | projectIcon: ProjectIconOverride | null; |
| ... | ... | @@ -321,17 +323,17 @@ function SidebarThreadTooltip({ |
| 321 | 323 | {thread.title} |
| 322 | 324 | </div> |
| 323 | 325 | <div className="grid gap-1.5 pl-0.5 text-xs text-muted-foreground"> |
| 324 | | {projectTitle ? ( |
| 326 | {projectDisplayName ? ( |
| 325 | 327 | <div className="flex min-w-0 items-center gap-2"> |
| 326 | 328 | <ProjectFavicon |
| 327 | 329 | environmentId={thread.environmentId} |
| 328 | 330 | cwd={projectCwd ?? ""} |
| 329 | | projectName={projectTitle} |
| 331 | projectName={projectTitle ?? ""} |
| 330 | 332 | faviconPath={projectFaviconPath} |
| 331 | 333 | projectIcon={projectIcon} |
| 332 | 334 | className="size-3 shrink-0" |
| 333 | 335 | /> |
| 334 | | <div className="min-w-0 truncate text-foreground/75">{projectTitle}</div> |
| 336 | <div className="min-w-0 truncate text-foreground/75">{projectDisplayName}</div> |
| 335 | 337 | </div> |
| 336 | 338 | ) : null} |
| 337 | 339 | {environmentLabel ? ( |
| ... | ... | @@ -497,6 +499,7 @@ const SidebarDraftRow = memo(function SidebarDraftRow(props: { |
| 497 | 499 | session: DraftSessionState; |
| 498 | 500 | composer: ComposerThreadDraftState; |
| 499 | 501 | projectTitle: string | null; |
| 502 | projectDisplayName: string | null; |
| 500 | 503 | projectCwd: string | null; |
| 501 | 504 | projectFaviconPath: string | null; |
| 502 | 505 | projectIcon: ProjectIconOverride | null; |
| ... | ... | @@ -571,7 +574,7 @@ const SidebarDraftRow = memo(function SidebarDraftRow(props: { |
| 571 | 574 | className="size-4 shrink-0" |
| 572 | 575 | /> |
| 573 | 576 | <span className="min-w-0 flex-1 truncate text-xs font-medium text-secondary-label"> |
| 574 | | {props.projectTitle} |
| 577 | {props.projectDisplayName} |
| 575 | 578 | </span> |
| 576 | 579 | <span className="ml-auto flex h-5 min-w-5 shrink-0 items-center justify-end"> |
| 577 | 580 | <Tooltip> |
| ... | ... | @@ -609,6 +612,7 @@ interface SidebarDraftRowData { |
| 609 | 612 | // subscription + closing divider) so per-keystroke composer updates |
| 610 | 613 | // re-render only this block, never the whole sidebar. Vanishes at count 0. |
| 611 | 614 | const SidebarDraftBlock = memo(function SidebarDraftBlock(props: { |
| 615 | projectTitleByKey: ReadonlyMap<string, string>; |
| 612 | 616 | projectDisplayNameByKey: ReadonlyMap<string, string>; |
| 613 | 617 | projectCwdByKey: ReadonlyMap<string, string>; |
| 614 | 618 | projectFaviconPathByKey: ReadonlyMap<string, string | null | undefined>; |
| ... | ... | @@ -706,7 +710,8 @@ const SidebarDraftBlock = memo(function SidebarDraftBlock(props: { |
| 706 | 710 | draftId={draftId} |
| 707 | 711 | session={session} |
| 708 | 712 | composer={composer} |
| 709 | | projectTitle={props.projectDisplayNameByKey.get(projectKey) ?? null} |
| 713 | projectTitle={props.projectTitleByKey.get(projectKey) ?? null} |
| 714 | projectDisplayName={props.projectDisplayNameByKey.get(projectKey) ?? null} |
| 710 | 715 | projectCwd={props.projectCwdByKey.get(projectKey) ?? null} |
| 711 | 716 | projectFaviconPath={props.projectFaviconPathByKey.get(projectKey) ?? null} |
| 712 | 717 | projectIcon={props.projectIconByKey.get(projectKey) ?? null} |
| ... | ... | @@ -759,6 +764,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 759 | 764 | projectFaviconPath: string | null; |
| 760 | 765 | projectIcon: ProjectIconOverride | null; |
| 761 | 766 | projectTitle: string | null; |
| 767 | projectDisplayName: string | null; |
| 762 | 768 | providerEntryByInstanceId: ReadonlyMap<string, ProviderInstanceEntry>; |
| 763 | 769 | timestampFormat: TimestampFormat; |
| 764 | 770 | onThreadClick: (event: ReactMouseEvent, threadRef: ScopedThreadRef) => void; |
| ... | ... | @@ -994,6 +1000,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 994 | 1000 | <SidebarThreadTooltip |
| 995 | 1001 | thread={thread} |
| 996 | 1002 | projectTitle={props.projectTitle} |
| 1003 | projectDisplayName={props.projectDisplayName} |
| 997 | 1004 | projectCwd={props.projectCwd} |
| 998 | 1005 | projectFaviconPath={props.projectFaviconPath} |
| 999 | 1006 | projectIcon={props.projectIcon} |
| ... | ... | @@ -1304,7 +1311,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 1304 | 1311 | <ProjectFavicon |
| 1305 | 1312 | environmentId={thread.environmentId} |
| 1306 | 1313 | cwd={props.projectCwd ?? ""} |
| 1307 | | projectName={props.projectTitle ?? thread.title} |
| 1314 | projectName={props.projectTitle ?? ""} |
| 1308 | 1315 | faviconPath={props.projectFaviconPath} |
| 1309 | 1316 | projectIcon={props.projectIcon} |
| 1310 | 1317 | className="size-4" |
| ... | ... | @@ -1465,14 +1472,14 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 1465 | 1472 | projectIcon={props.projectIcon} |
| 1466 | 1473 | className="size-4 shrink-0" |
| 1467 | 1474 | /> |
| 1468 | | {props.projectTitle ? ( |
| 1475 | {props.projectDisplayName ? ( |
| 1469 | 1476 | <span |
| 1470 | 1477 | className={cn( |
| 1471 | 1478 | "min-w-0 flex-1 truncate text-secondary-label text-xs", |
| 1472 | 1479 | shouldRecede ? "font-normal" : "font-medium", |
| 1473 | 1480 | )} |
| 1474 | 1481 | > |
| 1475 | | {props.projectTitle} |
| 1482 | {props.projectDisplayName} |
| 1476 | 1483 | </span> |
| 1477 | 1484 | ) : ( |
| 1478 | 1485 | <span className="flex-1" /> |
| ... | ... | @@ -1669,6 +1676,7 @@ const SidebarSearchResultRow = memo(function SidebarSearchResultRow(props: { |
| 1669 | 1676 | projectFaviconPath: string | null; |
| 1670 | 1677 | projectIcon: ProjectIconOverride | null; |
| 1671 | 1678 | projectTitle: string | null; |
| 1679 | projectDisplayName: string | null; |
| 1672 | 1680 | environmentLabel: string | null; |
| 1673 | 1681 | environmentMachine: EnvironmentMachineKind; |
| 1674 | 1682 | providerEntryByInstanceId: ReadonlyMap<string, ProviderInstanceEntry>; |
| ... | ... | @@ -1735,7 +1743,9 @@ const SidebarSearchResultRow = memo(function SidebarSearchResultRow(props: { |
| 1735 | 1743 | aria-selected={props.isHighlighted} |
| 1736 | 1744 | aria-current={props.isRouteActive ? "page" : undefined} |
| 1737 | 1745 | aria-label={ |
| 1738 | | props.projectTitle ? `${thread.title}, ${props.projectTitle}` : thread.title |
| 1746 | props.projectDisplayName |
| 1747 | ? `${thread.title}, ${props.projectDisplayName}` |
| 1748 | : thread.title |
| 1739 | 1749 | } |
| 1740 | 1750 | onMouseMove={props.onHighlight} |
| 1741 | 1751 | onClick={props.onSelect} |
| ... | ... | @@ -1751,7 +1761,7 @@ const SidebarSearchResultRow = memo(function SidebarSearchResultRow(props: { |
| 1751 | 1761 | <ProjectFavicon |
| 1752 | 1762 | environmentId={thread.environmentId} |
| 1753 | 1763 | cwd={props.projectCwd ?? ""} |
| 1754 | | projectName={props.projectTitle ?? thread.title} |
| 1764 | projectName={props.projectTitle ?? ""} |
| 1755 | 1765 | faviconPath={props.projectFaviconPath} |
| 1756 | 1766 | projectIcon={props.projectIcon} |
| 1757 | 1767 | className="size-4 shrink-0" |
| ... | ... | @@ -1764,6 +1774,7 @@ const SidebarSearchResultRow = memo(function SidebarSearchResultRow(props: { |
| 1764 | 1774 | <SidebarThreadTooltip |
| 1765 | 1775 | thread={thread} |
| 1766 | 1776 | projectTitle={props.projectTitle} |
| 1777 | projectDisplayName={props.projectDisplayName} |
| 1767 | 1778 | projectCwd={props.projectCwd} |
| 1768 | 1779 | projectFaviconPath={props.projectFaviconPath} |
| 1769 | 1780 | projectIcon={props.projectIcon} |
| ... | ... | @@ -1995,6 +2006,12 @@ export default function Sidebar() { |
| 1995 | 2006 | ), |
| 1996 | 2007 | [projects], |
| 1997 | 2008 | ); |
| 2009 | // Icons use saved titles. Group labels can include a repository owner or a different title. |
| 2010 | const projectTitleByKey = useMemo( |
| 2011 | () => |
| 2012 | new Map(projects.map((project) => [`${project.environmentId}:${project.id}`, project.title])), |
| 2013 | [projects], |
| 2014 | ); |
| 1998 | 2015 | const projectDisplayNameByKey = useMemo( |
| 1999 | 2016 | () => |
| 2000 | 2017 | new Map( |
| ... | ... | @@ -3631,7 +3648,7 @@ export default function Sidebar() { |
| 3631 | 3648 | <ProjectFavicon |
| 3632 | 3649 | environmentId={scopedProjectGroup.environmentId} |
| 3633 | 3650 | cwd={scopedProjectGroup.workspaceRoot} |
| 3634 | | projectName={scopedProjectGroup.displayName} |
| 3651 | projectName={scopedProjectGroup.title} |
| 3635 | 3652 | faviconPath={scopedProjectGroup.faviconPath} |
| 3636 | 3653 | projectIcon={scopedProjectGroup.projectIcon} |
| 3637 | 3654 | className="size-4" |
| ... | ... | @@ -3689,7 +3706,7 @@ export default function Sidebar() { |
| 3689 | 3706 | <ProjectFavicon |
| 3690 | 3707 | environmentId={project.environmentId} |
| 3691 | 3708 | cwd={project.workspaceRoot} |
| 3692 | | projectName={project.displayName} |
| 3709 | projectName={project.title} |
| 3693 | 3710 | faviconPath={project.faviconPath} |
| 3694 | 3711 | projectIcon={project.projectIcon} |
| 3695 | 3712 | className="size-4 shrink-0" |
| ... | ... | @@ -3780,6 +3797,10 @@ export default function Sidebar() { |
| 3780 | 3797 | null |
| 3781 | 3798 | } |
| 3782 | 3799 | projectTitle={ |
| 3800 | projectTitleByKey.get(`${thread.environmentId}:${thread.projectId}`) ?? |
| 3801 | null |
| 3802 | } |
| 3803 | projectDisplayName={ |
| 3783 | 3804 | projectDisplayNameByKey.get( |
| 3784 | 3805 | `${thread.environmentId}:${thread.projectId}`, |
| 3785 | 3806 | ) ?? null |
| ... | ... | @@ -3902,6 +3923,10 @@ export default function Sidebar() { |
| 3902 | 3923 | null |
| 3903 | 3924 | } |
| 3904 | 3925 | projectTitle={ |
| 3926 | projectTitleByKey.get(`${thread.environmentId}:${thread.projectId}`) ?? |
| 3927 | null |
| 3928 | } |
| 3929 | projectDisplayName={ |
| 3905 | 3930 | projectDisplayNameByKey.get( |
| 3906 | 3931 | `${thread.environmentId}:${thread.projectId}`, |
| 3907 | 3932 | ) ?? null |
| ... | ... | @@ -3941,6 +3966,7 @@ export default function Sidebar() { |
| 3941 | 3966 | const items: ReactNode[] = [ |
| 3942 | 3967 | <SidebarDraftBlock |
| 3943 | 3968 | key="draft-sessions" |
| 3969 | projectTitleByKey={projectTitleByKey} |
| 3944 | 3970 | projectDisplayNameByKey={projectDisplayNameByKey} |
| 3945 | 3971 | projectCwdByKey={projectCwdByKey} |
| 3946 | 3972 | projectFaviconPathByKey={projectFaviconPathByKey} |