diff options
author | Nate Sesti <sestinj@gmail.com> | 2023-08-20 20:21:33 -0700 |
---|---|---|
committer | Nate Sesti <sestinj@gmail.com> | 2023-08-20 20:21:33 -0700 |
commit | 2d3d96e5b55a225eb97251850909eb7a0a7242ed (patch) | |
tree | 208a20e6a833817766b697df3ab49efe0c1d07a2 /extension/react-app | |
parent | c98f860460767fe14f8fbf139150b1bd1ee2ff12 (diff) | |
download | sncontinue-2d3d96e5b55a225eb97251850909eb7a0a7242ed.tar.gz sncontinue-2d3d96e5b55a225eb97251850909eb7a0a7242ed.tar.bz2 sncontinue-2d3d96e5b55a225eb97251850909eb7a0a7242ed.zip |
feat: :sparkles: delete context groups
Diffstat (limited to 'extension/react-app')
6 files changed, 186 insertions, 103 deletions
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index c407a779..31cb4371 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -7,8 +7,6 @@ import React, { import { useCombobox } from "downshift"; import styled from "styled-components"; import { - Button, - TextInput, defaultBorderRadius, lightGray, secondaryDark, @@ -33,44 +31,14 @@ import { } from "../redux/slices/uiStateSlice"; import { useDispatch, useSelector } from "react-redux"; import { RootStore } from "../redux/store"; +import SelectContextGroupDialog from "./dialogs/SelectContextGroupDialog"; +import AddContextGroupDialog from "./dialogs/AddContextGroupDialog"; const SEARCH_INDEX_NAME = "continue_context_items"; // #region styled components const mainInputFontSize = 13; -const MiniPillSpan = styled.span` - padding: 3px; - padding-left: 6px; - padding-right: 6px; - border-radius: ${defaultBorderRadius}; - color: ${vscForeground}; - background-color: #fff3; - overflow: hidden; - font-size: 12px; - display: flex; - align-items: center; - text-align: center; - justify-content: center; -`; - -const ContextGroupSelectDiv = styled.div` - display: flex; - align-items: center; - gap: 8px; - padding: 8px; - border-radius: ${defaultBorderRadius}; - background-color: ${secondaryDark}; - color: ${vscForeground}; - margin-top: 8px; - cursor: pointer; - - &:hover { - background-color: ${vscBackground}; - color: ${vscForeground}; - } -`; - const EmptyPillDiv = styled.div` padding: 4px; padding-left: 8px; @@ -374,81 +342,16 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { }, [inputRef.current]); const showSelectContextGroupDialog = () => { - dispatch( - setDialogMessage( - <div className="px-4"> - <h2>Saved Context Groups</h2> - - {savedContextGroups && Object.keys(savedContextGroups).length > 0 ? ( - <div className="overflow-scroll"> - {Object.keys(savedContextGroups).map((key: string) => { - const contextGroup = savedContextGroups[key]; - return ( - <ContextGroupSelectDiv - onClick={() => { - dispatch(setDialogMessage(undefined)); - dispatch(setShowDialog(false)); - client?.selectContextGroup(key); - }} - > - <b>{key}: </b> - - {contextGroup.map((contextItem) => { - return ( - <MiniPillSpan> - {contextItem.description.name} - </MiniPillSpan> - ); - })} - </ContextGroupSelectDiv> - ); - })} - </div> - ) : ( - <div>No saved context groups</div> - )} - <Button - className="ml-auto" - onClick={() => { - dispatch(setDialogMessage(undefined)); - dispatch(setShowDialog(false)); - }} - > - Cancel - </Button> - </div> - ) - ); + dispatch(setDialogMessage(<SelectContextGroupDialog />)); dispatch(setShowDialog(true)); }; const showDialogToSaveContextGroup = () => { - let inputElement: HTMLInputElement | null = null; dispatch( setDialogMessage( - <div> - <TextInput - defaultValue="My Context Group" - type="text" - ref={(input) => { - inputElement = input; - }} - /> - <br /> - <Button - className="ml-auto" - onClick={() => { - dispatch(setDialogMessage(undefined)); - dispatch(setShowDialog(false)); - const title = inputElement - ? inputElement.value - : "My Context Group"; - client?.saveContextGroup(title, props.selectedContextItems); - }} - > - Create - </Button> - </div> + <AddContextGroupDialog + selectedContextItems={props.selectedContextItems} + /> ) ); dispatch(setShowDialog(true)); diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index 7fcc41f1..44d25ae6 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -58,6 +58,19 @@ const TextDialog = (props: { onClose: () => void; message?: string | JSX.Element; }) => { + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + props.onClose(); + } + }; + + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [props]); + return ( <ScreenCover onClick={() => { diff --git a/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx b/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx new file mode 100644 index 00000000..f6c7c626 --- /dev/null +++ b/extension/react-app/src/components/dialogs/AddContextGroupDialog.tsx @@ -0,0 +1,50 @@ +import { useContext } from "react"; +import { Button, TextInput } from ".."; +import { GUIClientContext } from "../../App"; +import { useDispatch } from "react-redux"; +import { + setDialogMessage, + setShowDialog, +} from "../../redux/slices/uiStateSlice"; +import { ContextItem } from "../../../../schema/FullState"; + +function AddContextGroupDialog({ + selectedContextItems, +}: { + selectedContextItems: ContextItem[]; +}) { + const dispatch = useDispatch(); + const client = useContext(GUIClientContext); + + let inputElement: HTMLInputElement | null = null; + + const handleCreate = () => { + dispatch(setDialogMessage(undefined)); + dispatch(setShowDialog(false)); + const title = inputElement ? inputElement.value : "My Context Group"; + client?.saveContextGroup(title, selectedContextItems); + }; + + return ( + <div> + <TextInput + defaultValue="My Context Group" + type="text" + ref={(input) => { + inputElement = input; + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + handleCreate(); + } + }} + /> + <br /> + <Button className="ml-auto" onClick={handleCreate}> + Create + </Button> + </div> + ); +} + +export default AddContextGroupDialog; diff --git a/extension/react-app/src/components/dialogs/SelectContextGroupDialog.tsx b/extension/react-app/src/components/dialogs/SelectContextGroupDialog.tsx new file mode 100644 index 00000000..b8fc2bb7 --- /dev/null +++ b/extension/react-app/src/components/dialogs/SelectContextGroupDialog.tsx @@ -0,0 +1,111 @@ +import { useDispatch, useSelector } from "react-redux"; +import { RootStore } from "../../redux/store"; +import { useContext } from "react"; +import { GUIClientContext } from "../../App"; +import { TrashIcon } from "@heroicons/react/24/outline"; +import HeaderButtonWithText from "../HeaderButtonWithText"; +import { + setDialogMessage, + setShowDialog, +} from "../../redux/slices/uiStateSlice"; +import { + Button, + defaultBorderRadius, + secondaryDark, + vscBackground, + vscForeground, +} from ".."; +import styled from "styled-components"; + +const MiniPillSpan = styled.span` + padding: 3px; + padding-left: 6px; + padding-right: 6px; + border-radius: ${defaultBorderRadius}; + color: ${vscForeground}; + background-color: #fff3; + overflow: hidden; + font-size: 12px; + display: flex; + align-items: center; + text-align: center; + justify-content: center; +`; + +const ContextGroupSelectDiv = styled.div` + display: flex; + align-items: center; + gap: 8px; + padding: 8px; + border-radius: ${defaultBorderRadius}; + background-color: ${secondaryDark}; + color: ${vscForeground}; + margin-top: 8px; + cursor: pointer; + + &:hover { + background-color: ${vscBackground}; + color: ${vscForeground}; + } +`; + +function SelectContextGroupDialog() { + const dispatch = useDispatch(); + const savedContextGroups = useSelector( + (state: RootStore) => state.serverState.saved_context_groups + ); + const client = useContext(GUIClientContext); + + return ( + <div className="px-4"> + <h2>Saved Context Groups</h2> + + {savedContextGroups && Object.keys(savedContextGroups).length > 0 ? ( + <div className="overflow-scroll"> + {Object.keys(savedContextGroups).map((key: string) => { + const contextGroup = savedContextGroups[key]; + return ( + <ContextGroupSelectDiv + onClick={() => { + dispatch(setDialogMessage(undefined)); + dispatch(setShowDialog(false)); + client?.selectContextGroup(key); + }} + > + <b>{key}: </b> + + {contextGroup.map((contextItem) => { + return ( + <MiniPillSpan>{contextItem.description.name}</MiniPillSpan> + ); + })} + <HeaderButtonWithText + text="Delete" + onClick={(e) => { + e.stopPropagation(); + client?.deleteContextGroup(key); + }} + > + <TrashIcon width="1.4em" height="1.4em" /> + </HeaderButtonWithText> + </ContextGroupSelectDiv> + ); + })} + </div> + ) : ( + <div>No saved context groups</div> + )} + <Button + className="ml-auto" + onClick={() => { + dispatch(setDialogMessage(undefined)); + dispatch(setShowDialog(false)); + }} + > + Cancel + </Button> + </div> + ); +} + +export default SelectContextGroupDialog; diff --git a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts index 2e8aaeef..c9e7def2 100644 --- a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts @@ -40,6 +40,8 @@ abstract class AbstractContinueGUIClientProtocol { abstract saveContextGroup(title: string, contextItems: ContextItem[]): void; abstract selectContextGroup(id: string): void; + + abstract deleteContextGroup(id: string): void; } export default AbstractContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index aa558adb..b3ac2570 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -143,6 +143,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { selectContextGroup(id: string): void { this.messenger?.send("select_context_group", { id }); } + + deleteContextGroup(id: string): void { + this.messenger?.send("delete_context_group", { id }); + } } export default ContinueGUIClientProtocol; |