web(coder UI): ChatInput migration + Thinking render + DiffPanel route fix
Bundles in-progress working-tree UI work not authored this session (CoderPane ChatInput migration, AgentComposerBar/CoderMessageList/tab-bar/sidebar/pane refinements, provider icons) with this session's changes to the same files: MessageBubble renders a collapsible 'Thinking' block from reasoning_text/reasoning_parts (surfacing ACP agent_thought_chunk + native reasoning), and the DiffPanel approve/reject calls are repointed to the real /api/coder/pending/:id/apply and /reject routes (the old /sessions/:id/pending/:id/approve|reject paths did not exist). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,7 @@ interface Props {
|
||||
project: Project | null;
|
||||
/** New BooCode opens a fresh coder session; chat/terminal split in-place. */
|
||||
onAddPane: (kind: 'chat' | 'terminal' | 'coder') => void;
|
||||
onCoderConnectedChange?: (paneId: string, connected: boolean) => void;
|
||||
}
|
||||
|
||||
export function Workspace({
|
||||
@@ -48,6 +49,7 @@ export function Workspace({
|
||||
chatsHook,
|
||||
session,
|
||||
project,
|
||||
onCoderConnectedChange,
|
||||
onAddPane,
|
||||
}: Props) {
|
||||
const {
|
||||
@@ -141,6 +143,7 @@ export function Workspace({
|
||||
|
||||
// Per-coder-pane WS connection (status dot lives in the pane header).
|
||||
const [coderConnected, setCoderConnected] = useState<Record<string, boolean>>({});
|
||||
const [coderLabels, setCoderLabels] = useState<Record<string, string>>({});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full min-h-0">
|
||||
@@ -212,24 +215,23 @@ export function Workspace({
|
||||
onRemovePane={panes.length > 1 ? () => removePane(idx) : undefined}
|
||||
/>
|
||||
)}
|
||||
{isCoder && (
|
||||
<div className="flex items-center gap-2 border-b border-border bg-muted/30 px-2 py-1 shrink-0">
|
||||
{isCoder && !isMobile && (
|
||||
<div className="flex items-center gap-1 border-b border-border px-2 py-1 shrink-0">
|
||||
<Code size={12} className="text-muted-foreground" />
|
||||
<span className="text-xs text-muted-foreground">BooCode</span>
|
||||
<div className="ml-auto flex items-center gap-1.5">
|
||||
<div className="ml-auto flex items-center gap-1">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="inline-flex items-center justify-center size-5 rounded text-muted-foreground hover:bg-muted hover:text-foreground max-md:size-7"
|
||||
className="inline-flex items-center justify-center size-5 rounded text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
aria-label="New pane"
|
||||
title="New pane"
|
||||
>
|
||||
<Plus size={12} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-40">
|
||||
<DropdownMenuContent align="end" className="w-fit">
|
||||
<DropdownMenuItem onSelect={() => onAddPane('chat')}>
|
||||
<MessageSquare size={14} /> New BooChat
|
||||
</DropdownMenuItem>
|
||||
@@ -241,23 +243,12 @@ export function Workspace({
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<span
|
||||
className={cn(
|
||||
'inline-block w-1.5 h-1.5 rounded-full shrink-0',
|
||||
coderConnected[pane.id] ? 'bg-green-500' : 'bg-red-500',
|
||||
)}
|
||||
title={coderConnected[pane.id] ? 'Connected' : 'Disconnected'}
|
||||
/>
|
||||
{panes.length > 1 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
removePane(idx);
|
||||
}}
|
||||
className="inline-flex items-center justify-center size-5 rounded text-muted-foreground hover:bg-muted hover:text-foreground max-md:size-7"
|
||||
aria-label="Close BooCode pane"
|
||||
title="Close BooCode pane"
|
||||
onClick={(e) => { e.stopPropagation(); removePane(idx); }}
|
||||
className="inline-flex items-center justify-center size-5 rounded text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
aria-label="Close pane"
|
||||
>
|
||||
<X size={12} />
|
||||
</button>
|
||||
@@ -283,7 +274,7 @@ export function Workspace({
|
||||
<Plus size={12} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-40">
|
||||
<DropdownMenuContent align="end" className="w-fit">
|
||||
<DropdownMenuItem onSelect={() => onAddPane('chat')}>
|
||||
<MessageSquare size={14} /> New BooChat
|
||||
</DropdownMenuItem>
|
||||
@@ -354,9 +345,15 @@ export function Workspace({
|
||||
chatId={activePaneChatId(pane)}
|
||||
chatPending={isPaneChatPending(pane.id)}
|
||||
projectPath={project?.path}
|
||||
onConnectedChange={(connected) =>
|
||||
onConnectedChange={(connected) => {
|
||||
setCoderConnected((prev) =>
|
||||
prev[pane.id] === connected ? prev : { ...prev, [pane.id]: connected },
|
||||
);
|
||||
onCoderConnectedChange?.(pane.id, connected);
|
||||
}}
|
||||
onAgentLabelChange={(label) =>
|
||||
setCoderLabels((prev) =>
|
||||
prev[pane.id] === label ? prev : { ...prev, [pane.id]: label },
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -384,19 +381,12 @@ export function Workspace({
|
||||
/>
|
||||
) : (
|
||||
<SessionLandingPage
|
||||
sessionId={sessionId}
|
||||
projectId={projectId}
|
||||
chats={chats}
|
||||
sessionId={sessionId}
|
||||
agentId={agentId}
|
||||
onAgentChange={onAgentChange}
|
||||
createChat={() => api.chats.create(sessionId)}
|
||||
onOpenChat={(chatId) => openChatInPane(idx, chatId)}
|
||||
onSend={(content) => void handleLandingSend(idx, content)}
|
||||
onReopenChat={async (chatId) => {
|
||||
await unarchiveChat(chatId);
|
||||
openChatInPane(idx, chatId);
|
||||
}}
|
||||
onArchiveChat={archiveChat}
|
||||
onRenameChat={renameChat}
|
||||
onDeleteChat={deleteChat}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user