Fix editor integration: move EditorPanel to ChatSessionView

- Fixed Ace import (default import, not named)
- Moved EditorPanel from FilesPanel to ChatSessionView
- Editor now replaces chat view when file is selected (per UI design guide)
- FILES panel now contains only the file tree
- Added editorFilePath state to track open file
- File selection in tree opens editor in content area
- Close button returns to chat view

This matches the UI design guide specification where the File Editor
replaces the Chat View in the content area when a file is selected.
This commit is contained in:
Rob Colbert 2026-05-12 19:45:50 -04:00
parent 1e13f95808
commit fb8b73e290
3 changed files with 39 additions and 47 deletions

View File

@ -1,5 +1,5 @@
import { useState, useCallback, useEffect } from 'react';
import AceEditor from 'react-ace';
import Ace from 'react-ace';
import 'ace-builds/src-noconflict/mode-text';
import 'ace-builds/src-noconflict/theme-tomorrow';
import 'ace-builds/src-noconflict/ext-language_tools';
@ -298,7 +298,7 @@ export default function EditorPanel({ workspaceMode, filePath, onCloseFile }: Ed
{/* ACE Editor */}
{!state.isLoading && (
<div className="flex-1 min-h-0">
<AceEditor
<Ace
mode={state.language}
theme="tomorrow"
name="editor"

View File

@ -1,25 +1,15 @@
import { useState } from "react";
import { WorkspaceMode } from "../lib/types";
import FileTree from "./FileTree";
import EditorPanel from "./EditorPanel";
interface FilesPanelProps {
workspaceMode: WorkspaceMode;
onFileSelect?: (path: string) => void;
}
export default function FilesPanel({ workspaceMode }: FilesPanelProps) {
const [selectedFilePath, setSelectedFilePath] = useState<string | undefined>(undefined);
export default function FilesPanel({ workspaceMode, onFileSelect }: FilesPanelProps) {
const isReadOnly = workspaceMode === WorkspaceMode.Agent;
const isReadWrite = workspaceMode === WorkspaceMode.User;
const handleFileSelect = (path: string) => {
setSelectedFilePath(path);
};
const handleCloseFile = () => {
setSelectedFilePath(undefined);
};
return (
<div className="border-t border-border-subtle flex flex-col flex-1 min-h-0">
<div className="flex items-center justify-between px-4 py-2 bg-bg-tertiary">
@ -49,27 +39,12 @@ export default function FilesPanel({ workspaceMode }: FilesPanelProps) {
</span>
</div>
</div>
{/* Split view: File tree on left, editor on right */}
<div className="flex-1 flex overflow-hidden min-h-0">
{/* File Tree - 30% width, resizable in future */}
<div className="w-1/3 min-w-[200px] border-r border-border-subtle overflow-auto flex-shrink-0">
<FileTree
workspaceMode={workspaceMode}
onFileSelect={handleFileSelect}
/>
</div>
{/* Editor Panel - remaining space */}
<div className="flex-1 min-w-0">
<EditorPanel
workspaceMode={workspaceMode}
filePath={selectedFilePath}
onCloseFile={handleCloseFile}
/>
</div>
<div className="flex-1 overflow-auto">
<FileTree
workspaceMode={workspaceMode}
onFileSelect={onFileSelect}
/>
</div>
<div className="px-4 py-2 bg-bg-tertiary border-t border-border-subtle">
<p className="text-xs text-text-muted">
{isReadOnly

View File

@ -7,6 +7,7 @@ import WorkspaceModeIndicator from '../components/WorkspaceModeIndicator';
import FilesPanel from '../components/FilesPanel';
import LogPanel from '../components/LogPanel';
import ChatTurnComponent from '../components/ChatTurn';
import EditorPanel from '../components/EditorPanel';
import { AppContext } from '../App';
interface LogEntry {
@ -74,6 +75,7 @@ export default function ChatSessionView() {
const [_connectionState, setConnectionState] = useState<'disconnected' | 'connecting' | 'connected' | 'error'>('disconnected');
const [isOtherTab, setIsOtherTab] = useState(false);
const [reconnectAttempts, setReconnectAttempts] = useState(0);
const [editorFilePath, setEditorFilePath] = useState<string | undefined>(undefined);
const messagesEndRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
@ -1086,18 +1088,27 @@ export default function ChatSessionView() {
{isEditingProvider && (
<div className="absolute inset-0 bg-bg-primary/80 z-30" />
)}
{/* Chat View (75%) */}
<div className="flex-1 flex flex-col overflow-hidden">
{/* Messages */}
<div className="flex-1 overflow-y-auto p-3 space-y-2">
{turns.map((turn) => (
<ChatTurnComponent
key={turn._id}
turn={turn}
/>
))}
<div ref={messagesEndRef} />
</div>
{/* File Editor View (replaces Chat View when file is open) */}
{editorFilePath ? (
<EditorPanel
workspaceMode={workspaceMode}
filePath={editorFilePath}
onCloseFile={() => setEditorFilePath(undefined)}
/>
) : (
/* Chat View (75%) */
<div className="flex-1 flex flex-col overflow-hidden">
{/* Messages */}
<div className="flex-1 overflow-y-auto p-3 space-y-2">
{turns.map((turn) => (
<ChatTurnComponent
key={turn._id}
turn={turn}
/>
))}
<div ref={messagesEndRef} />
</div>
{/* Prompt Input */}
<div className="border-t border-border-subtle p-4 bg-bg-secondary shrink-0">
@ -1138,6 +1149,7 @@ export default function ChatSessionView() {
</form>
</div>
</div>
)}
{/* Log Panel (25%) */}
<LogPanel
@ -1375,7 +1387,12 @@ export default function ChatSessionView() {
</div>
{/* FILES Panel */}
<FilesPanel workspaceMode={workspaceMode} />
<FilesPanel
workspaceMode={workspaceMode}
onFileSelect={(path) => {
setEditorFilePath(path);
}}
/>
</div>
</div>
);