batch3 T5: frontend foundation — Pane types, panes API, user-events WS
- Mirror Pane/PaneState/UserStream types - api.panes.* CRUD methods - sessionEvents adds session_updated, session_loaded, open_file_in_browser - useUserEvents hook: single app-level WS to /api/ws/user with reconnect - useSidebar handles session_updated (in-place patch + re-sort) and session_loaded (active-project highlight gap fix); open_file_in_browser is a deliberate no-op here, consumed by Workspace later - App.tsx mounts useUserEvents once Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,9 @@ import type {
|
||||
SidebarResponse,
|
||||
ListDirResult,
|
||||
ViewFileResult,
|
||||
Pane,
|
||||
PaneCreateRequest,
|
||||
PaneUpdateRequest,
|
||||
} from './types';
|
||||
|
||||
export class ApiError extends Error {
|
||||
@@ -113,4 +116,23 @@ export const api = {
|
||||
sidebar: {
|
||||
get: () => request<SidebarResponse>('/api/sidebar'),
|
||||
},
|
||||
|
||||
panes: {
|
||||
getForSession: (sessionId: string) =>
|
||||
request<{ panes: Pane[] }>(`/api/sessions/${sessionId}/panes`),
|
||||
create: (sessionId: string, body: PaneCreateRequest) =>
|
||||
request<Pane>(`/api/sessions/${sessionId}/panes`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
}),
|
||||
update: (id: string, body: PaneUpdateRequest) =>
|
||||
request<Pane>(`/api/panes/${id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
}),
|
||||
remove: (id: string) =>
|
||||
request<void>(`/api/panes/${id}`, { method: 'DELETE' }),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,6 +64,7 @@ export interface SidebarSession {
|
||||
name: string;
|
||||
model: string;
|
||||
updated_at: string;
|
||||
project_id: string;
|
||||
}
|
||||
|
||||
export interface SidebarProject {
|
||||
@@ -96,6 +97,36 @@ export interface ViewFileResult {
|
||||
bytes_returned: number;
|
||||
}
|
||||
|
||||
export type PaneKind = 'chat' | 'file_browser';
|
||||
|
||||
export interface FileBrowserPaneState {
|
||||
open_file?: string | null;
|
||||
filter?: string;
|
||||
expanded_dirs?: string[];
|
||||
}
|
||||
export type ChatPaneState = Record<string, never>;
|
||||
export type PaneState = ChatPaneState | FileBrowserPaneState;
|
||||
|
||||
interface PaneBase {
|
||||
id: string;
|
||||
session_id: string;
|
||||
position: number;
|
||||
created_at: string;
|
||||
}
|
||||
export type Pane = PaneBase & (
|
||||
| { kind: 'chat'; state: ChatPaneState }
|
||||
| { kind: 'file_browser'; state: FileBrowserPaneState }
|
||||
);
|
||||
|
||||
export interface PaneCreateRequest {
|
||||
kind: PaneKind;
|
||||
position?: number;
|
||||
}
|
||||
export interface PaneUpdateRequest {
|
||||
state?: PaneState;
|
||||
position?: number;
|
||||
}
|
||||
|
||||
export type WsFrame =
|
||||
| { type: 'snapshot'; messages: Message[] }
|
||||
| { type: 'message_started'; message_id: string; role: MessageRole }
|
||||
|
||||
Reference in New Issue
Block a user