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:
@@ -162,6 +162,10 @@ export interface ChatStatusEvent {
|
||||
reason?: ErrorReason;
|
||||
}
|
||||
|
||||
export interface RefetchMessagesEvent {
|
||||
type: 'refetch_messages';
|
||||
}
|
||||
|
||||
export type SessionEvent =
|
||||
| SessionRenamedEvent
|
||||
| ProjectCreatedEvent
|
||||
@@ -186,7 +190,8 @@ export type SessionEvent =
|
||||
| ProjectArchivedEvent
|
||||
| ProjectUnarchivedEvent
|
||||
| ProjectUpdatedEvent
|
||||
| ChatStatusEvent;
|
||||
| ChatStatusEvent
|
||||
| RefetchMessagesEvent;
|
||||
type Listener = (event: SessionEvent) => void;
|
||||
|
||||
const listeners = new Set<Listener>();
|
||||
|
||||
@@ -294,5 +294,21 @@ export function useSessionStream(sessionId: string | undefined) {
|
||||
};
|
||||
}, [sessionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!sessionId) return;
|
||||
return sessionEvents.subscribe((event) => {
|
||||
if (event.type === 'refetch_messages') {
|
||||
void api.messages
|
||||
.list(sessionId)
|
||||
.then((messages) => {
|
||||
setState((s) => applyFrame(s, { type: 'snapshot', messages }));
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
console.warn('refetch_messages failed', err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [sessionId]);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -184,6 +184,7 @@ function applyEvent(prev: SidebarResponse, event: import('./sessionEvents').Sess
|
||||
case 'chat_unarchived':
|
||||
case 'chat_deleted':
|
||||
case 'chat_status':
|
||||
case 'refetch_messages':
|
||||
return prev;
|
||||
case 'project_archived': {
|
||||
const next = prev.projects.filter((p) => p.id !== event.project_id);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useViewport } from './useViewport';
|
||||
|
||||
interface SidebarDrawerState {
|
||||
open: boolean;
|
||||
@@ -13,13 +14,17 @@ const Ctx = createContext<SidebarDrawerState | null>(null);
|
||||
export function SidebarDrawerProvider({ children }: { children: ReactNode }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const location = useLocation();
|
||||
const { isMobile } = useViewport();
|
||||
|
||||
// Auto-close on navigation. Effect fires once on mount too (open default
|
||||
// is false, so no observable effect) and on every pathname change after.
|
||||
useEffect(() => {
|
||||
setOpen(false);
|
||||
}, [location.pathname]);
|
||||
|
||||
// Close drawer on orientation change (landscape→portrait transition).
|
||||
useEffect(() => {
|
||||
setOpen(false);
|
||||
}, [isMobile]);
|
||||
|
||||
const toggle = useCallback(() => setOpen((v) => !v), []);
|
||||
|
||||
return <Ctx.Provider value={{ open, setOpen, toggle }}>{children}</Ctx.Provider>;
|
||||
|
||||
Reference in New Issue
Block a user