v1.4-fork-header: fork from message + delete message + header polish + housekeeping
- Fork: POST /api/chats/:id/fork creates a new chat in the same session, copies messages up to target (status=complete) with row-offset clock_timestamp() for stable ordering. Client emits open_chat_in_active_pane event; Workspace opens it in the active pane. No maybeAutoNameChat on forks. - Delete: DELETE /api/chats/:id/messages/:message_id with 409 if the chat is currently streaming. Cascading-forward delete (created_at >= target). MessageBubble Trash button + confirm Dialog. - Header: Projects -> Project -> Session breadcrumb, model badge pill, inline session rename, active file path via new useActivePane() hook. Server now publishes session_renamed on PATCH /api/sessions/:id; client-side dup emit removed from Session.tsx. - Housekeeping: NOW() -> clock_timestamp() in schema.sql defaults, dead PaneTab.tsx and panes/PaneShell.tsx removed, session_panes backfill INSERT removed (CREATE TABLE retained), Tailnet trust comment near app.listen(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { PanelRight, MessageSquare, Terminal, Bot } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { api } from '@/api/client';
|
||||
import { sessionEvents } from '@/hooks/sessionEvents';
|
||||
import { setActivePaneInfo, clearActivePane } from '@/hooks/useActivePane';
|
||||
import type { Chat, WorkspacePane } from '@/api/types';
|
||||
import { ChatPane } from '@/components/panes/ChatPane';
|
||||
import { ChatTabBar } from '@/components/ChatTabBar';
|
||||
@@ -87,6 +88,29 @@ export function Workspace({ sessionId, projectId }: Props) {
|
||||
savePanes(sessionId, panes);
|
||||
}, [sessionId, panes]);
|
||||
|
||||
useEffect(() => {
|
||||
const active = panes[activePaneIdx];
|
||||
if (!active) {
|
||||
clearActivePane();
|
||||
return;
|
||||
}
|
||||
setActivePaneInfo({
|
||||
sessionId,
|
||||
paneId: active.id,
|
||||
kind: active.kind,
|
||||
activeFile: null,
|
||||
});
|
||||
}, [sessionId, panes, activePaneIdx]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearActivePane();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const activePaneIdxRef = useRef(activePaneIdx);
|
||||
activePaneIdxRef.current = activePaneIdx;
|
||||
|
||||
useEffect(() => {
|
||||
return sessionEvents.subscribe((event) => {
|
||||
if (event.type === 'chat_created' && event.session_id === sessionId) {
|
||||
@@ -118,6 +142,9 @@ export function Workspace({ sessionId, projectId }: Props) {
|
||||
setChats((prev) => prev.filter((c) => c.id !== event.chat_id));
|
||||
removeChatFromPanes(event.chat_id);
|
||||
}
|
||||
if (event.type === 'open_chat_in_active_pane') {
|
||||
openChatInPane(activePaneIdxRef.current, event.chat_id);
|
||||
}
|
||||
});
|
||||
}, [sessionId]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user