diff options
Diffstat (limited to 'extension/react-app/src/components')
-rw-r--r-- | extension/react-app/src/components/HeaderButtonWithText.tsx | 4 | ||||
-rw-r--r-- | extension/react-app/src/components/InfoHover.tsx | 19 | ||||
-rw-r--r-- | extension/react-app/src/components/Layout.tsx | 9 | ||||
-rw-r--r-- | extension/react-app/src/components/ModelSettings.tsx | 107 | ||||
-rw-r--r-- | extension/react-app/src/components/index.ts | 50 |
5 files changed, 176 insertions, 13 deletions
diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index bcd36972..3122c287 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -1,7 +1,5 @@ import React, { useState } from "react"; -import { Tooltip } from "react-tooltip"; -import styled from "styled-components"; -import { HeaderButton, StyledTooltip, defaultBorderRadius } from "."; +import { HeaderButton, StyledTooltip } from "."; interface HeaderButtonWithTextProps { text: string; diff --git a/extension/react-app/src/components/InfoHover.tsx b/extension/react-app/src/components/InfoHover.tsx new file mode 100644 index 00000000..2cb8ad71 --- /dev/null +++ b/extension/react-app/src/components/InfoHover.tsx @@ -0,0 +1,19 @@ +import { InformationCircleIcon } from "@heroicons/react/24/outline"; +import { StyledTooltip } from "."; + +const InfoHover = ({ msg }: { msg: string }) => { + const id = "info-hover"; + + return ( + <> + <InformationCircleIcon + data-tooltip-id={id} + data-tooltip-content={msg} + className="h-5 w-5 text-gray-500 cursor-help" + /> + <StyledTooltip id={id} place="bottom" /> + </> + ); +}; + +export default InfoHover; diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx index cec3f8e1..c0f0929b 100644 --- a/extension/react-app/src/components/Layout.tsx +++ b/extension/react-app/src/components/Layout.tsx @@ -18,6 +18,7 @@ import { BookOpenIcon, ChatBubbleOvalLeftEllipsisIcon, SparklesIcon, + Cog6ToothIcon, } from "@heroicons/react/24/outline"; import HeaderButtonWithText from "./HeaderButtonWithText"; import { useNavigate } from "react-router-dom"; @@ -193,6 +194,14 @@ const Layout = () => { <ChatBubbleOvalLeftEllipsisIcon width="1.4em" height="1.4em" /> </HeaderButtonWithText> </a> + <HeaderButtonWithText + onClick={() => { + navigate("/settings"); + }} + text="Settings" + > + <Cog6ToothIcon width="1.4em" height="1.4em" /> + </HeaderButtonWithText> </Footer> </div> </LayoutTopDiv> diff --git a/extension/react-app/src/components/ModelSettings.tsx b/extension/react-app/src/components/ModelSettings.tsx new file mode 100644 index 00000000..99200502 --- /dev/null +++ b/extension/react-app/src/components/ModelSettings.tsx @@ -0,0 +1,107 @@ +import styled from "styled-components"; +import { LLM } from "../../../schema/LLM"; +import { + Label, + Select, + TextInput, + defaultBorderRadius, + lightGray, + vscForeground, +} from "."; +import { useState } from "react"; +import { useFormContext } from "react-hook-form"; + +const Div = styled.div<{ dashed: boolean }>` + border: 1px ${(props) => (props.dashed ? "dashed" : "solid")} ${lightGray}; + border-radius: ${defaultBorderRadius}; + padding: 8px; + margin-bottom: 16px; +`; + +type ModelOption = "api_key" | "model" | "context_length"; + +const DefaultModelOptions: { + [key: string]: { [key in ModelOption]?: string }; +} = { + OpenAI: { + api_key: "", + model: "gpt-4", + }, + MaybeProxyOpenAI: { + api_key: "", + model: "gpt-4", + }, + Anthropic: { + api_key: "", + model: "claude-2", + }, + default: { + api_key: "", + model: "gpt-4", + }, +}; + +function ModelSettings(props: { llm: any | undefined; role: string }) { + const [modelOptions, setModelOptions] = useState<{ + [key in ModelOption]?: string; + }>(DefaultModelOptions[props.llm?.class_name || "default"]); + + const { register, setValue, getValues } = useFormContext(); + + return ( + <Div dashed={typeof props.llm === undefined}> + {props.llm ? ( + <> + <b>{props.role}</b>: <b> {props.llm.class_name || "gpt-4"}</b> + <form> + {typeof modelOptions.api_key !== undefined && ( + <> + <Label>API Key</Label> + <TextInput + type="text" + defaultValue={props.llm.api_key} + placeholder="API Key" + {...register(`models.${props.role}.api_key`)} + /> + </> + )} + {modelOptions.model && ( + <> + <Label>Model</Label> + <TextInput + type="text" + defaultValue={props.llm.model} + placeholder="Model" + {...register(`models.${props.role}.model`)} + /> + </> + )} + </form> + </> + ) : ( + <div> + <b>Add Model</b> + <div className="my-4"> + <Select + defaultValue="" + onChange={(e) => { + if (e.target.value) { + e.target.value = ""; + } + }} + > + <option disabled value=""> + Select Model Type + </option> + <option value="newModel1">New Model 1</option> + <option value="newModel2">New Model 2</option> + <option value="newModel3">New Model 3</option> + </Select> + </div> + </div> + )} + </Div> + ); +} + +export default ModelSettings; diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index 6705ceb2..f2e154bc 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -40,21 +40,29 @@ export const StyledTooltip = styled(Tooltip)` padding-left: 12px; padding-right: 12px; z-index: 100; + + max-width: 80vw; `; export const TextArea = styled.textarea` - width: 100%; + padding: 8px; + font-family: inherit; border-radius: ${defaultBorderRadius}; - border: none; + margin: 16px auto; + height: auto; + width: calc(100% - 32px); background-color: ${secondaryDark}; - resize: vertical; - - padding: 4px; - caret-color: ${vscForeground}; - color: #{vscForeground}; + color: ${vscForeground}; + z-index: 1; + border: 1px solid transparent; &:focus { - outline: 1px solid ${buttonColor}; + outline: 1px solid ${lightGray}; + border: 1px solid transparent; + } + + &::placeholder { + color: ${lightGray}80; } `; @@ -84,11 +92,33 @@ export const H3 = styled.h3` export const TextInput = styled.input.attrs({ type: "text" })` width: 100%; - padding: 12px 20px; + padding: 8px 12px; + margin: 8px 0; + box-sizing: border-box; + border-radius: ${defaultBorderRadius}; + outline: 1px solid ${lightGray}; + border: none; + background-color: ${vscBackground}; + color: ${vscForeground}; + + &:focus { + background: ${secondaryDark}; + } +`; + +export const Select = styled.select` + padding: 8px 12px; margin: 8px 0; box-sizing: border-box; border-radius: ${defaultBorderRadius}; - border: 2px solid gray; + outline: 1px solid ${lightGray}; + border: none; + background-color: ${vscBackground}; + color: ${vscForeground}; +`; + +export const Label = styled.label` + font-size: 13px; `; const spin = keyframes` |