Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11009,6 +11009,8 @@ export default function ChatView(props: ChatViewProps) {
isServerThread={isServerThread}
activeThreadTitle={activeThread.title}
activeProject={activeProject ?? null}
parentThreadLink={parentThreadLink}
onOpenThread={onOpenRelatedThread}
rightPanelOpen={inlineRightPanelOwnsTitleBar}
onNewThreadInProject={handleNewThreadInActiveProject}
{...(activeDraftLogicalProjectKey
Expand Down
72 changes: 72 additions & 0 deletions apps/web/src/components/chat/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ interface ChatHeaderProps {
/** Drafts have no server thread yet, so the title carries no action menu. */
isServerThread: boolean;
activeProject: EnvironmentProject | null;
parentThreadLink: { threadId: ThreadId; title: string } | null;
onOpenThread: (threadId: ThreadId) => void;
rightPanelOpen: boolean;
onNewThreadInProject: () => void;
onOpenProjectSettings?: (() => void) | undefined;
Expand Down Expand Up @@ -71,12 +73,47 @@ export const ChatHeader = memo(function ChatHeader({
activeThreadTitle,
isServerThread,
activeProject,
parentThreadLink,
onOpenThread,
rightPanelOpen,
onNewThreadInProject,
onOpenProjectSettings,
}: ChatHeaderProps) {
const activeProjectName = activeProject?.title;
const activeProjectCwd = activeProject?.workspaceRoot ?? null;
const breadcrumbContainerRef = useRef<HTMLDivElement>(null);
const [collapseParentTitle, setCollapseParentTitle] = useState(false);
useEffect(() => {
const list = breadcrumbContainerRef.current?.querySelector("ol");
if (!list || !parentThreadLink) return;
// Measure the untruncated labels, including a collapsed parent's hidden
// text, so expanding and collapsing never change the fit calculation.
const measure = () => {
const gap = Number.parseFloat(getComputedStyle(list).columnGap) || 0;
const width = Array.from(list.children).reduce(
(total, item) => {
const content = item.firstElementChild;
if (!content) return total;
const label = content.matches('[data-slot="workspace-breadcrumb-text"]')
? content
: content.querySelector<HTMLElement>('[data-slot="workspace-breadcrumb-text"]');
const ellipsis = content.querySelector("[data-parent-breadcrumb-ellipsis]");
return (
total +
content.getBoundingClientRect().width +
(label ? label.scrollWidth - label.clientWidth : 0) -
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
(ellipsis?.getBoundingClientRect().width ?? 0)
);
},
gap * (list.children.length - 1),
);
setCollapseParentTitle(width > list.clientWidth);
};
measure();
const observer = new ResizeObserver(measure);
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
observer.observe(list);
return () => observer.disconnect();
}, [activeProjectName, activeThreadTitle, parentThreadLink]);
const activeThreadRef = useMemo(
() => scopeThreadRef(activeThreadEnvironmentId, activeThreadId),
[activeThreadEnvironmentId, activeThreadId],
Expand Down Expand Up @@ -230,6 +267,7 @@ export const ChatHeader = memo(function ChatHeader({
);
return (
<div
ref={breadcrumbContainerRef}
className={cn(
"flex min-w-0 flex-1 items-center gap-2 sm:gap-3",
rightPanelOpen ? "pr-10" : "pr-24",
Expand Down Expand Up @@ -270,6 +308,40 @@ export const ChatHeader = memo(function ChatHeader({
</WorkspaceBreadcrumbSeparator>
</>
) : null}
{parentThreadLink ? (
<>
<WorkspaceBreadcrumbItem>
<Tooltip>
<TooltipTrigger
render={
<button
type="button"
aria-label={`Open parent thread: ${parentThreadLink.title}`}
onClick={() => onOpenThread(parentThreadLink.threadId)}
className="inline-flex min-w-0 max-w-full cursor-pointer items-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
/>
}
>
<WorkspaceBreadcrumbText
aria-hidden
className={collapseParentTitle ? "w-0" : undefined}
>
{parentThreadLink.title}
</WorkspaceBreadcrumbText>
{collapseParentTitle ? (
<span aria-hidden data-parent-breadcrumb-ellipsis>
...
</span>
) : null}
</TooltipTrigger>
<TooltipPopup side="top">{parentThreadLink.title}</TooltipPopup>
</Tooltip>
</WorkspaceBreadcrumbItem>
<WorkspaceBreadcrumbSeparator>
<WorkspaceBreadcrumbText>/</WorkspaceBreadcrumbText>
</WorkspaceBreadcrumbSeparator>
</>
) : null}
<WorkspaceBreadcrumbItem current className="min-w-10 flex-1">
{renamingTitle !== null ? (
<input
Expand Down
Loading