diff options
author | Nate Sesti <sestinj@gmail.com> | 2023-06-06 00:21:15 -0400 |
---|---|---|
committer | Nate Sesti <sestinj@gmail.com> | 2023-06-06 00:21:15 -0400 |
commit | 04aa13340b7a621a9ff678a3c0cfc1d9aa9fb646 (patch) | |
tree | ad6acb284566c9ad4bda6eaf78ad5283368e86f4 /extension | |
parent | 9cda43f842b2489ce3119f43596a1a8a997adeb2 (diff) | |
download | sncontinue-04aa13340b7a621a9ff678a3c0cfc1d9aa9fb646.tar.gz sncontinue-04aa13340b7a621a9ff678a3c0cfc1d9aa9fb646.tar.bz2 sncontinue-04aa13340b7a621a9ff678a3c0cfc1d9aa9fb646.zip |
many design improvements
Diffstat (limited to 'extension')
-rw-r--r-- | extension/package.json | 4 | ||||
-rw-r--r-- | extension/react-app/src/components/DebugPanel.tsx | 15 | ||||
-rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 52 | ||||
-rw-r--r-- | extension/react-app/src/components/index.ts | 11 | ||||
-rw-r--r-- | extension/react-app/src/tabs/chat/MessageDiv.tsx | 1 | ||||
-rw-r--r-- | extension/react-app/src/tabs/gui.tsx | 74 | ||||
-rw-r--r-- | extension/src/continueIdeClient.ts | 39 |
7 files changed, 141 insertions, 55 deletions
diff --git a/extension/package.json b/extension/package.json index 7bd48f98..c834f402 100644 --- a/extension/package.json +++ b/extension/package.json @@ -42,12 +42,12 @@ "description": "The URL of the Continue server to use." }, "continue.OPENAI_API_KEY": { - "type": "string", + "type": "password", "default": "", "description": "The OpenAI API key to use for code generation." }, "continue.HUGGING_FACE_TOKEN": { - "type": "string", + "type": "password", "default": "", "description": "The Hugging Face API token to use for code generation." } diff --git a/extension/react-app/src/components/DebugPanel.tsx b/extension/react-app/src/components/DebugPanel.tsx index 9dacc624..11ec2fe2 100644 --- a/extension/react-app/src/components/DebugPanel.tsx +++ b/extension/react-app/src/components/DebugPanel.tsx @@ -9,7 +9,7 @@ import { } from "../redux/slices/configSlice"; import { setHighlightedCode } from "../redux/slices/miscSlice"; import { updateFileSystem } from "../redux/slices/debugContexSlice"; -import { buttonColor, defaultBorderRadius, vscBackground } from "."; +import { defaultBorderRadius, secondaryDark, vscBackground } from "."; interface DebugPanelProps { tabs: { element: React.ReactElement; @@ -19,14 +19,15 @@ interface DebugPanelProps { const GradientContainer = styled.div` // Uncomment to get gradient border - background: linear-gradient( + /* background: linear-gradient( 101.79deg, #12887a 0%, #87245c 37.64%, #e12637 65.98%, #ffb215 110.45% - ); + ); */ /* padding: 10px; */ + background-color: ${secondaryDark}; margin: 0; height: 100%; /* border: 1px solid white; */ @@ -36,11 +37,8 @@ const GradientContainer = styled.div` const MainDiv = styled.div` height: 100%; border-radius: ${defaultBorderRadius}; - overflow-y: scroll; - scrollbar-gutter: stable both-edges; scrollbar-base-color: transparent; - /* background: ${vscBackground}; */ - background-color: #1e1e1ede; + background-color: ${vscBackground}; `; const TabBar = styled.div<{ numTabs: number }>` @@ -105,9 +103,6 @@ function DebugPanel(props: DebugPanelProps) { <div key={index} hidden={index !== currentTab} - className={ - tab.title === "Chat" ? "overflow-hidden" : "overflow-scroll" - } style={{ scrollbarGutter: "stable both-edges" }} > {tab.element} diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index f54d4d75..dab5a752 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -2,13 +2,11 @@ import { useCallback, useEffect, useRef, useState } from "react"; import styled, { keyframes } from "styled-components"; import { appear, - buttonColor, defaultBorderRadius, - MainContainerWithBorder, - MainTextInput, secondaryDark, vscBackground, GradientBorder, + vscBackgroundTransparent, } from "."; import { RangeInFile, FileEdit } from "../../../src/client"; import CodeBlock from "./CodeBlock"; @@ -32,6 +30,7 @@ interface StepContainerProps { onRefinement: (input: string) => void; onUserInput: (input: string) => void; onRetry: () => void; + open?: boolean; } const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>` @@ -44,17 +43,25 @@ const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>` `; const StepContainerDiv = styled.div<{ open: boolean }>` - background-color: ${(props) => (props.open ? vscBackground : secondaryDark)}; - border-radius: ${defaultBorderRadius}; - padding: 8px; + /* background-color: ${(props) => + props.open ? vscBackground : secondaryDark}; */ + /* border-radius: ${defaultBorderRadius}; */ + /* padding: 8px; */ `; const HeaderDiv = styled.div` + background-color: ${vscBackgroundTransparent}; display: grid; grid-template-columns: 1fr auto; align-items: center; `; +const ContentDiv = styled.div` + padding: 8px; + padding-left: 16px; + background-color: ${vscBackground}; +`; + const HeaderButton = styled.button` background-color: transparent; border: 1px solid white; @@ -75,12 +82,10 @@ const OnHoverDiv = styled.div` animation: ${appear} 0.3s ease-in-out; `; -const NaturalLanguageInput = styled(MainTextInput)` - width: 80%; -`; - function StepContainer(props: StepContainerProps) { - const [open, setOpen] = useState(false); + const [open, setOpen] = useState( + typeof props.open === "undefined" ? true : props.open + ); const [isHovered, setIsHovered] = useState(false); const naturalLanguageInputRef = useRef<HTMLTextAreaElement>(null); const userInputRef = useRef<HTMLInputElement>(null); @@ -116,11 +121,11 @@ function StepContainer(props: StepContainerProps) { }} hidden={props.historyNode.step.hide as any} > - <GradientBorder - className="m-2 overflow-hidden cursor-pointer" - onClick={() => setOpen((prev) => !prev)} - > - <StepContainerDiv open={open}> + <StepContainerDiv open={open}> + <GradientBorder + className="overflow-hidden cursor-pointer" + onClick={() => setOpen((prev) => !prev)} + > <HeaderDiv> <h4 className="m-2"> {open ? ( @@ -128,7 +133,7 @@ function StepContainer(props: StepContainerProps) { ) : ( <ChevronRight size="1.4em" /> )} - {props.historyNode.step.name as any}: + {props.historyNode.step.name as any} </h4> {/* <HeaderButton onClick={(e) => { @@ -152,8 +157,9 @@ function StepContainer(props: StepContainerProps) { <></> )} </HeaderDiv> - - {open && ( + </GradientBorder> + <ContentDiv hidden={!open}> + {open && false && ( <> <pre className="overflow-scroll"> Step Details: @@ -177,7 +183,7 @@ function StepContainer(props: StepContainerProps) { </ReactMarkdown> )} - {props.historyNode.step.name === "Waiting for user input" && ( + {/* {props.historyNode.step.name === "Waiting for user input" && ( <InputAndButton onUserInput={(value) => { props.onUserInput(value); @@ -202,9 +208,9 @@ function StepContainer(props: StepContainerProps) { value="Confirm" /> </> - )} - </StepContainerDiv> - </GradientBorder> + )} */} + </ContentDiv> + </StepContainerDiv> {/* <OnHoverDiv hidden={!open}> <NaturalLanguageInput diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index 7ba60467..ac5faa41 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -3,6 +3,7 @@ import styled, { keyframes } from "styled-components"; export const defaultBorderRadius = "5px"; export const secondaryDark = "rgb(37 37 38)"; export const vscBackground = "rgb(30 30 30)"; +export const vscBackgroundTransparent = "#1e1e1ede"; export const buttonColor = "rgb(113 28 59)"; export const buttonColorHover = "rgb(113 28 59 0.67)"; @@ -94,9 +95,13 @@ export const Loader = styled.div` margin: auto; `; -export const GradientBorder = styled.div<{ borderWidth?: string }>` - border-radius: ${defaultBorderRadius}; - padding: ${(props) => props.borderWidth || "1px"}; +export const GradientBorder = styled.div<{ + borderWidth?: string; + borderRadius?: string; +}>` + border-radius: ${(props) => props.borderRadius || "0"}; + padding-top: ${(props) => props.borderWidth || "1px"}; + padding-bottom: ${(props) => props.borderWidth || "1px"}; background: linear-gradient( 101.79deg, #12887a 0%, diff --git a/extension/react-app/src/tabs/chat/MessageDiv.tsx b/extension/react-app/src/tabs/chat/MessageDiv.tsx index ad81f5e9..1d7bb5f5 100644 --- a/extension/react-app/src/tabs/chat/MessageDiv.tsx +++ b/extension/react-app/src/tabs/chat/MessageDiv.tsx @@ -21,7 +21,6 @@ const Container = styled.div` width: fit-content; max-width: 75%; overflow-y: scroll; - scrollbar-gutter: stable both-edges; word-wrap: break-word; -ms-word-wrap: break-word; height: fit-content; diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 7dd30acb..c66172a9 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -1,25 +1,21 @@ import styled from "styled-components"; import { - Button, defaultBorderRadius, vscBackground, - MainTextInput, Loader, + MainTextInput, } from "../components"; import ContinueButton from "../components/ContinueButton"; import { useCallback, useEffect, useRef, useState } from "react"; import { History } from "../../../schema/History"; import { HistoryNode } from "../../../schema/HistoryNode"; import StepContainer from "../components/StepContainer"; -import { useSelector } from "react-redux"; -import { RootStore } from "../redux/store"; -import useContinueWebsocket from "../hooks/useWebsocket"; import useContinueGUIProtocol from "../hooks/useWebsocket"; let TopGUIDiv = styled.div` display: grid; grid-template-columns: 1fr; - overflow: scroll; + background-color: ${vscBackground}; `; let UserInputQueueItem = styled.div` @@ -156,8 +152,20 @@ function GUI(props: GUIProps) { // current_index: 0, // } as any); + const topGuiDivRef = useRef<HTMLDivElement>(null); const client = useContinueGUIProtocol(); + const scrollToBottom = useCallback(() => { + if (topGuiDivRef.current) { + setTimeout(() => { + window.scrollTo({ + top: window.outerHeight, + behavior: "smooth", + }); + }, 100); + } + }, [topGuiDivRef.current]); + useEffect(() => { console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate); client?.onStateUpdate((state) => { @@ -165,9 +173,15 @@ function GUI(props: GUIProps) { setWaitingForSteps(state.active); setHistory(state.history); setUserInputQueue(state.user_input_queue); + + scrollToBottom(); }); }, [client]); + useEffect(() => { + scrollToBottom(); + }, [waitingForSteps]); + const mainTextInputRef = useRef<HTMLTextAreaElement>(null); useEffect(() => { @@ -189,16 +203,33 @@ function GUI(props: GUIProps) { if (mainTextInputRef.current) { if (!client) return; let input = mainTextInputRef.current.value; - if (input.trim() === "") return; - setWaitingForSteps(true); - client.sendMainInput(input); - setUserInputQueue((queue) => { - return [...queue, input]; - }); - mainTextInputRef.current.value = ""; - mainTextInputRef.current.style.height = ""; + if ( + history && + history.timeline[history.current_index].step.name === + "Waiting for user input" + ) { + if (input.trim() === "") return; + onStepUserInput(input, history!.current_index); + } else if ( + history && + history.timeline[history.current_index].step.name === + "Waiting for user confirmation" + ) { + onStepUserInput("ok", history!.current_index); + } else { + if (input.trim() === "") return; + + client.sendMainInput(input); + setUserInputQueue((queue) => { + return [...queue, input]; + }); + mainTextInputRef.current.value = ""; + mainTextInputRef.current.style.height = ""; + } } + + setWaitingForSteps(true); }; const onStepUserInput = (input: string, index: number) => { @@ -209,7 +240,14 @@ function GUI(props: GUIProps) { // const iterations = useSelector(selectIterations); return ( - <TopGUIDiv> + <TopGUIDiv + ref={topGuiDivRef} + onKeyDown={(e) => { + if (e.key === "Enter" && e.ctrlKey) { + onMainTextInput(); + } + }} + > {typeof client === "undefined" && ( <> <Loader></Loader> @@ -249,6 +287,12 @@ function GUI(props: GUIProps) { </div> <MainTextInput + disabled={ + history + ? history.timeline[history.current_index].step.name === + "Waiting for user confirmation" + : false + } ref={mainTextInputRef} onKeyDown={(e) => { if (e.key === "Enter") { diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index a5a1c5dc..25287d32 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -96,6 +96,12 @@ class IdeProtocolClient { fileEdit, }); break; + case "highlightCode": + this.highlightCode(data.rangeInFile, data.color); + break; + case "runCommand": + this.runCommand(data.command); + break; case "saveFile": this.saveFile(data.filepath); break; @@ -117,6 +123,28 @@ class IdeProtocolClient { // ------------------------------------ // // On message handlers + async highlightCode(rangeInFile: RangeInFile, color: string) { + const range = new vscode.Range( + rangeInFile.range.start.line, + rangeInFile.range.start.character, + rangeInFile.range.end.line, + rangeInFile.range.end.character + ); + const editor = await openEditorAndRevealRange( + rangeInFile.filepath, + range, + vscode.ViewColumn.One + ); + if (editor) { + editor.setDecorations( + vscode.window.createTextEditorDecorationType({ + backgroundColor: color, + }), + [range] + ); + } + } + showSuggestion(edit: FileEdit) { // showSuggestion already exists showSuggestion( @@ -289,7 +317,16 @@ class IdeProtocolClient { } runCommand(command: string) { - vscode.window.terminals[0].sendText(command, true); + if (vscode.window.terminals.length === 0) { + const terminal = vscode.window.createTerminal(); + terminal.show(); + terminal.sendText("bash", true); + terminal.sendText(command, true); + return; + } + const terminal = vscode.window.terminals[0]; + terminal.show(); + terminal.sendText(command, true); // But need to know when it's done executing... } } |