From 7e825b571f6d82cd3c2a88630f533ca498ab070f Mon Sep 17 00:00:00 2001 From: Akki Date: Tue, 16 Apr 2024 16:43:04 +0400 Subject: [PATCH] fix(): build out opendevin modal component (#1141) --- frontend/src/components/LoadMessageModal.tsx | 117 +++++++------- frontend/src/components/ODModal.tsx | 71 +++++++++ frontend/src/components/SettingModal.tsx | 159 +++++++++---------- frontend/src/i18n/translation.json | 16 +- frontend/tailwind.config.js | 33 ++-- 5 files changed, 247 insertions(+), 149 deletions(-) create mode 100644 frontend/src/components/ODModal.tsx diff --git a/frontend/src/components/LoadMessageModal.tsx b/frontend/src/components/LoadMessageModal.tsx index bc4caf9954..ef0262dfb9 100644 --- a/frontend/src/components/LoadMessageModal.tsx +++ b/frontend/src/components/LoadMessageModal.tsx @@ -1,77 +1,82 @@ import React from "react"; -import { - Modal, - ModalContent, - ModalHeader, - ModalBody, - ModalFooter, - Button, -} from "@nextui-org/react"; +import { Button } from "@nextui-org/react"; import { fetchMsgs, clearMsgs } from "../services/session"; import { sendChatMessageFromEvent } from "../services/chatService"; import { handleAssistantMessage } from "../services/actions"; import { ResFetchMsg } from "../types/ResponseType"; +import ODModal from "./ODModal"; +import toast from "../utils/toast"; -interface Props { +interface LoadMessageModalProps { isOpen: boolean; onClose: () => void; } -function LoadMessageModal({ isOpen, onClose }: Props): JSX.Element { - const handleDelMsg = () => { +function LoadMessageModal({ + isOpen, + onClose, +}: LoadMessageModalProps): JSX.Element { + const handleStartNewSession = () => { clearMsgs().then().catch(); onClose(); }; - const handleLoadMsg = () => { - fetchMsgs() - .then((data) => { - if ( - data === undefined || - data.messages === undefined || - data.messages.length === 0 - ) { - return; + const handleResumeSession = async () => { + try { + const data = await fetchMsgs(); + if (!data || !data.messages || data.messages.length === 0) { + return; + } + + data.messages.forEach((msg: ResFetchMsg) => { + switch (msg.role) { + case "user": + sendChatMessageFromEvent(msg.payload); + break; + case "assistant": + handleAssistantMessage(msg.payload); + break; + default: + break; } - const { messages } = data; - messages.forEach((msg: ResFetchMsg) => { - switch (msg.role) { - case "user": - sendChatMessageFromEvent(msg.payload); - break; - case "assistant": - handleAssistantMessage(msg.payload); - break; - default: - } - }); - }) - .catch(); - onClose(); + }); + + onClose(); + } catch (error) { + toast.stickyError("ws", "Error fetching the session"); + } }; return ( - - - <> - - Unfinished Session Detected - - - You have an unfinished session. Do you want to load it? - - - - - - - - - + + Resume Session + + } + secondaryAction={ + + } + > +

+ You seem to have an unfinished task. Would you like to pick up where you + left off or start fresh? +

+
); } diff --git a/frontend/src/components/ODModal.tsx b/frontend/src/components/ODModal.tsx new file mode 100644 index 0000000000..c36ea6fca4 --- /dev/null +++ b/frontend/src/components/ODModal.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { + ModalProps, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, +} from "@nextui-org/react"; + +interface ODModalProps extends Omit { + title?: string; + subtitle?: string; + primaryAction?: React.ReactNode; + secondaryAction?: React.ReactNode; + children: React.ReactNode; + isOpen: boolean; + onClose: () => void; + size: "sm" | "md"; +} + +function ODModal(props: ODModalProps): React.ReactElement { + const { + children, + title, + subtitle, + primaryAction, + secondaryAction, + size, + ...modalProps + } = props; + + return ( + + + + {title &&

{title}

} + {subtitle && ( + + {subtitle} + + )} +
+ {children} + {(primaryAction || secondaryAction) && ( + + {primaryAction} + {secondaryAction} + + )} +
+
+ ); +} + +ODModal.defaultProps = { + title: "", + subtitle: "", + primaryAction: null, + secondaryAction: null, +}; + +export default ODModal; diff --git a/frontend/src/components/SettingModal.tsx b/frontend/src/components/SettingModal.tsx index 4042203f07..79df456508 100644 --- a/frontend/src/components/SettingModal.tsx +++ b/frontend/src/components/SettingModal.tsx @@ -4,11 +4,6 @@ import { Autocomplete, AutocompleteItem, Button, - Modal, - ModalBody, - ModalContent, - ModalFooter, - ModalHeader, Select, SelectItem, } from "@nextui-org/react"; @@ -25,6 +20,7 @@ import { RootState } from "../store"; import { I18nKey } from "../i18n/declaration"; import { AvailableLanguages } from "../i18n"; import { ArgConfigType } from "../types/ConfigType"; +import ODModal from "./ODModal"; interface Props { isOpen: boolean; @@ -88,82 +84,83 @@ function InnerSettingModal({ isOpen, onClose }: Props): JSX.Element { item.toLowerCase().includes(input.toLowerCase()); return ( - - - <> - - {t(I18nKey.CONFIGURATION$MODAL_TITLE)} - - - ({ - label: v, - value: v, - }))} - label={t(I18nKey.CONFIGURATION$MODEL_SELECT_LABEL)} - placeholder={t(I18nKey.CONFIGURATION$MODEL_SELECT_PLACEHOLDER)} - selectedKey={model} - onSelectionChange={(key) => { - setModel(key as string); - }} - onInputChange={(e) => setInputModel(e)} - onKeyDown={(e: KeyboardEvent) => e.continuePropagation()} - defaultFilter={customFilter} - defaultInputValue={inputModel} - allowsCustomValue - > - {(item: { label: string; value: string }) => ( - - {item.label} - - )} - - - ({ - label: v, - value: v, - }))} - label={t(I18nKey.CONFIGURATION$AGENT_SELECT_LABEL)} - placeholder={t(I18nKey.CONFIGURATION$AGENT_SELECT_PLACEHOLDER)} - defaultSelectedKey={agent} - onSelectionChange={(key) => { - setAgent(key as string); - }} - onKeyDown={(e: KeyboardEvent) => e.continuePropagation()} - defaultFilter={customFilter} - > - {(item: { label: string; value: string }) => ( - - {item.label} - - )} - - - - - - - - - - - + + {t(I18nKey.CONFIGURATION$MODAL_SAVE_BUTTON_LABEL)} + + } + secondaryAction={ + + } + > + <> + ({ + label: v, + value: v, + }))} + label={t(I18nKey.CONFIGURATION$MODEL_SELECT_LABEL)} + placeholder={t(I18nKey.CONFIGURATION$MODEL_SELECT_PLACEHOLDER)} + selectedKey={model} + onSelectionChange={(key) => { + setModel(key as string); + }} + onInputChange={(e) => setInputModel(e)} + onKeyDown={(e: KeyboardEvent) => e.continuePropagation()} + defaultFilter={customFilter} + defaultInputValue={inputModel} + allowsCustomValue + > + {(item: { label: string; value: string }) => ( + + {item.label} + + )} + + ({ + label: v, + value: v, + }))} + label={t(I18nKey.CONFIGURATION$AGENT_SELECT_LABEL)} + placeholder={t(I18nKey.CONFIGURATION$AGENT_SELECT_PLACEHOLDER)} + defaultSelectedKey={agent} + onSelectionChange={(key) => { + setAgent(key as string); + }} + onKeyDown={(e: KeyboardEvent) => e.continuePropagation()} + defaultFilter={customFilter} + > + {(item: { label: string; value: string }) => ( + + {item.label} + + )} + + + + ); } diff --git a/frontend/src/i18n/translation.json b/frontend/src/i18n/translation.json index 46053dd259..53944c828c 100644 --- a/frontend/src/i18n/translation.json +++ b/frontend/src/i18n/translation.json @@ -95,6 +95,18 @@ "es": "Configuración", "tr": "Konfigürasyon" }, + "CONFIGURATION$MODAL_SUB_TITLE": { + "en": "Adjust settings to your liking", + "zh-CN": "根据您的喜好调整设置", + "de": "Passen Sie die Einstellungen nach Ihren Wünschen an ", + "ko-KR": "원하는 대로 설정 조정", + "no": "Juster innstillinger etter dine ønsker ", + "zh-TW": "調整設定以符合您的喜好", + "it": "Regola le impostazioni in base alle tue preferenze", + "pt": "Ajuste as configurações de acordo com sua preferência", + "es": "Ajusta la configuración a tu gusto", + "tr": "Ayarları isteğinize göre ayarlayın" + }, "CONFIGURATION$MODEL_SELECT_LABEL": { "en": "Model", "zh-CN": "模型", @@ -201,7 +213,7 @@ "it": "Invia un messaggio (non interromperà l'Assistente)", "pt": "Envie uma mensagem (não interromperá o Assistente)", "es": "Enviar un mensaje (no interrumpirá al Asistente)", - "tr": "Bir mesaj gönderin (Asistan Kesilmeyecek)" + "tr": "Bir mesaj gönderin (Asistan Kesilmeyecek)" }, "CHAT_INTERFACE$INPUT_SEND_MESSAGE_BUTTON_CONTENT": { "en": "Send", @@ -215,4 +227,4 @@ "es": "Enviar", "tr": "Gönder" } -} + } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index d5a11b62a7..46c0a0b68f 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,14 +1,27 @@ /** @type {import('tailwindcss').Config} */ const { nextui } = require("@nextui-org/react"); export default { - content: [ - "./src/**/*.{js,ts,jsx,tsx}", - "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}", - ], - darkMode: "class", - plugins: [ - nextui({ - defaultTheme: "dark", - }), - ], + content: [ + "./src/**/*.{js,ts,jsx,tsx}", + "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}", + ], + darkMode: "class", + plugins: [ + nextui({ + defaultTheme: "dark", + layout: { + radius: { + small: "5px", + large: "20px", + }, + }, + themes: { + dark: { + colors: { + primary:"#4465DB", + }, + } + } + }), + ], };