diff options
author | Nate Sesti <sestinj@gmail.com> | 2023-06-26 16:39:07 -0700 |
---|---|---|
committer | Nate Sesti <sestinj@gmail.com> | 2023-06-26 16:39:07 -0700 |
commit | 0b3e6fdf553a481bdd899a2608376dbb95c8e72e (patch) | |
tree | 615381124b54fb8a10523335c971b5a2d208b767 /extension/react-app | |
parent | deca77889cfc8eaa4065694f113525eda365e5d0 (diff) | |
parent | 0862b388dc0f07e45b6daeaec1f8c05925623692 (diff) | |
download | sncontinue-0b3e6fdf553a481bdd899a2608376dbb95c8e72e.tar.gz sncontinue-0b3e6fdf553a481bdd899a2608376dbb95c8e72e.tar.bz2 sncontinue-0b3e6fdf553a481bdd899a2608376dbb95c8e72e.zip |
Merge branch 'main' into styled-code
Diffstat (limited to 'extension/react-app')
18 files changed, 292 insertions, 66 deletions
diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index 18ef3ee6..fa624b3f 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -18,6 +18,7 @@ "react-markdown": "^8.0.5", "react-redux": "^8.0.5", "react-syntax-highlighter": "^15.5.0", + "react-switch": "^7.0.0", "styled-components": "^5.3.6", "vscode-webview": "^1.0.1-beta.1" }, @@ -2921,19 +2922,16 @@ } } }, - "node_modules/react-syntax-highlighter": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", - "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "node_modules/react-switch": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/react-switch/-/react-switch-7.0.0.tgz", + "integrity": "sha512-KkDeW+cozZXI6knDPyUt3KBN1rmhoVYgAdCJqAh7st7tk8YE6N0iR89zjCWO8T8dUTeJGTR0KU+5CHCRMRffiA==", "dependencies": { - "@babel/runtime": "^7.3.1", - "highlight.js": "^10.4.1", - "lowlight": "^1.17.0", - "prismjs": "^1.27.0", - "refractor": "^3.6.0" + "prop-types": "^15.7.2" }, "peerDependencies": { - "react": ">= 0.14.0" + "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/read-cache": { @@ -5351,16 +5349,12 @@ "use-sync-external-store": "^1.0.0" } }, - "react-syntax-highlighter": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", - "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "react-switch": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/react-switch/-/react-switch-7.0.0.tgz", + "integrity": "sha512-KkDeW+cozZXI6knDPyUt3KBN1rmhoVYgAdCJqAh7st7tk8YE6N0iR89zjCWO8T8dUTeJGTR0KU+5CHCRMRffiA==", "requires": { - "@babel/runtime": "^7.3.1", - "highlight.js": "^10.4.1", - "lowlight": "^1.17.0", - "prismjs": "^1.27.0", - "refractor": "^3.6.0" + "prop-types": "^15.7.2" } }, "read-cache": { diff --git a/extension/react-app/package.json b/extension/react-app/package.json index d43ec55e..5fe27916 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -19,6 +19,7 @@ "react-markdown": "^8.0.5", "react-redux": "^8.0.5", "react-syntax-highlighter": "^15.5.0", + "react-switch": "^7.0.0", "styled-components": "^5.3.6", "vscode-webview": "^1.0.1-beta.1" }, diff --git a/extension/react-app/public/continue.gif b/extension/react-app/public/continue.gif Binary files differnew file mode 100644 index 00000000..daed6663 --- /dev/null +++ b/extension/react-app/public/continue.gif diff --git a/extension/react-app/public/continue_arrow.png b/extension/react-app/public/continue_arrow.png Binary files differdeleted file mode 100644 index 3b16ddf9..00000000 --- a/extension/react-app/public/continue_arrow.png +++ /dev/null diff --git a/extension/react-app/public/play_button.png b/extension/react-app/public/play_button.png Binary files differnew file mode 100644 index 00000000..af379375 --- /dev/null +++ b/extension/react-app/public/play_button.png diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index a720a6ce..9438ab23 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -22,7 +22,7 @@ const StyledCopyButton = styled.button<{ visible: boolean }>` /* position: relative; */ float: right; border: none; - background-color: transparent; + background-color: ${secondaryDark}; cursor: pointer; padding: 0; /* margin: 4px; */ @@ -77,7 +77,10 @@ function CodeBlock(props: { language?: string; children: string }) { setHovered(false); }} > - <CopyButton visible={hovered} textToCopy={props.children} /> + <CopyButton + visible={hovered} + textToCopy={(props.children as any).props.children[0]} + /> <StyledCode>{props.children}</StyledCode> </StyledPre> ); diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index ddc9d5dc..3816cee8 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -116,6 +116,15 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { disabled={props.disabled} placeholder="Type '/' to see available slash commands." {...getInputProps({ + onChange: (e) => { + const target = e.target as HTMLTextAreaElement; + // Update the height of the textarea to match the content, up to a max of 200px. + target.style.height = "auto"; + target.style.height = `${Math.min( + target.scrollHeight, + 300 + ).toString()}px`; + }, onKeyDown: (event) => { if (event.key === "Enter" && event.shiftKey) { // Prevent Downshift's default 'Enter' behavior. @@ -136,14 +145,24 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { } else if (event.key === "Tab" && items.length > 0) { setInputValue(items[0].name); event.preventDefault(); - } else if (event.key === "ArrowUp") { + } else if ( + event.key === "ArrowUp" || + (event.key === "ArrowDown" && + event.currentTarget.value.split("\n").length > 1) + ) { + (event.nativeEvent as any).preventDownshiftDefault = true; + } else if ( + event.key === "ArrowUp" && + event.currentTarget.value.split("\n").length > 1 + ) { if (positionInHistory == 0) return; setInputValue(history[positionInHistory - 1]); setPositionInHistory((prev) => prev - 1); - } else if (event.key === "ArrowDown") { - if (positionInHistory >= history.length - 1) { - setInputValue(""); - } else { + } else if ( + event.key === "ArrowDown" && + event.currentTarget.value.split("\n").length > 1 + ) { + if (positionInHistory < history.length - 1) { setInputValue(history[positionInHistory + 1]); } setPositionInHistory((prev) => 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 f9483f0f..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 - style={{ padding: "3px" }} - onMouseEnter={() => setHover(true)} + disabled={props.disabled} + style={{ padding: "1px", paddingLeft: hover ? "4px" : "1px" }} + 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 1eb1d1fd..827d2d5f 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -49,9 +49,13 @@ const StepContainerDiv = styled.div<{ open: boolean }>` /* padding: 8px; */ `; -const HeaderDiv = styled.div<{ error: boolean }>` +const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>` background-color: ${(props) => - props.error ? "#522" : vscBackgroundTransparent}; + props.error + ? "#522" + : props.loading + ? vscBackgroundTransparent + : vscBackground}; display: grid; grid-template-columns: 1fr auto auto; grid-gap: 8px; @@ -76,12 +80,22 @@ const StyledCode = styled.code` color: lightgray; `; +const gradient = keyframes` + 0% { + background-position: 0px 0; + } + 100% { + background-position: 100em 0; + } +`; + const GradientBorder = styled.div<{ borderWidth?: number; borderRadius?: string; borderColor?: string; isFirst: boolean; isLast: boolean; + loading: boolean; }>` border-radius: ${(props) => props.borderRadius || "0"}; padding-top: ${(props) => @@ -91,13 +105,18 @@ const GradientBorder = styled.div<{ background: ${(props) => props.borderColor ? props.borderColor - : `linear-gradient( + : `repeating-linear-gradient( 101.79deg, #12887a 0%, - #87245c 37.64%, - #e12637 65.98%, - #ffb215 110.45% + #87245c 16%, + #e12637 33%, + #ffb215 55%, + #e12637 67%, + #87245c 85%, + #12887a 99% )`}; + animation: ${(props) => (props.loading ? gradient : "")} 6s linear infinite; + background-size: 200% 200%; `; function StepContainer(props: StepContainerProps) { @@ -138,10 +157,15 @@ function StepContainer(props: StepContainerProps) { > <StepContainerDiv open={props.open}> <GradientBorder + loading={props.historyNode.active as boolean | false} isFirst={props.isFirst} isLast={props.isLast} borderColor={ - props.historyNode.observation?.error ? "#f00" : undefined + props.historyNode.observation?.error + ? "#f00" + : props.historyNode.active + ? undefined + : "white" } className="overflow-hidden cursor-pointer" onClick={(e) => { @@ -153,6 +177,7 @@ function StepContainer(props: StepContainerProps) { }} > <HeaderDiv + loading={props.historyNode.active as boolean | false} error={props.historyNode.observation?.error ? true : false} > <h4 className="m-2"> @@ -175,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/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 624d22d5..13b74423 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -1,11 +1,5 @@ import styled from "styled-components"; -import { - defaultBorderRadius, - vscBackground, - Loader, - MainTextInput, - HeaderButton, -} from "../components"; +import { defaultBorderRadius, Loader } from "../components"; import ContinueButton from "../components/ContinueButton"; import { useCallback, useEffect, useRef, useState } from "react"; import { History } from "../../../schema/History"; @@ -20,6 +14,11 @@ import { import ComboBox from "../components/ComboBox"; import TextDialog from "../components/TextDialog"; import HeaderButtonWithText from "../components/HeaderButtonWithText"; +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; @@ -33,7 +32,7 @@ const UserInputQueueItem = styled.div` text-align: center; `; -const Footer = styled.footer` +const Footer = styled.footer<{ dataSwitchChecked: boolean }>` display: flex; flex-direction: row; gap: 8px; @@ -42,6 +41,8 @@ const Footer = styled.footer` align-items: center; margin-top: 8px; border-top: 0.1px solid gray; + background-color: ${(props) => + props.dataSwitchChecked ? "#12887a33" : "transparent"}; `; interface GUIProps { @@ -49,14 +50,22 @@ interface GUIProps { } function GUI(props: GUIProps) { + const posthog = usePostHog(); + const vscMachineId = useSelector( + (state: RootStore) => state.config.vscMachineId + ); + + const [usingFastModel, setUsingFastModel] = useState(false); const [waitingForSteps, setWaitingForSteps] = useState(false); const [userInputQueue, setUserInputQueue] = useState<string[]>([]); const [availableSlashCommands, setAvailableSlashCommands] = useState< { name: string; description: string }[] >([]); + const [dataSwitchChecked, setDataSwitchChecked] = useState(false); + const [showDataSharingInfo, setShowDataSharingInfo] = useState(false); const [stepsOpen, setStepsOpen] = useState<boolean[]>([]); const [history, setHistory] = useState<History | undefined>(); - // { + // { // timeline: [ // { // step: { @@ -144,6 +153,7 @@ function GUI(props: GUIProps) { // ], // }, // { + // active: false, // step: { // name: "SolveTracebackStep", // traceback: { @@ -204,24 +214,41 @@ function GUI(props: GUIProps) { }, [topGuiDivRef.current, scrollTimeout]); useEffect(() => { + const listener = (e: any) => { + // Cmd + J to toggle fast model + if (e.key === "i" && e.metaKey && e.shiftKey) { + setUsingFastModel((prev) => !prev); + } + }; + window.addEventListener("keydown", listener); + + return () => { + window.removeEventListener("keydown", listener); + }; + }, []); + + useEffect(() => { 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(); @@ -263,8 +290,9 @@ function GUI(props: GUIProps) { const onMainTextInput = () => { if (mainTextInputRef.current) { - if (!client) return; let input = mainTextInputRef.current.value; + mainTextInputRef.current.value = ""; + if (!client) return; if ( history?.timeline.length && @@ -301,6 +329,7 @@ function GUI(props: GUIProps) { // const iterations = useSelector(selectIterations); return ( <> + <LoadingCover hidden={true} message="Downloading local model..." /> <TextDialog showDialog={showFeedbackDialog} onEnter={(text) => { @@ -323,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) => { @@ -340,7 +367,7 @@ function GUI(props: GUIProps) { setStepsOpen(nextStepsOpen); }} onToggleAll={() => { - setStepsOpen((prev) => prev.map(() => !prev[index])); + setStepsOpen((prev) => prev.map((_, index) => !prev[index])); }} key={index} onUserInput={(input: string) => { @@ -390,17 +417,87 @@ function GUI(props: GUIProps) { /> <ContinueButton onClick={onMainTextInput} /> </TopGUIDiv> - <Footer> + <div + style={{ + position: "fixed", + bottom: "50px", + backgroundColor: "white", + color: "black", + borderRadius: defaultBorderRadius, + padding: "16px", + margin: "16px", + }} + 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. + <br /> + <br /> + <b> + {dataSwitchChecked + ? "No data is being collected. In the future, you would be contributing data" + : "No data is being collected. In the future, your data would not be shared"} + </b> + </div> + <Footer dataSwitchChecked={dataSwitchChecked}> + <div + style={{ + display: "flex", + gap: "4px", + marginRight: "auto", + alignItems: "center", + }} + onMouseEnter={() => { + setShowDataSharingInfo(true); + }} + onMouseLeave={() => { + setShowDataSharingInfo(false); + }} + > + <ReactSwitch + height={20} + handleDiameter={20} + width={40} + onChange={() => { + posthog?.capture("data_switch_toggled", { + vscMachineId: vscMachineId, + dataSwitchChecked: !dataSwitchChecked, + }); + setDataSwitchChecked((prev) => !prev); + }} + onColor="#12887a" + checked={dataSwitchChecked} + /> + <span style={{ cursor: "help", fontSize: "14px" }}> + Contribute Data + </span> + </div> + <HeaderButtonWithText + onClick={() => { + client?.changeDefaultModel( + usingFastModel ? "gpt-4" : "gpt-3.5-turbo" + ); + setUsingFastModel((prev) => !prev); + }} + text={usingFastModel ? "gpt-3.5-turbo" : "gpt-4"} + > + <div + style={{ fontSize: "18px", marginLeft: "2px", marginRight: "2px" }} + > + {usingFastModel ? "⚡" : "🧠"} + </div> + </HeaderButtonWithText> <HeaderButtonWithText onClick={() => { client?.sendClear(); }} - text="Clear History" + text="Clear All" > <Trash size="1.6em" /> </HeaderButtonWithText> <a href="https://continue.dev/docs" className="no-underline"> - <HeaderButtonWithText text="Continue Docs"> + <HeaderButtonWithText text="Docs"> <BookOpen size="1.6em" /> </HeaderButtonWithText> </a> |