diff options
Diffstat (limited to 'extension/react-app/src')
-rw-r--r-- | extension/react-app/src/App.tsx | 39 | ||||
-rw-r--r-- | extension/react-app/src/components/CodeBlock.tsx | 4 | ||||
-rw-r--r-- | extension/react-app/src/components/ComboBox.tsx | 191 | ||||
-rw-r--r-- | extension/react-app/src/components/ContinueButton.tsx | 2 | ||||
-rw-r--r-- | extension/react-app/src/components/HeaderButtonWithText.tsx | 44 | ||||
-rw-r--r-- | extension/react-app/src/components/Loader.tsx | 40 | ||||
-rw-r--r-- | extension/react-app/src/components/PillButton.tsx | 144 | ||||
-rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 13 | ||||
-rw-r--r-- | extension/react-app/src/components/TextDialog.tsx | 2 | ||||
-rw-r--r-- | extension/react-app/src/components/UserInputContainer.tsx | 6 | ||||
-rw-r--r-- | extension/react-app/src/components/index.ts | 22 | ||||
-rw-r--r-- | extension/react-app/src/hooks/ContinueGUIClientProtocol.ts | 4 | ||||
-rw-r--r-- | extension/react-app/src/hooks/useContinueGUIProtocol.ts | 8 | ||||
-rw-r--r-- | extension/react-app/src/index.css | 9 | ||||
-rw-r--r-- | extension/react-app/src/main.tsx | 6 | ||||
-rw-r--r-- | extension/react-app/src/tabs/gui.tsx | 22 |
16 files changed, 358 insertions, 198 deletions
diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index a51541d0..8785f88f 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -1,28 +1,33 @@ import DebugPanel from "./components/DebugPanel"; import MainTab from "./tabs/main"; -import { Provider } from "react-redux"; -import store from "./redux/store"; import WelcomeTab from "./tabs/welcome"; import ChatTab from "./tabs/chat"; import GUI from "./tabs/gui"; +import { createContext } from "react"; +import useContinueGUIProtocol from "./hooks/useWebsocket"; +import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol"; + +export const GUIClientContext = createContext< + ContinueGUIClientProtocol | undefined +>(undefined); function App() { + const client = useContinueGUIProtocol(); + return ( - <> - <Provider store={store}> - <DebugPanel - tabs={[ - { - element: <GUI />, - title: "GUI", - }, - // { element: <MainTab />, title: "Debug Panel" }, - // { element: <WelcomeTab />, title: "Welcome" }, - // { element: <ChatTab />, title: "Chat" }, - ]} - ></DebugPanel> - </Provider> - </> + <GUIClientContext.Provider value={client}> + <DebugPanel + tabs={[ + { + element: <GUI />, + title: "GUI", + }, + // { element: <MainTab />, title: "Debug Panel" }, + // { element: <WelcomeTab />, title: "Welcome" }, + // { element: <ChatTab />, title: "Chat" }, + ]} + /> + </GUIClientContext.Provider> ); } diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index 17f5626b..fe9b3a95 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -52,9 +52,9 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) { }} > {clicked ? ( - <CheckCircle color="#00ff00" size="1.4em" /> + <CheckCircle color="#00ff00" size="1.5em" /> ) : ( - <Clipboard color={hovered ? "#00ff00" : "white"} size="1.4em" /> + <Clipboard color={hovered ? "#00ff00" : "white"} size="1.5em" /> )} </StyledCopyButton> </> diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 81b148b9..7ee5dc24 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -4,6 +4,7 @@ import styled from "styled-components"; import { buttonColor, defaultBorderRadius, + lightGray, secondaryDark, vscBackground, } from "."; @@ -16,11 +17,32 @@ import { LockClosed, LockOpen, Plus, + DocumentPlus, } from "@styled-icons/heroicons-outline"; +import { HighlightedRangeContext } from "../../../schema/FullState"; // #region styled components const mainInputFontSize = 16; +const EmptyPillDiv = styled.div` + padding: 8px; + border-radius: ${defaultBorderRadius}; + border: 1px dashed ${lightGray}; + color: ${lightGray}; + background-color: ${vscBackground}; + overflow: hidden; + display: flex; + align-items: center; + text-align: center; + cursor: pointer; + font-size: 13px; + + &:hover { + background-color: ${lightGray}; + color: ${vscBackground}; + } +`; + const ContextDropdown = styled.div` position: absolute; padding: 4px; @@ -41,17 +63,19 @@ const MainTextInput = styled.textarea` padding: 8px; font-size: ${mainInputFontSize}px; + font-family: inherit; + border: 1px solid transparent; border-radius: ${defaultBorderRadius}; - border: 1px solid white; margin: 8px auto; + height: auto; width: 100%; - background-color: ${vscBackground}; + background-color: ${secondaryDark}; color: white; z-index: 1; &:focus { + outline: 1px solid #ff000066; border: 1px solid transparent; - outline: 1px solid orange; } `; @@ -69,7 +93,6 @@ const Ul = styled.ul<{ background: ${vscBackground}; background-color: ${secondaryDark}; color: white; - font-family: "Fira Code", monospace; max-height: ${UlMaxHeight}px; overflow: scroll; padding: 0; @@ -102,7 +125,7 @@ interface ComboBoxProps { onInputValueChange: (inputValue: string) => void; disabled?: boolean; onEnter: (e: React.KeyboardEvent<HTMLInputElement>) => void; - highlightedCodeSections: (RangeInFile & { contents: string })[]; + highlightedCodeSections: HighlightedRangeContext[]; deleteContextItems: (indices: number[]) => void; onTogglePin: () => void; onToggleAddContext: () => void; @@ -119,16 +142,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { React.useState(false); const [pinned, setPinned] = useState(false); const [highlightedCodeSections, setHighlightedCodeSections] = React.useState( - props.highlightedCodeSections || [ - { - filepath: "test.ts", - range: { - start: { line: 0, character: 0 }, - end: { line: 0, character: 0 }, - }, - contents: "import * as a from 'a';", - }, - ] + props.highlightedCodeSections || [] ); useEffect(() => { @@ -169,6 +183,71 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { return ( <> + <div className="px-2 flex gap-2 items-center flex-wrap mt-2"> + {highlightedCodeSections.length > 1 && ( + <> + <HeaderButtonWithText + text="Clear Context" + onClick={() => { + props.deleteContextItems( + highlightedCodeSections.map((_, idx) => idx) + ); + }} + > + <Trash size="1.6em" /> + </HeaderButtonWithText> + </> + )} + {highlightedCodeSections.map((section, idx) => ( + <PillButton + editing={section.editing} + pinned={section.pinned} + index={idx} + key={`${section.filepath}${idx}`} + title={`${section.range.filepath} (${ + section.range.range.start.line + 1 + }-${section.range.range.end.line + 1})`} + onDelete={() => { + if (props.deleteContextItems) { + props.deleteContextItems([idx]); + } + setHighlightedCodeSections((prev) => { + const newSections = [...prev]; + newSections.splice(idx, 1); + return newSections; + }); + }} + onHover={(val: boolean) => { + if (val) { + setHoveringButton(val); + } else { + setTimeout(() => { + setHoveringButton(val); + }, 100); + } + }} + /> + ))} + {props.highlightedCodeSections.length > 0 && + (props.addingHighlightedCode ? ( + <EmptyPillDiv + onClick={() => { + props.onToggleAddContext(); + }} + > + Highlight to Add Context + </EmptyPillDiv> + ) : ( + <HeaderButtonWithText + text="Add to Context" + onClick={() => { + props.onToggleAddContext(); + }} + > + <DocumentPlus width="1.6em"></DocumentPlus> + </HeaderButtonWithText> + ))} + </div> <div className="flex px-2" ref={divRef} hidden={!isOpen}> <MainTextInput disabled={props.disabled} @@ -260,80 +339,10 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { ))} </Ul> </div> - <div className="px-2 flex gap-2 items-center flex-wrap"> - {highlightedCodeSections.length === 0 && ( - <HeaderButtonWithText - text={ - props.addingHighlightedCode ? "Adding Context" : "Add Context" - } - onClick={() => { - props.onToggleAddContext(); - }} - inverted={props.addingHighlightedCode} - > - <Plus size="1.6em" /> - </HeaderButtonWithText> - )} - {highlightedCodeSections.length > 0 && ( - <> - <HeaderButtonWithText - text="Clear Context" - onClick={() => { - props.deleteContextItems( - highlightedCodeSections.map((_, idx) => idx) - ); - }} - > - <Trash size="1.6em" /> - </HeaderButtonWithText> - <HeaderButtonWithText - text={pinned ? "Unpin Context" : "Pin Context"} - inverted={pinned} - onClick={() => { - setPinned((prev) => !prev); - props.onTogglePin(); - }} - > - {pinned ? ( - <LockClosed size="1.6em"></LockClosed> - ) : ( - <LockOpen size="1.6em"></LockOpen> - )} - </HeaderButtonWithText> - </> - )} - {highlightedCodeSections.map((section, idx) => ( - <PillButton - title={`${section.filepath} (${section.range.start.line + 1}-${ - section.range.end.line + 1 - })`} - onDelete={() => { - if (props.deleteContextItems) { - props.deleteContextItems([idx]); - } - setHighlightedCodeSections((prev) => { - const newSections = [...prev]; - newSections.splice(idx, 1); - return newSections; - }); - }} - onHover={(val: boolean) => { - if (val) { - setHoveringButton(val); - } else { - setTimeout(() => { - setHoveringButton(val); - }, 100); - } - }} - /> - ))} - - <span className="text-trueGray-400 ml-auto mr-4 text-xs text-right"> - Highlight code to include as context. Currently open file included by - default. {highlightedCodeSections.length === 0 && ""} - </span> - </div> + {/* <span className="text-trueGray-400 ml-auto m-auto text-xs text-right"> + Highlight code to include as context. Currently open file included by + default. {highlightedCodeSections.length === 0 && ""} + </span> */} <ContextDropdown onMouseEnter={() => { setHoveringContextDropdown(true); @@ -345,9 +354,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { > {highlightedCodeSections.map((section, idx) => ( <> - <p>{section.filepath}</p> + <p>{section.range.filepath}</p> <CodeBlock showCopy={false} key={idx}> - {section.contents} + {section.range.contents} </CodeBlock> </> ))} diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx index 5295799a..462f2b46 100644 --- a/extension/react-app/src/components/ContinueButton.tsx +++ b/extension/react-app/src/components/ContinueButton.tsx @@ -18,7 +18,7 @@ let StyledButton = styled(Button)` &:hover { transition-delay: 0.5s; - transition-property: background; + transition-property: "background"; background: linear-gradient( 45deg, #be1a55 14.44%, diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index 72a653c5..de8e3c98 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; - -import { HeaderButton } from "."; +import { Tooltip } from "react-tooltip"; +import styled from "styled-components"; +import { HeaderButton, StyledTooltip, defaultBorderRadius } from "."; interface HeaderButtonWithTextProps { text: string; @@ -13,25 +14,28 @@ interface HeaderButtonWithTextProps { const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => { const [hover, setHover] = useState(false); - const paddingLeft = (props.disabled ? (props.active ? "3px" : "1px"): (hover ? "4px" : "1px")); return ( - <HeaderButton - inverted={props.inverted} - disabled={props.disabled} - style={{ padding: (props.active ? "3px" : "1px"), paddingLeft, borderRadius: (props.active ? "50%" : undefined) }} - onMouseEnter={() => { - if (!props.disabled) { - setHover(true); - } - }} - onMouseLeave={() => { - setHover(false); - }} - onClick={props.onClick} - > - <span hidden={!hover}>{props.text}</span> - {props.children} - </HeaderButton> + <> + <HeaderButton + data-tooltip-id={`header_button_${props.text}`} + inverted={props.inverted} + disabled={props.disabled} + onMouseEnter={() => { + if (!props.disabled) { + setHover(true); + } + }} + onMouseLeave={() => { + setHover(false); + }} + onClick={props.onClick} + > + {props.children} + </HeaderButton> + <StyledTooltip id={`header_button_${props.text}`} place="bottom"> + {props.text} + </StyledTooltip> + </> ); }; diff --git a/extension/react-app/src/components/Loader.tsx b/extension/react-app/src/components/Loader.tsx new file mode 100644 index 00000000..90eff793 --- /dev/null +++ b/extension/react-app/src/components/Loader.tsx @@ -0,0 +1,40 @@ +import { Play } from "@styled-icons/heroicons-outline"; +import { useSelector } from "react-redux"; +import styled from "styled-components"; +import { RootStore } from "../redux/store"; + +const DEFAULT_SIZE = "28px"; + +const FlashingDiv = styled.div` + margin: auto; + width: ${DEFAULT_SIZE}; + animation: flash 1.2s infinite ease-in-out; + @keyframes flash { + 0% { + opacity: 0.4; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.4; + } + } +`; + +function Loader(props: { size?: string }) { + const vscMediaUrl = useSelector( + (state: RootStore) => state.config.vscMediaUrl + ); + return ( + <FlashingDiv> + {vscMediaUrl ? ( + <img src={`${vscMediaUrl}/play_button.png`} width="22px" /> + ) : ( + <Play width={props.size || DEFAULT_SIZE} /> + )} + </FlashingDiv> + ); +} + +export default Loader; diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index 5a02c6b2..a384832e 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,54 +1,136 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import styled from "styled-components"; -import { defaultBorderRadius } from "."; -import { XMark } from "@styled-icons/heroicons-outline"; +import { + StyledTooltip, + defaultBorderRadius, + lightGray, + secondaryDark, +} from "."; +import { Trash, PaintBrush, MapPin } from "@styled-icons/heroicons-outline"; +import { GUIClientContext } from "../App"; const Button = styled.button` border: none; color: white; - background-color: transparent; - border: 1px solid white; + background-color: ${secondaryDark}; border-radius: ${defaultBorderRadius}; - padding: 3px 6px; + padding: 8px; + overflow: hidden; + + cursor: pointer; +`; + +const GridDiv = styled.div` + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + display: grid; + grid-gap: 0; + grid-template-columns: 1fr 1fr; + align-items: center; + border-radius: ${defaultBorderRadius}; + overflow: hidden; + + background-color: ${secondaryDark}; +`; + +const ButtonDiv = styled.div<{ backgroundColor: string }>` + background-color: ${secondaryDark}; + padding: 3px; + height: 100%; + display: flex; + align-items: center; &:hover { - background-color: white; - color: black; + background-color: ${(props) => props.backgroundColor}; } - - cursor: pointer; `; interface PillButtonProps { onHover?: (arg0: boolean) => void; onDelete?: () => void; title: string; + index: number; + editing: boolean; + pinned: boolean; } const PillButton = (props: PillButtonProps) => { const [isHovered, setIsHovered] = useState(false); + const client = useContext(GUIClientContext); + return ( - <Button - onMouseEnter={() => { - setIsHovered(true); - if (props.onHover) { - props.onHover(true); - } - }} - onMouseLeave={() => { - setIsHovered(false); - if (props.onHover) { - props.onHover(false); - } - }} - onClick={() => { - if (props.onDelete) { - props.onDelete(); - } - }} - > - {props.title} - </Button> + <> + <Button + style={{ + position: "relative", + borderColor: props.editing + ? "#8800aa" + : props.pinned + ? "#ffff0099" + : "transparent", + borderWidth: "1px", + borderStyle: "solid", + }} + onMouseEnter={() => { + setIsHovered(true); + if (props.onHover) { + props.onHover(true); + } + }} + onMouseLeave={() => { + setIsHovered(false); + if (props.onHover) { + props.onHover(false); + } + }} + > + {isHovered && ( + <GridDiv> + <ButtonDiv + data-tooltip-id={`edit-${props.index}`} + backgroundColor={"#8800aa55"} + onClick={() => { + client?.setEditingAtIndices([props.index]); + }} + > + <PaintBrush style={{ margin: "auto" }} width="1.6em"></PaintBrush> + </ButtonDiv> + + {/* <ButtonDiv + data-tooltip-id={`pin-${props.index}`} + backgroundColor={"#ffff0055"} + onClick={() => { + client?.setPinnedAtIndices([props.index]); + }} + > + <MapPin style={{ margin: "auto" }} width="1.6em"></MapPin> + </ButtonDiv> */} + <StyledTooltip id={`pin-${props.index}`}> + Edit this range + </StyledTooltip> + <ButtonDiv + data-tooltip-id={`delete-${props.index}`} + backgroundColor={"#cc000055"} + onClick={() => { + if (props.onDelete) { + props.onDelete(); + } + }} + > + <Trash style={{ margin: "auto" }} width="1.6em"></Trash> + </ButtonDiv> + </GridDiv> + )} + {props.title} + </Button> + <StyledTooltip id={`edit-${props.index}`}> + {props.editing ? "Editing this range" : "Edit this range"} + </StyledTooltip> + <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip> + </> ); }; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 2aed2e72..91d7b8ef 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -13,7 +13,7 @@ import { ArrowPath, XMark, } from "@styled-icons/heroicons-outline"; -import { Stop } from "@styled-icons/heroicons-solid"; +import { StopCircle } from "@styled-icons/heroicons-solid"; import { HistoryNode } from "../../../schema/HistoryNode"; import ReactMarkdown from "react-markdown"; import HeaderButtonWithText from "./HeaderButtonWithText"; @@ -67,7 +67,6 @@ const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>` const ContentDiv = styled.div<{ isUserInput: boolean }>` padding: 8px; - padding-left: 16px; background-color: ${(props) => props.isUserInput ? secondaryDark : vscBackground}; font-size: 13px; @@ -167,7 +166,7 @@ function StepContainer(props: StepContainerProps) { ? "#f00" : props.historyNode.active ? undefined - : "white" + : "transparent" } className="overflow-hidden cursor-pointer" onClick={(e) => { @@ -182,7 +181,7 @@ function StepContainer(props: StepContainerProps) { loading={props.historyNode.active as boolean | false} error={props.historyNode.observation?.error ? true : false} > - <h4 className="m-2"> + <div className="m-2"> {!isUserInput && (props.open ? ( <ChevronDown size="1.4em" /> @@ -191,7 +190,7 @@ function StepContainer(props: StepContainerProps) { ))} {props.historyNode.observation?.title || (props.historyNode.step.name as any)} - </h4> + </div> {/* <HeaderButton onClick={(e) => { e.stopPropagation(); @@ -203,16 +202,14 @@ function StepContainer(props: StepContainerProps) { <> <HeaderButtonWithText - disabled={props.historyNode.active as boolean} onClick={(e) => { e.stopPropagation(); props.onDelete(); }} text={props.historyNode.active ? "Stop" : "Delete"} - active={props.historyNode.active} > {props.historyNode.active ? ( - <Stop size="1.2em" onClick={props.onDelete} /> + <StopCircle size="1.6em" onClick={props.onDelete} /> ) : ( <XMark size="1.6em" onClick={props.onDelete} /> )} diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index a564f884..ea5727f0 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -8,6 +8,7 @@ const ScreenCover = styled.div` width: 100%; height: 100%; background-color: rgba(168, 168, 168, 0.5); + z-index: 100; `; const DialogContainer = styled.div` @@ -35,7 +36,6 @@ const TextArea = styled.textarea` border-radius: 8px; padding: 8px; outline: 1px solid black; - font-family: Arial, Helvetica, sans-serif; resize: none; &:focus { diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx index 28437d35..f51f0cb5 100644 --- a/extension/react-app/src/components/UserInputContainer.tsx +++ b/extension/react-app/src/components/UserInputContainer.tsx @@ -15,12 +15,10 @@ interface UserInputContainerProps { } const StyledDiv = styled.div` - background-color: rgb(45 45 45); + background-color: ${secondaryDark}; padding: 8px; padding-left: 16px; padding-right: 16px; - border-bottom: 1px solid white; - border-top: 1px solid white; font-size: 13px; display: flex; align-items: center; @@ -29,7 +27,7 @@ const StyledDiv = styled.div` const UserInputContainer = (props: UserInputContainerProps) => { return ( <StyledDiv> - <b>{props.children}</b> + {props.children} <div style={{ marginLeft: "auto" }}> <HeaderButtonWithText onClick={(e) => { diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index db1925ed..9ae0f097 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -1,7 +1,9 @@ +import { Tooltip } from "react-tooltip"; import styled, { keyframes } from "styled-components"; export const defaultBorderRadius = "5px"; -export const secondaryDark = "rgb(42 42 42)"; +export const lightGray = "rgb(100 100 100)"; +export const secondaryDark = "rgb(45 45 45)"; export const vscBackground = "rgb(30 30 30)"; export const vscBackgroundTransparent = "#1e1e1ede"; export const buttonColor = "rgb(113 28 59)"; @@ -26,6 +28,16 @@ export const Button = styled.button` } `; +export const StyledTooltip = styled(Tooltip)` + font-size: 12px; + background-color: rgb(60 60 60); + border-radius: ${defaultBorderRadius}; + padding: 6px; + padding-left: 12px; + padding-right: 12px; + z-index: 100; +`; + export const TextArea = styled.textarea` width: 100%; border-radius: ${defaultBorderRadius}; @@ -128,19 +140,17 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>` background-color: ${({ inverted }) => (inverted ? "white" : "transparent")}; color: ${({ inverted }) => (inverted ? "black" : "white")}; - border: 1px solid white; + border: none; border-radius: ${defaultBorderRadius}; cursor: pointer; &:hover { background-color: ${({ inverted }) => - typeof inverted === "undefined" || inverted ? "white" : "transparent"}; - color: ${({ inverted }) => - typeof inverted === "undefined" || inverted ? "black" : "white"}; + typeof inverted === "undefined" || inverted ? lightGray : "transparent"}; } display: flex; align-items: center; justify-content: center; gap: 4px; - padding: 1px; + padding: 2px; `; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index f123bb2b..a179c2bf 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -23,6 +23,10 @@ abstract class AbstractContinueGUIClientProtocol { abstract deleteContextAtIndices(indices: number[]): void; + abstract setEditingAtIndices(indices: number[]): void; + + abstract setPinnedAtIndices(indices: number[]): void; + abstract toggleAddingHighlightedCode(): void; } diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 49f200ae..2060dd7f 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -75,6 +75,14 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { this.messenger.send("delete_context_at_indices", { indices }); } + setEditingAtIndices(indices: number[]) { + this.messenger.send("set_editing_at_indices", { indices }); + } + + setPinnedAtIndices(indices: number[]) { + this.messenger.send("set_pinned_at_indices", { indices }); + } + toggleAddingHighlightedCode(): void { this.messenger.send("toggle_adding_highlighted_code", {}); } diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css index 6dc514ec..682551f8 100644 --- a/extension/react-app/src/index.css +++ b/extension/react-app/src/index.css @@ -10,19 +10,12 @@ --def-border-radius: 5px; } -@font-face { - font-family: "Mona Sans"; - src: url("assets/Mona-Sans.woff2") format("woff2 supports variations"), - url("assets/Mona-Sans.woff2") format("woff2-variations"); - font-weight: 200 900; - font-stretch: 75% 85%; -} - html, body, #root { height: 100%; background-color: var(--vsc-background); + font-family: "Lexend", sans-serif; } body { diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx index 0b02575c..a76bced6 100644 --- a/extension/react-app/src/main.tsx +++ b/extension/react-app/src/main.tsx @@ -1,6 +1,8 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; +import { Provider } from "react-redux"; +import store from "./redux/store"; import "./index.css"; import posthog from "posthog-js"; @@ -17,7 +19,9 @@ posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", { ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( <React.StrictMode> <PostHogProvider client={posthog}> - <App /> + <Provider store={store}> + <App /> + </Provider> </PostHogProvider> </React.StrictMode> ); diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index e5320c6a..3cce30de 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -1,11 +1,13 @@ import styled from "styled-components"; -import { defaultBorderRadius, Loader } from "../components"; +import { defaultBorderRadius } from "../components"; +import Loader from "../components/Loader"; import ContinueButton from "../components/ContinueButton"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { FullState, HighlightedRangeContext } from "../../../schema/FullState"; +import { useCallback, useEffect, useRef, useState, useContext } from "react"; import { History } from "../../../schema/History"; import { HistoryNode } from "../../../schema/HistoryNode"; import StepContainer from "../components/StepContainer"; -import useContinueGUIProtocol from "../hooks/useWebsocket"; +import { GUIClientContext } from "../App"; import { BookOpen, ChatBubbleOvalLeftEllipsis, @@ -52,6 +54,7 @@ interface GUIProps { } function GUI(props: GUIProps) { + const client = useContext(GUIClientContext); const posthog = usePostHog(); const vscMachineId = useSelector( (state: RootStore) => state.config.vscMachineId @@ -70,7 +73,9 @@ function GUI(props: GUIProps) { const [usingFastModel, setUsingFastModel] = useState(false); const [waitingForSteps, setWaitingForSteps] = useState(false); const [userInputQueue, setUserInputQueue] = useState<string[]>([]); - const [highlightedRanges, setHighlightedRanges] = useState([]); + const [highlightedRanges, setHighlightedRanges] = useState< + HighlightedRangeContext[] + >([]); const [addingHighlightedCode, setAddingHighlightedCode] = useState(false); const [availableSlashCommands, setAvailableSlashCommands] = useState< { name: string; description: string }[] @@ -112,7 +117,6 @@ function GUI(props: GUIProps) { const [feedbackDialogMessage, setFeedbackDialogMessage] = useState(""); const topGuiDivRef = useRef<HTMLDivElement>(null); - const client = useContinueGUIProtocol(); const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>( null @@ -148,7 +152,7 @@ function GUI(props: GUIProps) { }, []); useEffect(() => { - client?.onStateUpdate((state) => { + client?.onStateUpdate((state: FullState) => { // Scroll only if user is at very bottom of the window. setUsingFastModel(state.default_model === "gpt-3.5-turbo"); const shouldScrollToBottom = @@ -289,7 +293,7 @@ function GUI(props: GUIProps) { > {typeof client === "undefined" && ( <> - <Loader></Loader> + <Loader /> <p style={{ textAlign: "center" }}>Loading Continue server...</p> </> )} @@ -316,7 +320,8 @@ function GUI(props: GUIProps) { setStepsOpen(nextStepsOpen); }} onToggleAll={() => { - setStepsOpen((prev) => prev.map((_, index) => !prev[index])); + const shouldOpen = !stepsOpen[index]; + setStepsOpen((prev) => prev.map(() => shouldOpen)); }} key={index} onUserInput={(input: string) => { @@ -381,6 +386,7 @@ function GUI(props: GUIProps) { borderRadius: defaultBorderRadius, padding: "16px", margin: "16px", + zIndex: 100, }} hidden={!showDataSharingInfo} > |