diff options
Diffstat (limited to 'extension/react-app/src')
13 files changed, 203 insertions, 42 deletions
diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index 0aae0bbb..b0de13ac 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -5,28 +5,27 @@ import { defaultBorderRadius, secondaryDark, vscBackground } from "."; import { Clipboard, CheckCircle } from "@styled-icons/heroicons-outline"; +import StyledCode from "./StyledCode"; + const StyledPre = styled.pre` overflow-y: scroll; word-wrap: normal; border: 0.5px solid gray; border-radius: ${defaultBorderRadius}; background-color: ${secondaryDark}; - padding: 8px; - padding-top: 14px; - padding-bottom: 16px; + position: relative; `; -const StyledCode = styled.code``; +const CopyButtonDiv = styled.div` + position: absolute; + top: 4px; + right: 4px; +`; const StyledCopyButton = styled.button<{ visible: boolean }>` - /* position: relative; */ - float: right; border: none; - background-color: ${secondaryDark}; + background-color: transparent; cursor: pointer; - padding: 0; - /* margin: 4px; */ - margin-top: -6px; visibility: ${(props) => (props.visible ? "visible" : "hidden")}; `; @@ -62,9 +61,55 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) { ); } -function CodeBlock(props: { language?: string; children: string }) { +function CodeBlock(props: { children: string }) { + const [result, setResult] = useState<AutoHighlightResult | undefined>( + undefined + ); useEffect(() => { - hljs.highlightAll(); + const result = hljs.highlightAuto( + (props.children as any).props.children[0], + [ + "python", + "javascript", + "typescript", + "bash", + "html", + "css", + "json", + "yaml", + "markdown", + "sql", + "java", + "c", + "cpp", + "csharp", + "go", + "kotlin", + "php", + "ruby", + "rust", + "scala", + "swift", + "dart", + "haskell", + "perl", + "r", + "matlab", + "powershell", + "lua", + "elixir", + "clojure", + "groovy", + "julia", + "vbnet", + "objectivec", + "fsharp", + "erlang", + "ocaml", + ] + ); + console.log(result); + setResult(result); }, [props.children]); const [hovered, setHovered] = useState<boolean>(false); @@ -77,11 +122,15 @@ function CodeBlock(props: { language?: string; children: string }) { setHovered(false); }} > - <CopyButton - visible={hovered} - textToCopy={(props.children as any).props.children[0]} - /> - <StyledCode>{props.children}</StyledCode> + <CopyButtonDiv> + <CopyButton + visible={hovered} + textToCopy={(props.children as any).props.children[0]} + /> + </CopyButtonDiv> + <StyledCode language={result?.language}> + {(props.children as any).props.children[0]} + </StyledCode> </StyledPre> ); } diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx index c6117bf9..ef6719b7 100644 --- a/extension/react-app/src/components/ContinueButton.tsx +++ b/extension/react-app/src/components/ContinueButton.tsx @@ -1,6 +1,8 @@ import styled, { keyframes } from "styled-components"; import { Button } from "."; import { Play } from "@styled-icons/heroicons-outline"; +import { useSelector } from "react-redux"; +import { RootStore } from "../redux/store"; let StyledButton = styled(Button)` margin: auto; @@ -25,14 +27,21 @@ let StyledButton = styled(Button)` `; function ContinueButton(props: { onClick?: () => void; hidden?: boolean }) { + const vscMediaUrl = useSelector( + (state: RootStore) => state.config.vscMediaUrl + ); + return ( <StyledButton hidden={props.hidden} className="m-auto" onClick={props.onClick} > - <Play /> - {/* <img src={"/continue_arrow.png"} width="16px"></img> */} + {vscMediaUrl ? ( + <img src={`${vscMediaUrl}/play_button.png`} width="22px" /> + ) : ( + <Play /> + )} Continue </StyledButton> ); diff --git a/extension/react-app/src/components/DebugPanel.tsx b/extension/react-app/src/components/DebugPanel.tsx index 30f38779..94dbac9e 100644 --- a/extension/react-app/src/components/DebugPanel.tsx +++ b/extension/react-app/src/components/DebugPanel.tsx @@ -6,6 +6,7 @@ import { setApiUrl, setVscMachineId, setSessionId, + setVscMediaUrl, } from "../redux/slices/configSlice"; import { setHighlightedCode } from "../redux/slices/miscSlice"; import { updateFileSystem } from "../redux/slices/debugContexSlice"; @@ -37,6 +38,7 @@ function DebugPanel(props: DebugPanelProps) { dispatch(setApiUrl(event.data.apiUrl)); dispatch(setVscMachineId(event.data.vscMachineId)); dispatch(setSessionId(event.data.sessionId)); + dispatch(setVscMediaUrl(event.data.vscMediaUrl)); break; case "highlightedCode": dispatch(setHighlightedCode(event.data.rangeInFile)); diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index acaca9ce..30931f86 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -6,14 +6,20 @@ interface HeaderButtonWithTextProps { text: string; onClick?: (e: any) => void; children: React.ReactNode; + disabled?: boolean; } const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => { const [hover, setHover] = useState(false); return ( <HeaderButton + disabled={props.disabled} style={{ padding: "1px", paddingLeft: hover ? "4px" : "1px" }} - onMouseEnter={() => setHover(true)} + onMouseEnter={() => { + if (!props.disabled) { + setHover(true); + } + }} onMouseLeave={() => { setHover(false); }} diff --git a/extension/react-app/src/components/LoadingCover.tsx b/extension/react-app/src/components/LoadingCover.tsx new file mode 100644 index 00000000..a0f8f7a2 --- /dev/null +++ b/extension/react-app/src/components/LoadingCover.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import styled from "styled-components"; + +const StyledDiv = styled.div` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background: linear-gradient( + 101.79deg, + #12887a 0%, + #87245c 32%, + #e12637 63%, + #ffb215 100% + ); + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + z-index: 10; +`; + +const StyledImg = styled.img` + /* add your styles here */ +`; + +const StyledDiv2 = styled.div` + width: 50%; + height: 5px; + background: white; + margin-top: 20px; +`; + +interface LoadingCoverProps { + message: string; + hidden?: boolean; +} + +const LoadingCover = (props: LoadingCoverProps) => { + return ( + <StyledDiv style={{ display: props.hidden ? "none" : "inherit" }}> + <StyledImg src="continue.gif" alt="centered image" width="50%" /> + <StyledDiv2></StyledDiv2> + <p>{props.message}</p> + </StyledDiv> + ); +}; + +export default LoadingCover; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 74a1c4e8..827d2d5f 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -200,6 +200,7 @@ function StepContainer(props: StepContainerProps) { <> <HeaderButtonWithText + disabled={props.historyNode.active as boolean} onClick={(e) => { e.stopPropagation(); props.onDelete(); diff --git a/extension/react-app/src/components/StyledCode.tsx b/extension/react-app/src/components/StyledCode.tsx new file mode 100644 index 00000000..c5ed0101 --- /dev/null +++ b/extension/react-app/src/components/StyledCode.tsx @@ -0,0 +1,19 @@ +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { vscDarkPlus as highlightStyle } from "react-syntax-highlighter/dist/esm/styles/prism"; + +interface StyledCodeProps { + children: string; + language?: string; +} + +const StyledCode = (props: StyledCodeProps) => ( + <SyntaxHighlighter + customStyle={{ margin: "0" }} + style={highlightStyle} + language={props.language || "python"} + > + {props.children} + </SyntaxHighlighter> +); + +export default StyledCode; diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index e50a7686..2632e572 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -15,6 +15,7 @@ const DialogContainer = styled.div` top: 50%; left: 50%; transform: translate(-50%, -50%); + width: 75%; `; const Dialog = styled.div` @@ -76,7 +77,6 @@ const TextDialog = (props: { <Dialog> <P>Thanks for your feedback. We'll get back to you soon!</P> <TextArea - cols={50} rows={10} ref={textAreaRef} onKeyDown={(e) => { diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 824bb086..3d8e0a38 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -13,6 +13,8 @@ abstract class AbstractContinueGUIClientProtocol { callback: (commands: { name: string; description: string }[]) => void ): void; + abstract changeDefaultModel(model: string): void; + abstract sendClear(): void; abstract retryAtIndex(index: number): void; diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 59397742..f43a66ff 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -55,6 +55,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { }); } + changeDefaultModel(model: string) { + this.messenger.send("change_default_model", { model }); + } + sendClear() { this.messenger.send("clear_history", {}); } diff --git a/extension/react-app/src/redux/slices/configSlice.ts b/extension/react-app/src/redux/slices/configSlice.ts index a6a641e6..1b107bed 100644 --- a/extension/react-app/src/redux/slices/configSlice.ts +++ b/extension/react-app/src/redux/slices/configSlice.ts @@ -37,9 +37,21 @@ export const configSlice = createSlice({ ...state, sessionId: action.payload, }), + setVscMediaUrl: ( + state: RootStore["config"], + action: { type: string; payload: string } + ) => ({ + ...state, + vscMediaUrl: action.payload, + }), }, }); -export const { setVscMachineId, setApiUrl, setWorkspacePath, setSessionId } = - configSlice.actions; +export const { + setVscMachineId, + setApiUrl, + setWorkspacePath, + setSessionId, + setVscMediaUrl, +} = configSlice.actions; export default configSlice.reducer; diff --git a/extension/react-app/src/redux/store.ts b/extension/react-app/src/redux/store.ts index f9eb0517..a5eef4ba 100644 --- a/extension/react-app/src/redux/store.ts +++ b/extension/react-app/src/redux/store.ts @@ -21,6 +21,7 @@ export interface RootStore { vscMachineId: string | undefined; sessionId: string | undefined; sessionStarted: number | undefined; + vscMediaUrl: string | undefined; }; chat: { messages: ChatMessage[]; diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index f0e3ffd4..13b74423 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -18,6 +18,7 @@ import ReactSwitch from "react-switch"; import { usePostHog } from "posthog-js/react"; import { useSelector } from "react-redux"; import { RootStore } from "../redux/store"; +import LoadingCover from "../components/LoadingCover"; const TopGUIDiv = styled.div` overflow: hidden; @@ -215,7 +216,7 @@ function GUI(props: GUIProps) { useEffect(() => { const listener = (e: any) => { // Cmd + J to toggle fast model - if (e.key === "j" && e.metaKey) { + if (e.key === "i" && e.metaKey && e.shiftKey) { setUsingFastModel((prev) => !prev); } }; @@ -230,21 +231,24 @@ function GUI(props: GUIProps) { console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate); client?.onStateUpdate((state) => { // Scroll only if user is at very bottom of the window. + setUsingFastModel(state.default_model === "gpt-3.5-turbo"); const shouldScrollToBottom = topGuiDivRef.current && topGuiDivRef.current?.offsetHeight - window.scrollY < 100; setWaitingForSteps(state.active); setHistory(state.history); setUserInputQueue(state.user_input_queue); - const nextStepsOpen = [...stepsOpen]; - for ( - let i = nextStepsOpen.length; - i < state.history.timeline.length; - i++ - ) { - nextStepsOpen.push(true); - } - setStepsOpen(nextStepsOpen); + setStepsOpen((prev) => { + const nextStepsOpen = [...prev]; + for ( + let i = nextStepsOpen.length; + i < state.history.timeline.length; + i++ + ) { + nextStepsOpen.push(true); + } + return nextStepsOpen; + }); if (shouldScrollToBottom) { scrollToBottom(); @@ -325,6 +329,7 @@ function GUI(props: GUIProps) { // const iterations = useSelector(selectIterations); return ( <> + <LoadingCover hidden={true} message="Downloading local model..." /> <TextDialog showDialog={showFeedbackDialog} onEnter={(text) => { @@ -347,9 +352,7 @@ function GUI(props: GUIProps) { {typeof client === "undefined" && ( <> <Loader></Loader> - <p style={{ textAlign: "center" }}> - Trying to reconnect with server... - </p> + <p style={{ textAlign: "center" }}>Loading Continue server...</p> </> )} {history?.timeline.map((node: HistoryNode, index: number) => { @@ -388,7 +391,7 @@ function GUI(props: GUIProps) { /> ); })} - {/* {waitingForSteps && <Loader></Loader>} */} + {waitingForSteps && <Loader></Loader>} <div> {userInputQueue.map((input) => { @@ -426,9 +429,9 @@ function GUI(props: GUIProps) { }} hidden={!showDataSharingInfo} > - By turning on this switch, you signal that you would - contribute this software development data to a publicly - accessible, open-source dataset in the future. + By turning on this switch, you signal that you would contribute this + software development data to a publicly accessible, open-source dataset + in the future. <br /> <br /> <b> @@ -470,8 +473,11 @@ function GUI(props: GUIProps) { Contribute Data </span> </div> - {/* <HeaderButtonWithText + <HeaderButtonWithText onClick={() => { + client?.changeDefaultModel( + usingFastModel ? "gpt-4" : "gpt-3.5-turbo" + ); setUsingFastModel((prev) => !prev); }} text={usingFastModel ? "gpt-3.5-turbo" : "gpt-4"} @@ -481,7 +487,7 @@ function GUI(props: GUIProps) { > {usingFastModel ? "⚡" : "🧠"} </div> - </HeaderButtonWithText> */} + </HeaderButtonWithText> <HeaderButtonWithText onClick={() => { client?.sendClear(); |