diff --git a/web/src/components/internal-ui/ChatBox.tsx b/web/src/components/internal-ui/ChatBox.tsx index 34ba409d..9de9cfe2 100644 --- a/web/src/components/internal-ui/ChatBox.tsx +++ b/web/src/components/internal-ui/ChatBox.tsx @@ -6,6 +6,7 @@ import { ENDPOINTS, UserType } from "../../features/constants"; import useGptStore from "../../utils/store"; import { useEffect } from "react"; import { v4 as uuid } from "uuid"; +import { useLocation } from "react-router-dom"; interface Props { messageData: Message[]; @@ -14,14 +15,17 @@ interface Props { id: string; } -interface BasicGenApiResponse { +interface BasicApiResponse { output: string; } const ChatBox = ({ messageData, endpoint, request, id }: Props) => { const addMessage = useGptStore((s) => s.addMessage); + const resetMessages = useGptStore((s) => s.resetMessages); - const { data, error, isLoading } = usePost( + const location = useLocation(); + + const { data, error, isLoading } = usePost( endpoint, request, id @@ -29,9 +33,12 @@ const ChatBox = ({ messageData, endpoint, request, id }: Props) => { useEffect(() => { if (data?.data.output) addMessage(UserType.BOT, data?.data.output!, uuid()); - console.log(messageData); }, [request, data]); + useEffect(() => { + return () => resetMessages(); + }, [location.pathname]); + return ( { + return ( +
+ +
+ +

Unathorized Route

+
+ + + +
+
+ ); +}; + +export default ErrorPage; diff --git a/web/src/components/internal-ui/Input.tsx b/web/src/components/internal-ui/Input.tsx index e1cdc466..40b8a340 100644 --- a/web/src/components/internal-ui/Input.tsx +++ b/web/src/components/internal-ui/Input.tsx @@ -1,19 +1,23 @@ import { useFormContext } from "react-hook-form"; -import { BasicGenFields } from "../../features/constants"; +import { BasicGenFields, BugFixFields } from "../../features/constants"; import { validateForm } from "../../utils/formValidator"; interface Props { - fieldName: BasicGenFields; + fieldName: string; label?: string; placeholder?: string; } -const Input = ({ fieldName, label, placeholder }: Props) => { +const Input = ({ fieldName, label, placeholder = "Placeholder" }: Props) => { const { register, formState: { errors }, } = useFormContext(); + const showTextArea = + fieldName === BasicGenFields.INPUT || + fieldName === BugFixFields.BUG_DESCRIPTION; + const defaultStyle = "border border-stone-600 bg-stone-900 rounded-md flex h-auto p-4"; @@ -23,7 +27,7 @@ const Input = ({ fieldName, label, placeholder }: Props) => {
{label}
- {fieldName !== BasicGenFields.INPUT ? ( + {!showTextArea ? ( { - const isOpen = useGptStore((s) => s.isOpen); - const setIsOpen = useGptStore((s) => s.setIsOpen); - - return ( - <> - setIsOpen(false)} - title="Devops-GPT API" - content={btnMappings.map((route) => ( - - - - ))} - /> -
- -
- - ); -}; - -export default Landing; diff --git a/web/src/features/basicGen/BasicGen.tsx b/web/src/features/basicGen/BasicGen.tsx index fbf94633..51db2e3d 100644 --- a/web/src/features/basicGen/BasicGen.tsx +++ b/web/src/features/basicGen/BasicGen.tsx @@ -1,87 +1,64 @@ -import { FormProvider, useForm } from "react-hook-form"; +import { FormProvider } from "react-hook-form"; import Input from "../../components/internal-ui/Input"; -import { BasicGenFields, ENDPOINTS, UserType } from "../constants"; +import { basicGenDefaultValues, BasicGenFields, ENDPOINTS } from "../constants"; import { Button, HStack, Stack } from "@chakra-ui/react"; import useGptStore from "../../utils/store"; import ChatBox from "../../components/internal-ui/ChatBox"; import { ApiRequestBasicGen, BasicGenFormData } from "../model"; -import { useEffect, useState } from "react"; + import { IoSendOutline } from "react-icons/io5"; -import { v4 as uuid } from "uuid"; + +import useFormHandler from "../../hooks/useFormHandler"; +import { basicGenMapper } from "../../utils/mapperFunctions"; const BasicGen = () => { - const formMethods = useForm({ - defaultValues: { - minToken: 100, - maxToken: 500, - service: "terraform", - input: undefined, - }, - mode: "onSubmit", - }); + const { formMethods, handleSubmit, onSubmit, request } = useFormHandler< + BasicGenFormData, + ApiRequestBasicGen + >(basicGenDefaultValues); - const { handleSubmit } = formMethods; + const handleFormSubmit = handleSubmit((data) => { + onSubmit(basicGenMapper(data), data.input); + }); const messages = useGptStore((s) => s.messages); - const addMessage = useGptStore((s) => s.addMessage); - const [req, setReq] = useState(null); - - const onSubmit = (data: BasicGenFormData) => { - addMessage(UserType.USER, data.input, uuid()); - const request: ApiRequestBasicGen = { - min_token: data.minToken, - max_token: data.maxToken, - service: data.service, - input: data.input, - requestId: uuid(), - }; - if (data.input) setReq(request); - }; - - useEffect(() => { - return () => setReq(null); - }, []); return ( -
- -
void handleSubmit(onSubmit)(e)}> - -
- - - -
- - + + +
+ + + +
+ + + + - -
- -
-
+ + + + + + ); }; diff --git a/web/src/features/bugFix/BugFix.tsx b/web/src/features/bugFix/BugFix.tsx new file mode 100644 index 00000000..536cd833 --- /dev/null +++ b/web/src/features/bugFix/BugFix.tsx @@ -0,0 +1,67 @@ +import { Button, HStack, Stack } from "@chakra-ui/react"; +import { FormProvider } from "react-hook-form"; +import { IoSendOutline } from "react-icons/io5"; +import ChatBox from "../../components/internal-ui/ChatBox"; +import Input from "../../components/internal-ui/Input"; +import useFormHandler from "../../hooks/useFormHandler"; +import { bugFixMapper } from "../../utils/mapperFunctions"; +import useGptStore from "../../utils/store"; +import { bugFixDefaultValues, BugFixFields, ENDPOINTS } from "../constants"; +import { ApiRequestBugFix, BugFixFormData } from "../model"; + +const BugFix = () => { + const { request, handleSubmit, onSubmit, formMethods } = useFormHandler< + BugFixFormData, + ApiRequestBugFix + >(bugFixDefaultValues); + + const messages = useGptStore((s) => s.messages); + + const handleFormSubmit = handleSubmit((data) => { + onSubmit(bugFixMapper(data), data.bugDescription); + }); + + return ( + +
+ +
+ + + + +
+ + + + + +
+
+
+ ); +}; + +export default BugFix; diff --git a/web/src/features/constants.ts b/web/src/features/constants.ts index b64737e8..1e23b5da 100644 --- a/web/src/features/constants.ts +++ b/web/src/features/constants.ts @@ -1,8 +1,16 @@ export enum BasicGenFields { MIN_TOKEN = "minToken", MAX_TOKEN = "maxToken", + SERVICE = "service", INPUT = "input", +} + +export enum BugFixFields { + MIN_TOKEN = "minToken", + MAX_TOKEN = "maxToken", SERVICE = "service", + VERSION = "version", + BUG_DESCRIPTION = "bugDescription", } export enum UserType { @@ -19,3 +27,18 @@ export enum ENDPOINTS { getDonwload = "/download", getDirectory = "/list-directory", } + +export const basicGenDefaultValues = { + minToken: 100, + maxToken: 500, + service: "terraform", + input: undefined, +}; + +export const bugFixDefaultValues = { + minToken: 100, + maxToken: 500, + service: "terraform", + version: "latest", + bugDescription: undefined, +}; diff --git a/web/src/features/model.ts b/web/src/features/model.ts index c5adf706..00e35722 100644 --- a/web/src/features/model.ts +++ b/web/src/features/model.ts @@ -20,3 +20,20 @@ export interface ApiRequestBasicGen { input: string; requestId: string; } + +export interface BugFixFormData { + minToken: number; + maxToken: number; + service: string; + bugDescription: string; + version: string; +} + +export interface ApiRequestBugFix { + min_token: number; + max_token: number; + service: string; + bug_description: string; + version: string; + requestId: string; +} diff --git a/web/src/hooks/useFormHandler.ts b/web/src/hooks/useFormHandler.ts new file mode 100644 index 00000000..9a59694d --- /dev/null +++ b/web/src/hooks/useFormHandler.ts @@ -0,0 +1,23 @@ +import { useState } from "react"; +import { FieldValues, useForm, UseFormProps } from "react-hook-form"; +import { v4 as uuid } from "uuid"; +import useGptStore from "../utils/store"; +import { UserType } from "../features/constants"; + +const useFormHandler = ( + initialValues: UseFormProps["defaultValues"] +) => { + const [request, setRequest] = useState(); + const formMethods = useForm({ defaultValues: initialValues }); + const addMessage = useGptStore((s) => s.addMessage); + const { handleSubmit } = formMethods; + + const onSubmit = (data: K, content: string) => { + addMessage(UserType.USER, content, uuid()); + formMethods.reset(); + if (data) setRequest({ ...data, requestId: uuid() }); + }; + return { formMethods, request, handleSubmit, onSubmit }; +}; + +export default useFormHandler; diff --git a/web/src/layouts/Header.tsx b/web/src/layouts/Header.tsx index 1c3c1c07..b7bbf215 100644 --- a/web/src/layouts/Header.tsx +++ b/web/src/layouts/Header.tsx @@ -1,18 +1,19 @@ -import { Link } from "react-router-dom"; import { Image } from "@chakra-ui/react"; +import useGptStore from "../utils/store"; const Header = () => { + const setIsOpen = useGptStore((s) => s.setIsOpen); return ( <>
- +
); diff --git a/web/src/layouts/Layout.tsx b/web/src/layouts/Layout.tsx index 6bbc4d31..ddf9665c 100644 --- a/web/src/layouts/Layout.tsx +++ b/web/src/layouts/Layout.tsx @@ -1,9 +1,27 @@ +import { Button } from "@chakra-ui/react"; +import Drawer from "../components/internal-ui/Drawer"; +import { btnMappings } from "../utils/routing"; +import useGptStore from "../utils/store"; import Header from "./Header"; -import { Outlet } from "react-router-dom"; +import { Link, Outlet } from "react-router-dom"; const Layout = () => { + const isOpen = useGptStore((s) => s.isOpen); + const setIsOpen = useGptStore((s) => s.setIsOpen); return ( <> + setIsOpen(false)} + title="Devops-GPT API" + content={btnMappings.map((route) => ( + + + + ))} + />
diff --git a/web/src/utils/formValidator.tsx b/web/src/utils/formValidator.tsx index 6306efeb..fca66fa7 100644 --- a/web/src/utils/formValidator.tsx +++ b/web/src/utils/formValidator.tsx @@ -1,8 +1,8 @@ -import { RegisterOptions, FieldValues } from "react-hook-form"; -import { BasicGenFields } from "../features/constants"; +import { RegisterOptions } from "react-hook-form"; +import { BasicGenFields, BugFixFields } from "../features/constants"; -export const validateForm = (fieldName: BasicGenFields) => { - let validationRules: RegisterOptions = {}; +export const validateForm = (fieldName: string) => { + let validationRules: RegisterOptions = {}; switch (fieldName) { case BasicGenFields.MIN_TOKEN: validationRules = { @@ -28,6 +28,8 @@ export const validateForm = (fieldName: BasicGenFields) => { }, }; break; + case BugFixFields.VERSION: + case BugFixFields.BUG_DESCRIPTION: case BasicGenFields.INPUT: validationRules = { required: { @@ -35,6 +37,7 @@ export const validateForm = (fieldName: BasicGenFields) => { message: "Input can not be empty", }, }; + break; } return validationRules; }; diff --git a/web/src/utils/mapperFunctions.ts b/web/src/utils/mapperFunctions.ts new file mode 100644 index 00000000..33dbbe47 --- /dev/null +++ b/web/src/utils/mapperFunctions.ts @@ -0,0 +1,23 @@ +import { + BasicGenFormData, + ApiRequestBasicGen, + BugFixFormData, + ApiRequestBugFix, +} from "../features/model"; + +export const basicGenMapper = (data: BasicGenFormData): ApiRequestBasicGen => ({ + min_token: data.minToken, + max_token: data.maxToken, + service: data.service, + input: data.input, + requestId: "", +}); + +export const bugFixMapper = (data: BugFixFormData): ApiRequestBugFix => ({ + min_token: data.minToken, + max_token: data.maxToken, + bug_description: data.bugDescription, + service: data.service, + version: data.version, + requestId: "", +}); diff --git a/web/src/utils/router.tsx b/web/src/utils/router.tsx index 3d1d73b5..5888a388 100644 --- a/web/src/utils/router.tsx +++ b/web/src/utils/router.tsx @@ -1,15 +1,17 @@ import { createBrowserRouter } from "react-router-dom"; import Layout from "../layouts/Layout"; -import Landing from "../components/internal-ui/Landing"; import BasicGen from "../features/basicGen/BasicGen"; import { ENDPOINTS } from "../features/constants"; +import BugFix from "../features/bugFix/BugFix"; +import ErrorPage from "../components/internal-ui/ErrorPage"; export const router = createBrowserRouter([ { path: "/", element: , + errorElement: , children: [ - { index: true, element: }, - { path: ENDPOINTS.postBasic, element: }, + { index: true, element: }, + { path: ENDPOINTS.postFix, element: }, ], }, ]); diff --git a/web/src/utils/routing.ts b/web/src/utils/routing.ts index 2bf7fa14..9582f0a1 100644 --- a/web/src/utils/routing.ts +++ b/web/src/utils/routing.ts @@ -1,7 +1,7 @@ import { ENDPOINTS } from "../features/constants"; export const btnMappings = [ - { label: "Basic", route: ENDPOINTS.postBasic }, + { label: "Basic", route: "/" }, { label: "Bug fix", route: ENDPOINTS.postFix }, { label: "Installation", route: ENDPOINTS.postInstall }, { label: "Template - IaC", route: ENDPOINTS.PostIacTemp }, diff --git a/web/src/utils/store.ts b/web/src/utils/store.ts index bd300168..e395afea 100644 --- a/web/src/utils/store.ts +++ b/web/src/utils/store.ts @@ -8,10 +8,12 @@ interface DevOpsStore { messages: Message[]; addMessage: (user: UserType, content: string, id: string) => void; + + resetMessages: () => void; } const initialState: Pick = { - isOpen: true, + isOpen: false, messages: [], }; @@ -22,6 +24,7 @@ const useGptStore = create((set) => ({ set((state) => ({ messages: [...state.messages, { user, content, id }], })), + resetMessages: () => set({ messages: [] }), })); export default useGptStore;