diff options
author | Ty Dunn <ty@tydunn.com> | 2023-07-04 21:37:39 -0700 |
---|---|---|
committer | Ty Dunn <ty@tydunn.com> | 2023-07-04 21:37:39 -0700 |
commit | 26f147d2fdd5412117445c97a937c49b064da082 (patch) | |
tree | 0dd728f2ce806d0dba2dc15a65a26f2c58562a74 /extension/react-app | |
parent | d802dae10b26f59893380829feea3104b0650e14 (diff) | |
parent | 2d8c28965684d03ef711253e5555ef304882828f (diff) | |
download | sncontinue-26f147d2fdd5412117445c97a937c49b064da082.tar.gz sncontinue-26f147d2fdd5412117445c97a937c49b064da082.tar.bz2 sncontinue-26f147d2fdd5412117445c97a937c49b064da082.zip |
Merge branch 'main' into stop
Diffstat (limited to 'extension/react-app')
9 files changed, 92 insertions, 32 deletions
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 742c643b..3e1f3e16 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { useCombobox } from "downshift"; import styled from "styled-components"; import { @@ -10,7 +10,10 @@ import { import CodeBlock from "./CodeBlock"; import { RangeInFile } from "../../../src/client"; import PillButton from "./PillButton"; +import HeaderButtonWithText from "./HeaderButtonWithText"; +import { Trash, LockClosed, LockOpen } from "@styled-icons/heroicons-outline"; +// #region styled components const mainInputFontSize = 16; const ContextDropdown = styled.div` @@ -87,13 +90,16 @@ const Li = styled.li<{ cursor: pointer; `; +// #endregion + interface ComboBoxProps { items: { name: string; description: string }[]; onInputValueChange: (inputValue: string) => void; disabled?: boolean; - onEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void; - highlightedCodeSections?: (RangeInFile & { contents: string })[]; - deleteContextItem?: (idx: number) => void; + onEnter: (e: React.KeyboardEvent<HTMLInputElement>) => void; + highlightedCodeSections: (RangeInFile & { contents: string })[]; + deleteContextItems: (indices: number[]) => void; + onTogglePin: () => void; } const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { @@ -104,6 +110,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { const [hoveringButton, setHoveringButton] = React.useState(false); const [hoveringContextDropdown, setHoveringContextDropdown] = React.useState(false); + const [pinned, setPinned] = useState(false); const [highlightedCodeSections, setHighlightedCodeSections] = React.useState( props.highlightedCodeSections || [ { @@ -242,12 +249,42 @@ 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="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} + title={`${section.filepath} (${section.range.start.line + 1}-${ + section.range.end.line + 1 + })`} onDelete={() => { - if (props.deleteContextItem) { - props.deleteContextItem(idx); + if (props.deleteContextItems) { + props.deleteContextItems([idx]); } setHighlightedCodeSections((prev) => { const newSections = [...prev]; @@ -280,7 +317,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { onMouseLeave={() => { setHoveringContextDropdown(false); }} - hidden={!hoveringContextDropdown && !hoveringButton} + hidden={true || (!hoveringContextDropdown && !hoveringButton)} > {highlightedCodeSections.map((section, idx) => ( <> diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index 30931f86..3ddac93c 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -7,12 +7,14 @@ interface HeaderButtonWithTextProps { onClick?: (e: any) => void; children: React.ReactNode; disabled?: boolean; + inverted?: boolean; } const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => { const [hover, setHover] = useState(false); return ( <HeaderButton + inverted={props.inverted} disabled={props.disabled} style={{ padding: "1px", paddingLeft: hover ? "4px" : "1px" }} onMouseEnter={() => { diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index 33451db5..2352c3ad 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import styled from "styled-components"; import { defaultBorderRadius } from "."; +import { XMark } from "@styled-icons/heroicons-outline"; const Button = styled.button` border: none; @@ -42,22 +43,21 @@ const PillButton = (props: PillButtonProps) => { <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: "4px" }} > - <span>{props.title}</span> <span style={{ cursor: "pointer", color: "red", - borderLeft: "1px solid black", - paddingLeft: "4px", + borderRight: "1px solid black", + paddingRight: "4px", }} - hidden={!isHovered} onClick={() => { props.onDelete?.(); props.onHover?.(false); }} > - X + <XMark style={{ padding: "0px" }} size="1.2em" strokeWidth="2px" /> </span> + <span>{props.title}</span> </div> </Button> ); diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 492857b5..311f68cf 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -84,7 +84,8 @@ const MarkdownPre = styled.pre` const StyledCode = styled.code` word-wrap: break-word; - color: lightgray; + color: #f69292; + background: transparent; `; const gradient = keyframes` diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx index 59453169..44fdba38 100644 --- a/extension/react-app/src/components/UserInputContainer.tsx +++ b/extension/react-app/src/components/UserInputContainer.tsx @@ -6,10 +6,12 @@ import HeaderButtonWithText from "./HeaderButtonWithText"; import { Play, XMark } from "@styled-icons/heroicons-outline"; import { RootStore } from "../redux/store"; import { useSelector } from "react-redux"; +import { HistoryNode } from "../../../schema/HistoryNode"; interface UserInputContainerProps { onDelete: () => void; children: string; + historyNode: HistoryNode; } const StyledDiv = styled.div` @@ -26,7 +28,7 @@ const StyledDiv = styled.div` const UserInputContainer = (props: UserInputContainerProps) => { return ( - <StyledDiv> + <StyledDiv hidden={props.historyNode.step.hide as any}> {props.children} <div style={{ marginLeft: "auto" }}> <HeaderButtonWithText @@ -36,7 +38,7 @@ const UserInputContainer = (props: UserInputContainerProps) => { }} text="Delete" > - <XMark size="1.6em" onClick={props.onDelete} /> + <XMark size="1.6em" /> </HeaderButtonWithText> </div> </StyledDiv> diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index 429a7df5..db1925ed 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -124,16 +124,19 @@ export const appear = keyframes` } `; -export const HeaderButton = styled.button` - background-color: transparent; +export const HeaderButton = styled.button<{ inverted: boolean | undefined }>` + background-color: ${({ inverted }) => (inverted ? "white" : "transparent")}; + color: ${({ inverted }) => (inverted ? "black" : "white")}; + border: 1px solid white; border-radius: ${defaultBorderRadius}; cursor: pointer; - color: white; &:hover { - background-color: white; - color: black; + background-color: ${({ inverted }) => + typeof inverted === "undefined" || inverted ? "white" : "transparent"}; + color: ${({ inverted }) => + typeof inverted === "undefined" || inverted ? "black" : "white"}; } display: flex; align-items: center; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 228e9a53..96ea7ab3 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -21,7 +21,7 @@ abstract class AbstractContinueGUIClientProtocol { abstract deleteAtIndex(index: number): void; - abstract deleteContextItemAtIndex(index: number): void; + abstract deleteContextAtIndices(indices: number[]): void; } export default AbstractContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index a0c38c0f..e950387c 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -71,8 +71,8 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { this.messenger.send("delete_at_index", { index }); } - deleteContextItemAtIndex(index: number) { - this.messenger.send("delete_context_item_at_index", { index }); + deleteContextAtIndices(indices: number[]) { + this.messenger.send("delete_context_at_indices", { indices }); } } diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 40256f86..bbf0b126 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -74,6 +74,7 @@ function GUI(props: GUIProps) { const [availableSlashCommands, setAvailableSlashCommands] = useState< { name: string; description: string }[] >([]); + const [pinned, setPinned] = useState(false); const [showDataSharingInfo, setShowDataSharingInfo] = useState(false); const [stepsOpen, setStepsOpen] = useState<boolean[]>([ true, @@ -87,13 +88,16 @@ function GUI(props: GUIProps) { step: { name: "Welcome to Continue", hide: false, - description: - "Highlight code and ask a question or give instructions. Past steps are used as additional context by default. Use slash commands when you want fine-grained control.", + description: `- Highlight code and ask a question or give instructions +- Use \`cmd+k\` (Mac) / \`ctrl+k\` (Windows) to open Continue +- Use \`cmd+shift+e\` / \`ctrl+shift+e\` to open file Explorer +- Add your own OpenAI API key to VS Code Settings with \`cmd+,\` +- Use slash commands when you want fine-grained control +- Past steps are included as part of the context by default`, system_message: null, chat_context: [], manage_own_chat_context: false, - message: - "Highlight code and ask a question or give instructions. Past steps are used as additional context by default. Use slash commands when you want fine-grained control.", + message: "", }, depth: 0, deleted: false, @@ -185,9 +189,9 @@ function GUI(props: GUIProps) { const mainTextInputRef = useRef<HTMLInputElement>(null); - const deleteContextItem = useCallback( - (idx: number) => { - client?.deleteContextItemAtIndex(idx); + const deleteContextItems = useCallback( + (indices: number[]) => { + client?.deleteContextAtIndices(indices); }, [client] ); @@ -241,6 +245,13 @@ function GUI(props: GUIProps) { setUserInputQueue((queue) => { return [...queue, input]; }); + + // Delete all context items unless locked + if (!pinned) { + client?.deleteContextAtIndices( + highlightedRanges.map((_, index) => index) + ); + } } }; @@ -286,6 +297,7 @@ function GUI(props: GUIProps) { onDelete={() => { client?.deleteAtIndex(index); }} + historyNode={node} > {node.step.description as string} </UserInputContainer> @@ -345,7 +357,10 @@ function GUI(props: GUIProps) { onInputValueChange={() => {}} items={availableSlashCommands} highlightedCodeSections={highlightedRanges} - deleteContextItem={deleteContextItem} + deleteContextItems={deleteContextItems} + onTogglePin={() => { + setPinned((prev: boolean) => !prev); + }} /> <ContinueButton onClick={onMainTextInput} /> </TopGUIDiv> |