From 6cb174b7d194085ffcafa120522af27cafb1225f Mon Sep 17 00:00:00 2001 From: "sp.wack" <83104063+amanape@users.noreply.github.com> Date: Thu, 17 Oct 2024 21:14:55 +0400 Subject: [PATCH] [ALL-557] feat(frontend): Add save and discard actions to the editor (#4442) Co-authored-by: mamoodi --- frontend/src/components/editor-actions.tsx | 62 ++++++++++++++++++++ frontend/src/context/files.tsx | 17 ++++-- frontend/src/routes/_oh.app._index/route.tsx | 39 +++++++++++- 3 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 frontend/src/components/editor-actions.tsx diff --git a/frontend/src/components/editor-actions.tsx b/frontend/src/components/editor-actions.tsx new file mode 100644 index 0000000000..e66e9553e6 --- /dev/null +++ b/frontend/src/components/editor-actions.tsx @@ -0,0 +1,62 @@ +import { cn } from "@nextui-org/react"; +import { HTMLAttributes } from "react"; + +interface EditorActionButtonProps { + onClick: () => void; + disabled: boolean; + className: HTMLAttributes["className"]; +} + +function EditorActionButton({ + onClick, + disabled, + className, + children, +}: React.PropsWithChildren) { + return ( + + ); +} + +interface EditorActionsProps { + onSave: () => void; + onDiscard: () => void; + isDisabled: boolean; +} + +export function EditorActions({ + onSave, + onDiscard, + isDisabled, +}: EditorActionsProps) { + return ( +
+ + Save + + + + Discard + +
+ ); +} diff --git a/frontend/src/context/files.tsx b/frontend/src/context/files.tsx index c600eb08ca..cc1f5d7311 100644 --- a/frontend/src/context/files.tsx +++ b/frontend/src/context/files.tsx @@ -27,6 +27,7 @@ interface FilesContextType { modifiedFiles: Record; modifyFileContent: (path: string, content: string) => void; saveFileContent: (path: string) => string | undefined; + discardChanges: (path: string) => void; } const FilesContext = React.createContext( @@ -62,19 +63,25 @@ function FilesProvider({ children }: FilesProviderProps) { [files, modifiedFiles], ); + const discardChanges = React.useCallback((path: string) => { + setModifiedFiles((prev) => { + const newModifiedFiles = { ...prev }; + delete newModifiedFiles[path]; + return newModifiedFiles; + }); + }, []); + const saveFileContent = React.useCallback( (path: string): string | undefined => { const content = modifiedFiles[path]; if (content) { setFiles((prev) => ({ ...prev, [path]: content })); - const newModifiedFiles = { ...modifiedFiles }; - delete newModifiedFiles[path]; - setModifiedFiles(newModifiedFiles); + discardChanges(path); } return content; }, - [files, modifiedFiles, selectedPath], + [files, modifiedFiles, selectedPath, discardChanges], ); const value = React.useMemo( @@ -88,6 +95,7 @@ function FilesProvider({ children }: FilesProviderProps) { modifiedFiles, modifyFileContent, saveFileContent, + discardChanges, }), [ paths, @@ -99,6 +107,7 @@ function FilesProvider({ children }: FilesProviderProps) { modifiedFiles, modifyFileContent, saveFileContent, + discardChanges, ], ); diff --git a/frontend/src/routes/_oh.app._index/route.tsx b/frontend/src/routes/_oh.app._index/route.tsx index 9a5c0a73e9..5cc533e15d 100644 --- a/frontend/src/routes/_oh.app._index/route.tsx +++ b/frontend/src/routes/_oh.app._index/route.tsx @@ -13,6 +13,7 @@ import OpenHands from "#/api/open-hands"; import { useSocket } from "#/context/socket"; import CodeEditorCompoonent from "./code-editor-component"; import { useFiles } from "#/context/files"; +import { EditorActions } from "#/components/editor-actions"; export const clientLoader = async () => { const token = localStorage.getItem("token"); @@ -48,7 +49,13 @@ export function ErrorBoundary() { function CodeEditor() { const { token } = useLoaderData(); const { runtimeActive } = useSocket(); - const { setPaths } = useFiles(); + const { + setPaths, + selectedPath, + modifiedFiles, + saveFileContent: saveNewFileContent, + discardChanges, + } = useFiles(); const agentState = useSelector( (state: RootState) => state.agent.curAgentState, @@ -68,10 +75,38 @@ function CodeEditor() { [agentState], ); + const handleSave = async () => { + if (selectedPath) { + const content = saveNewFileContent(selectedPath); + + if (content && token) { + try { + await OpenHands.saveFile(token, selectedPath, content); + } catch (error) { + // handle error + } + } + } + }; + + const handleDiscard = () => { + if (selectedPath) discardChanges(selectedPath); + }; + return (
-
+
+ {selectedPath && ( +
+ {selectedPath} + +
+ )}