From 9f10ed373c6b8878fa30dae93950d246674bba29 Mon Sep 17 00:00:00 2001 From: Antoine Dewez <44063631+Zewed@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:50:09 -0800 Subject: [PATCH] feat(frontend): display which brain you are talking to (#2137) # Description Please include a summary of the changes and the related issue. Please also include relevant motivation and context. ## Checklist before requesting a review Please delete options that are not relevant. - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented hard-to-understand areas - [ ] I have ideally added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged ## Screenshots (if appropriate): --- .../ChatEditor/components/Editor/Editor.tsx | 8 ++- .../Editor/hooks/useChatStateUpdater.ts | 2 +- .../Editor/hooks/useMentionConfig.ts | 5 +- .../ChatEditor/components/Editor/styles.css | 4 +- .../components/ChatInput/index.module.scss | 22 +++++++ .../ActionsBar/components/ChatInput/index.tsx | 58 +++++++++++-------- .../MessageRow/MessageRow.module.scss | 3 +- .../components/DataPanel/DataPanel.tsx | 1 - .../RelatedBrains/RelatedBrains.tsx | 3 +- frontend/app/search/page.module.scss | 24 ++++++-- frontend/app/search/page.tsx | 10 ++++ .../CurrentBrain/CurrentBrain.module.scss | 33 +++++++++++ .../components/CurrentBrain/CurrentBrain.tsx | 39 +++++++++++++ .../DiscussionButton.module.scss | 5 +- .../ChatHistoryItem.module.scss | 3 +- .../MenuButton/MenuButton.module.scss | 5 +- .../components/SearchModal/SearchModal.tsx | 8 +-- .../FoldableSection.module.scss | 3 +- .../ui/SearchBar/SearchBar.module.scss | 37 +++++++----- .../lib/components/ui/SearchBar/SearchBar.tsx | 49 ++++++++++------ frontend/lib/helpers/iconList.ts | 3 +- frontend/styles/_Radius.module.scss | 3 + 22 files changed, 246 insertions(+), 82 deletions(-) create mode 100644 frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.module.scss create mode 100644 frontend/lib/components/CurrentBrain/CurrentBrain.module.scss create mode 100644 frontend/lib/components/CurrentBrain/CurrentBrain.tsx create mode 100644 frontend/styles/_Radius.module.scss diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/Editor.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/Editor.tsx index 6f8838e76380..30b8baa86208 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/Editor.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/Editor.tsx @@ -22,7 +22,13 @@ export const Editor = ({ const { editor } = useCreateEditorState(placeholder); useEffect(() => { - if (message === "") { + const htmlString = editor?.getHTML(); + if ( + message === "" || + (htmlString && + new DOMParser().parseFromString(htmlString, "text/html").body + .textContent === " ") + ) { editor?.commands.clearContent(); } }, [message, editor]); diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useChatStateUpdater.ts b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useChatStateUpdater.ts index ae5fc2ee82a2..7186496fff5b 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useChatStateUpdater.ts +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useChatStateUpdater.ts @@ -32,7 +32,7 @@ export const useChatStateUpdater = ({ if (brainId !== currentBrainId) { if (brainId === "") { - setCurrentBrainId(null); + return; } else { if (currentBrainId !== null) { removeExistingMentionFromEditor(editorNewState, "mention@"); diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useMentionConfig.ts b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useMentionConfig.ts index 12f211035b64..cbddf689cfbd 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useMentionConfig.ts +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/hooks/useMentionConfig.ts @@ -109,8 +109,9 @@ export const useMentionConfig = ({ class: "mention", }, suggestion: suggestionsConfig, - renderLabel: ({ options, node }) => - `${options.suggestion.char ?? ""}${node.attrs.label as string}`, + renderLabel: () => { + return ""; + }, }); return { diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/styles.css b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/styles.css index 6c799c7a6c5f..12684f18a7af 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/styles.css +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/ChatEditor/components/Editor/styles.css @@ -6,7 +6,5 @@ height: 0; } .mention { - background-color: #E0DDFC; - border-radius: 4px; - padding: 2px 4px; + display: none; } \ No newline at end of file diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.module.scss b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.module.scss new file mode 100644 index 000000000000..a774ddbb22f6 --- /dev/null +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.module.scss @@ -0,0 +1,22 @@ +@use "@/styles/Colors.module.scss"; +@use "@/styles/Radius.module.scss"; +@use "@/styles/Spacings.module.scss"; + +.chat_container { + display: flex; + flex-direction: column; + background-color: Colors.$white; + gap: Spacings.$spacing03; + border-radius: Radius.$big; + border: 1px solid Colors.$lighter-grey; + overflow: hidden; + + .chat_wrapper { + display: flex; + padding: Spacings.$spacing05; + + &.with_brain { + padding-top: 0; + } + } +} diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx index 22dd6bd6d82d..95352308078b 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx @@ -1,15 +1,19 @@ "use client"; +import { CurrentBrain } from "@/lib/components/CurrentBrain/CurrentBrain"; import Icon from "@/lib/components/ui/Icon/Icon"; import { LoaderIcon } from "@/lib/components/ui/LoaderIcon/LoaderIcon"; +import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; import { OnboardingQuestions } from "./components"; import { ChatEditor } from "./components/ChatEditor/ChatEditor"; import { useChatInput } from "./hooks/useChatInput"; +import styles from "./index.module.scss"; export const ChatInput = (): JSX.Element => { const { setMessage, submitQuestion, generatingAnswer, message } = useChatInput(); + const { currentBrain } = useBrainContext(); const handleSubmitQuestion = () => { if (message.trim() !== "") { @@ -20,36 +24,42 @@ export const ChatInput = (): JSX.Element => { return ( <> -
-
{ - e.preventDefault(); - handleSubmitQuestion(); - }} - className="sticky bottom-0 bg-white dark:bg-black w-full flex items-center gap-2 z-20 p-2" - > -
+ + { + e.preventDefault(); + handleSubmitQuestion(); + }} + > +
+ +
+ {generatingAnswer ? ( + + ) : ( + + )}
- {generatingAnswer ? ( - - ) : ( - - )} - -
+
+ ); }; diff --git a/frontend/app/chat/[chatId]/components/ChatDialogueArea/components/ChatDialogue/components/QADisplay/components/MessageRow/MessageRow.module.scss b/frontend/app/chat/[chatId]/components/ChatDialogueArea/components/ChatDialogue/components/QADisplay/components/MessageRow/MessageRow.module.scss index ad6387561de1..3aeff147cb29 100644 --- a/frontend/app/chat/[chatId]/components/ChatDialogueArea/components/ChatDialogue/components/QADisplay/components/MessageRow/MessageRow.module.scss +++ b/frontend/app/chat/[chatId]/components/ChatDialogueArea/components/ChatDialogue/components/QADisplay/components/MessageRow/MessageRow.module.scss @@ -1,4 +1,5 @@ @use "@/styles/Colors.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/Spacings.module.scss"; .message_row_container { @@ -10,7 +11,7 @@ .message_row_content { align-self: flex-end; - border-radius: 12px; + border-radius: Radius.$big; width: fit-content; padding-block: Spacings.$spacing03; padding-inline: Spacings.$spacing05; diff --git a/frontend/app/chat/[chatId]/components/DataPanel/DataPanel.tsx b/frontend/app/chat/[chatId]/components/DataPanel/DataPanel.tsx index 46b9e738ed63..dbbb0ce20f7a 100644 --- a/frontend/app/chat/[chatId]/components/DataPanel/DataPanel.tsx +++ b/frontend/app/chat/[chatId]/components/DataPanel/DataPanel.tsx @@ -29,7 +29,6 @@ const DataPanel = (): JSX.Element => { const updatedSources: Source[] = []; newSources.forEach((newSource) => { - console.info(newSource.source_url.length); const existingSourceIndex = updatedSources.findIndex( (source) => source.name.trim() === newSource.name.trim() ); diff --git a/frontend/app/chat/[chatId]/components/DataPanel/components/RelatedBrains/RelatedBrains.tsx b/frontend/app/chat/[chatId]/components/DataPanel/components/RelatedBrains/RelatedBrains.tsx index 214eef1a768e..f5e3c875bc7c 100644 --- a/frontend/app/chat/[chatId]/components/DataPanel/components/RelatedBrains/RelatedBrains.tsx +++ b/frontend/app/chat/[chatId]/components/DataPanel/components/RelatedBrains/RelatedBrains.tsx @@ -60,7 +60,8 @@ const RelatedBrains = ({ closeBrains }: RelatedBrainsProps): JSX.Element => {
{closeBrains?.map((brain, index) => ( diff --git a/frontend/app/search/page.module.scss b/frontend/app/search/page.module.scss index f315552ea1c7..7d8819c993d8 100644 --- a/frontend/app/search/page.module.scss +++ b/frontend/app/search/page.module.scss @@ -1,5 +1,6 @@ @use "@/styles/Colors.module.scss"; @use "@/styles/IconSizes.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/ScreenSizes.module.scss"; @use "@/styles/Spacings.module.scss"; @use "@/styles/Typography.module.scss"; @@ -12,6 +13,7 @@ display: flex; justify-content: center; align-items: center; + flex-direction: column; .main_container { display: flex; @@ -24,7 +26,7 @@ @media (max-width: ScreenSizes.$small) { width: 100%; - margin-inline: Spacings.$spacing07; + padding-inline: Spacings.$spacing07; } .quivr_logo_wrapper { @@ -43,10 +45,20 @@ } } - .add_brain_wrapper { - position: absolute; - bottom: Spacings.$spacing05; - left: 50%; - transform: translateX(-50%); + .shortcuts_card_wrapper { + background-color: Colors.$lightest-grey; + padding: Spacings.$spacing05; + gap: Spacings.$spacing03; + border-radius: Radius.$big; + + .shortcut_wrapper { + display: flex; + align-items: center; + gap: Spacings.$spacing03; + + .shortcut { + color: Colors.$primary; + } + } } } diff --git a/frontend/app/search/page.tsx b/frontend/app/search/page.tsx index 382ce66f45d6..58ac71d64169 100644 --- a/frontend/app/search/page.tsx +++ b/frontend/app/search/page.tsx @@ -33,6 +33,16 @@ const Search = (): JSX.Element => {
+
+
+ @ + Select a brain +
+
+ # + Select a prompt +
+
); }; diff --git a/frontend/lib/components/CurrentBrain/CurrentBrain.module.scss b/frontend/lib/components/CurrentBrain/CurrentBrain.module.scss new file mode 100644 index 000000000000..1d7e58e0ecf0 --- /dev/null +++ b/frontend/lib/components/CurrentBrain/CurrentBrain.module.scss @@ -0,0 +1,33 @@ +@use "@/styles/Colors.module.scss"; +@use "@/styles/Spacings.module.scss"; +@use "@/styles/Typography.module.scss"; + +.current_brain_wrapper { + background-color: Colors.$lightest-grey; + padding-inline: Spacings.$spacing05; + padding-block: Spacings.$spacing01; + font-size: Typography.$small; + color: Colors.$normal-grey; + + .brain_infos { + display: flex; + justify-content: space-between; + align-items: center; + + .left { + display: flex; + gap: Spacings.$spacing02; + align-items: center; + + .brain_name_wrapper { + display: flex; + gap: Spacings.$spacing02; + align-items: center; + + .brain_name { + color: Colors.$black; + } + } + } + } +} diff --git a/frontend/lib/components/CurrentBrain/CurrentBrain.tsx b/frontend/lib/components/CurrentBrain/CurrentBrain.tsx new file mode 100644 index 000000000000..33f7f43ff18f --- /dev/null +++ b/frontend/lib/components/CurrentBrain/CurrentBrain.tsx @@ -0,0 +1,39 @@ +import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; + +import styles from "./CurrentBrain.module.scss"; + +import { Icon } from "../ui/Icon/Icon"; + +export const CurrentBrain = (): JSX.Element => { + const { currentBrain, setCurrentBrainId } = useBrainContext(); + + const removeCurrentBrain = (): void => { + setCurrentBrainId(null); + }; + + if (!currentBrain) { + return <>; + } + + return ( +
+
+
+ Talking to +
+ + {currentBrain.name} +
+
+
{ + event.nativeEvent.stopImmediatePropagation(); + removeCurrentBrain(); + }} + > + +
+
+
+ ); +}; diff --git a/frontend/lib/components/Menu/components/DiscussionButton/DiscussionButton.module.scss b/frontend/lib/components/Menu/components/DiscussionButton/DiscussionButton.module.scss index f13a8bb362f5..4023d73984e6 100644 --- a/frontend/lib/components/Menu/components/DiscussionButton/DiscussionButton.module.scss +++ b/frontend/lib/components/Menu/components/DiscussionButton/DiscussionButton.module.scss @@ -1,5 +1,6 @@ @use "@/styles/Colors.module.scss"; @use "@/styles/IconSizes.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/Spacings.module.scss"; .button_wrapper { @@ -8,7 +9,7 @@ justify-content: space-between; align-items: center; border: 1px solid Colors.$lighter-grey; - border-radius: 12px; + border-radius: Radius.$big; background-color: Colors.$white; cursor: pointer; color: Colors.$dark-grey; @@ -30,7 +31,7 @@ justify-content: center; font-size: 12px; border: 1px solid Colors.$lighter-grey; - border-radius: 3px; + border-radius: Radius.$small; width: 16px; height: 16px; } diff --git a/frontend/lib/components/Menu/components/HistoryButton/ChatsSection/ChatHistoryItem/ChatHistoryItem.module.scss b/frontend/lib/components/Menu/components/HistoryButton/ChatsSection/ChatHistoryItem/ChatHistoryItem.module.scss index cfc8e333a647..b655b16671b8 100644 --- a/frontend/lib/components/Menu/components/HistoryButton/ChatsSection/ChatHistoryItem/ChatHistoryItem.module.scss +++ b/frontend/lib/components/Menu/components/HistoryButton/ChatsSection/ChatHistoryItem/ChatHistoryItem.module.scss @@ -1,4 +1,5 @@ @use "@/styles/Colors.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/Spacings.module.scss"; @use "@/styles/Typography.module.scss"; @@ -20,7 +21,7 @@ padding: 0; font-size: Typography.$small; background-color: Colors.$lighter-grey; - border-radius: 2px; + border-radius: Radius.$small; &:focus { box-shadow: none; diff --git a/frontend/lib/components/Menu/components/MenuButton/MenuButton.module.scss b/frontend/lib/components/Menu/components/MenuButton/MenuButton.module.scss index 9fbb65f29e2f..2d806831b757 100644 --- a/frontend/lib/components/Menu/components/MenuButton/MenuButton.module.scss +++ b/frontend/lib/components/Menu/components/MenuButton/MenuButton.module.scss @@ -1,4 +1,5 @@ @use "@/styles/Colors.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/Spacings.module.scss"; @use "@/styles/Typography.module.scss"; @@ -8,13 +9,13 @@ align-items: center; cursor: pointer; padding: Spacings.$spacing03; - border-radius: 5px; + border-radius: Radius.$normal; overflow: hidden; border-left: 2px solid transparent; &.selected { border-left: 2px solid Colors.$primary; - border-radius: 0 5px 5px 0; + border-radius: 0 Radius.$normal Radius.$normal 0; } .left { diff --git a/frontend/lib/components/SearchModal/SearchModal.tsx b/frontend/lib/components/SearchModal/SearchModal.tsx index 9a70456f7a86..290df748ddb8 100644 --- a/frontend/lib/components/SearchModal/SearchModal.tsx +++ b/frontend/lib/components/SearchModal/SearchModal.tsx @@ -39,12 +39,12 @@ export const SearchModal = (): JSX.Element => { }; useEffect(() => { - window.addEventListener("keydown", keydownHandler); - window.addEventListener("click", clickHandler); + document.addEventListener("keydown", keydownHandler); + document.addEventListener("click", clickHandler); return () => { - window.removeEventListener("keydown", keydownHandler); - window.removeEventListener("click", clickHandler); + document.removeEventListener("keydown", keydownHandler); + document.removeEventListener("click", clickHandler); }; }, []); diff --git a/frontend/lib/components/ui/FoldableSection/FoldableSection.module.scss b/frontend/lib/components/ui/FoldableSection/FoldableSection.module.scss index fa431f1fd09c..4badc5fc5a47 100644 --- a/frontend/lib/components/ui/FoldableSection/FoldableSection.module.scss +++ b/frontend/lib/components/ui/FoldableSection/FoldableSection.module.scss @@ -1,11 +1,12 @@ @use "@/styles/Colors.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/Spacings.module.scss"; @use "@/styles/Typography.module.scss"; .foldable_section_wrapper { display: flex; flex-direction: column; - border-radius: 5px; + border-radius: Radius.$normal; border: 1px dashed Colors.$lighter-grey; overflow: hidden; font-size: Typography.$small; diff --git a/frontend/lib/components/ui/SearchBar/SearchBar.module.scss b/frontend/lib/components/ui/SearchBar/SearchBar.module.scss index bd5a96069f81..f0c4f521d81b 100644 --- a/frontend/lib/components/ui/SearchBar/SearchBar.module.scss +++ b/frontend/lib/components/ui/SearchBar/SearchBar.module.scss @@ -1,27 +1,38 @@ @use "@/styles/Colors.module.scss"; @use "@/styles/IconSizes.module.scss"; +@use "@/styles/Radius.module.scss"; @use "@/styles/Spacings.module.scss"; .search_bar_wrapper { display: flex; - justify-content: space-between; - align-items: center; + flex-direction: column; gap: Spacings.$spacing03; background-color: Colors.$white; - padding: Spacings.$spacing05; - border-radius: 12px; + border-radius: Radius.$big; border: 1px solid Colors.$lighter-grey; + overflow: hidden; - .search_icon { - width: IconSizes.$big; - height: IconSizes.$big; - color: Colors.$accent; - cursor: pointer; + .editor_wrapper { + display: flex; + align-items: center; + justify-content: space-between; + padding: Spacings.$spacing05; - &.disabled { - color: Colors.$black; - pointer-events: none; - opacity: 0.2; + &.with_brain { + padding-top: 0; + } + + .search_icon { + width: IconSizes.$big; + height: IconSizes.$big; + color: Colors.$accent; + cursor: pointer; + + &.disabled { + color: Colors.$black; + pointer-events: none; + opacity: 0.2; + } } } } diff --git a/frontend/lib/components/ui/SearchBar/SearchBar.tsx b/frontend/lib/components/ui/SearchBar/SearchBar.tsx index 259562a909f1..957790b9a739 100644 --- a/frontend/lib/components/ui/SearchBar/SearchBar.tsx +++ b/frontend/lib/components/ui/SearchBar/SearchBar.tsx @@ -9,6 +9,7 @@ import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainConte import styles from "./SearchBar.module.scss"; +import { CurrentBrain } from "../../CurrentBrain/CurrentBrain"; import { LoaderIcon } from "../LoaderIcon/LoaderIcon"; export const SearchBar = ({ @@ -21,11 +22,11 @@ export const SearchBar = ({ const { message, setMessage } = useChatInput(); const { setMessages } = useChatContext(); const { addQuestion } = useChat(); - const { setCurrentBrainId } = useBrainContext(); + const { currentBrain, setCurrentBrainId } = useBrainContext(); useEffect(() => { setCurrentBrainId(null); - }, [setCurrentBrainId]); + }, []); useEffect(() => { setIsDisabled(message === ""); @@ -48,26 +49,38 @@ export const SearchBar = ({ } }; - /* eslint-disable @typescript-eslint/restrict-template-expressions */ return ( -
- void submit()} - placeholder="Search" - > - {searching ? ( - - ) : ( - + +
+ void submit()} + placeholder="Search" + > + {searching ? ( + + ) : ( + void submit()} - /> - )} + onClick={() => void submit()} + /> + )} +
); }; diff --git a/frontend/lib/helpers/iconList.ts b/frontend/lib/helpers/iconList.ts index 863f58f984a5..5e9e70c45d37 100644 --- a/frontend/lib/helpers/iconList.ts +++ b/frontend/lib/helpers/iconList.ts @@ -7,7 +7,7 @@ import { FaRegUserCircle, } from "react-icons/fa"; import { FaArrowUpFromBracket } from "react-icons/fa6"; -import { IoIosAdd } from "react-icons/io"; +import { IoIosAdd, IoMdClose } from "react-icons/io"; import { IoHomeOutline } from "react-icons/io5"; import { IconType } from "react-icons/lib"; import { @@ -32,6 +32,7 @@ export const iconList: { [name: string]: IconType } = { checkCircle: FaCheckCircle, chevronDown: LuChevronDown, chevronRight: LuChevronRight, + close: IoMdClose, copy: LuCopy, delete: MdDelete, edit: MdEdit, diff --git a/frontend/styles/_Radius.module.scss b/frontend/styles/_Radius.module.scss new file mode 100644 index 000000000000..5155967abaad --- /dev/null +++ b/frontend/styles/_Radius.module.scss @@ -0,0 +1,3 @@ +$big: 12px; +$normal: 5px; +$small: 2px;