- Added react-ace and ace-builds dependencies - Created EditorPanel component with ACE editor integration - Implemented file read/write socket protocol - Added backend handlers for fileReadRequest and fileWriteRequest - Implemented file loading from tree click - Implemented file saving with Ctrl+S shortcut - Added dirty state tracking and unsaved changes indicator - Enforced workspace mode (read-only in Agent mode) - Added security: path traversal prevention, binary file detection, file size limits - Updated FilesPanel with split view (tree + editor) Enables Users to edit files for the first time in Gadget Code.
85 lines
2.8 KiB
TypeScript
85 lines
2.8 KiB
TypeScript
import { useState } from "react";
|
|
import { WorkspaceMode } from "../lib/types";
|
|
import FileTree from "./FileTree";
|
|
import EditorPanel from "./EditorPanel";
|
|
|
|
interface FilesPanelProps {
|
|
workspaceMode: WorkspaceMode;
|
|
}
|
|
|
|
export default function FilesPanel({ workspaceMode }: FilesPanelProps) {
|
|
const [selectedFilePath, setSelectedFilePath] = useState<string | undefined>(undefined);
|
|
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">
|
|
<h3 className="text-sm font-semibold text-text-secondary uppercase tracking-wider">
|
|
Files
|
|
</h3>
|
|
<div className="flex items-center gap-1">
|
|
<span
|
|
className={`w-6 h-6 flex items-center justify-center font-mono font-bold text-xs rounded border ${
|
|
isReadWrite
|
|
? "border-green-500 strobe text-green-500"
|
|
: "border-border-default text-text-muted"
|
|
}`}
|
|
title="Read / Write"
|
|
>
|
|
RW
|
|
</span>
|
|
<span
|
|
className={`w-6 h-6 flex items-center justify-center font-mono font-bold text-xs rounded border ${
|
|
isReadOnly
|
|
? "border-green-500 strobe text-green-500"
|
|
: "border-border-default text-text-muted"
|
|
}`}
|
|
title="Read Only"
|
|
>
|
|
RO
|
|
</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>
|
|
|
|
<div className="px-4 py-2 bg-bg-tertiary border-t border-border-subtle">
|
|
<p className="text-xs text-text-muted">
|
|
{isReadOnly
|
|
? "Read-only: Agent is working"
|
|
: isReadWrite
|
|
? "Read-write mode enabled"
|
|
: "Select User or Agent mode to access files"}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|