Răsfoiți Sursa

Add code editor and separate tabs (#43)

Jim Su 2 ani în urmă
părinte
comite
cdb83c72e2

+ 36 - 0
frontend/package-lock.json

@@ -8,6 +8,7 @@
       "name": "opendevin-frontend",
       "version": "0.1.0",
       "dependencies": {
+        "@monaco-editor/react": "^4.6.0",
         "@testing-library/jest-dom": "^5.17.0",
         "@testing-library/react": "^13.4.0",
         "@testing-library/user-event": "^13.5.0",
@@ -1663,6 +1664,30 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@monaco-editor/loader": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz",
+      "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==",
+      "dependencies": {
+        "state-local": "^1.0.6"
+      },
+      "peerDependencies": {
+        "monaco-editor": ">= 0.21.0 < 1"
+      }
+    },
+    "node_modules/@monaco-editor/react": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz",
+      "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==",
+      "dependencies": {
+        "@monaco-editor/loader": "^1.4.0"
+      },
+      "peerDependencies": {
+        "monaco-editor": ">= 0.25.0 < 1",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -7281,6 +7306,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/monaco-editor": {
+      "version": "0.47.0",
+      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.47.0.tgz",
+      "integrity": "sha512-VabVvHvQ9QmMwXu4du008ZDuyLnHs9j7ThVFsiJoXSOQk18+LF89N4ADzPbFenm0W4V2bGHnFBztIRQTgBfxzw==",
+      "peer": true
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -8503,6 +8534,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/state-local": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
+      "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="
+    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",

+ 1 - 0
frontend/package.json

@@ -4,6 +4,7 @@
   "private": true,
   "type": "module",
   "dependencies": {
+    "@monaco-editor/react": "^4.6.0",
     "@testing-library/jest-dom": "^5.17.0",
     "@testing-library/react": "^13.4.0",
     "@testing-library/user-event": "^13.5.0",

+ 42 - 18
frontend/src/App.tsx

@@ -4,11 +4,41 @@ import "./App.css";
 import ChatInterface from "./components/ChatInterface";
 import Terminal from "./components/Terminal";
 import Planner from "./components/Planner";
+import CodeEditor from "./components/CodeEditor";
 
-function App(): JSX.Element {
-  const [activeTab, setActiveTab] = useState<"terminal" | "planner">(
-    "terminal",
+const TAB_OPTIONS = ["terminal", "planner", "code"] as const;
+type TabOption = (typeof TAB_OPTIONS)[number];
+
+const tabData = {
+  terminal: {
+    name: "Terminal",
+    component: <Terminal />,
+  },
+  planner: {
+    name: "Planner",
+    component: <Planner />,
+  },
+  code: {
+    name: "Code Editor",
+    component: <CodeEditor />,
+  },
+};
+
+type TabProps = {
+  name: string;
+  active: boolean;
+  onClick: () => void;
+};
+function Tab({ name, active, onClick }: TabProps): JSX.Element {
+  return (
+    <div className={`tab ${active ? "active" : ""}`} onClick={() => onClick()}>
+      {name}
+    </div>
   );
+}
+
+function App(): JSX.Element {
+  const [activeTab, setActiveTab] = useState<TabOption>("terminal");
 
   return (
     <div className="app">
@@ -17,22 +47,16 @@ function App(): JSX.Element {
       </div>
       <div className="right-pane">
         <div className="tab-container">
-          <div
-            className={`tab ${activeTab === "terminal" ? "active" : ""}`}
-            onClick={() => setActiveTab("terminal")}
-          >
-            Shell
-          </div>
-          <div
-            className={`tab ${activeTab === "planner" ? "active" : ""}`}
-            onClick={() => setActiveTab("planner")}
-          >
-            Planner
-          </div>
-        </div>
-        <div className="tab-content">
-          {activeTab === "terminal" ? <Terminal /> : <Planner />}
+          {TAB_OPTIONS.map((tab) => (
+            <Tab
+              key={tab}
+              name={tabData[tab].name}
+              active={activeTab === tab}
+              onClick={() => setActiveTab(tab)}
+            />
+          ))}
         </div>
+        <div className="tab-content">{tabData[activeTab].component}</div>
       </div>
     </div>
   );

+ 19 - 0
frontend/src/components/CodeEditor.tsx

@@ -0,0 +1,19 @@
+import React from "react";
+import Editor from "@monaco-editor/react";
+
+function CodeEditor(): JSX.Element {
+  const handleEditorChange = (value: string | undefined) => {
+    console.log("Content changed:", value);
+  };
+
+  return (
+    <Editor
+      height="100%"
+      defaultLanguage="javascript"
+      defaultValue="// Welcome to OpenDevin!"
+      onChange={handleEditorChange}
+    />
+  );
+}
+
+export default CodeEditor;