mirror of
https://github.com/StanGirard/quivr.git
synced 2024-12-25 04:12:44 +03:00
feat: restructure the sidebar of the brains management page (#1325)
* 🧩 Possibility to chose which buttons to display in the sidebar * Button "Back to chat" * 💄 Remove the frame around the brains library page * Give a size to the image in the profile button (for performance) * Optional prop showButtons in the sidebar * remove duration on waitFor and set sidebar animation duration to 200ms
This commit is contained in:
parent
85eba3da70
commit
f030db6952
@ -14,48 +14,49 @@ export const BrainsList = (): JSX.Element => {
|
||||
const { searchQuery, setSearchQuery, brains, isOnBrainsLibraryPage } =
|
||||
useBrainsList();
|
||||
|
||||
const { t } = useTranslation("brain");
|
||||
const { t } = useTranslation(["brain", "chat"]);
|
||||
|
||||
return (
|
||||
<Sidebar showFooter={false}>
|
||||
<div className="flex flex-col flex-1">
|
||||
<Sidebar showButtons={["user"]}>
|
||||
<div className="flex flex-col p-2 gap-2">
|
||||
<Link href="/chat">
|
||||
<Button type="button" className="bg-primary text-white py-2 w-full">
|
||||
{t("chat:back_to_chat")}
|
||||
</Button>
|
||||
</Link>
|
||||
<AddBrainModal triggerClassName="border-solid border-2 border-gray-300" />
|
||||
</div>
|
||||
<div className="px-2 pt-2 pb-4">
|
||||
<BrainSearchBar
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
/>
|
||||
<div
|
||||
data-testid="brains-list-items"
|
||||
className="flex-1 overflow-auto scrollbar h-full"
|
||||
>
|
||||
{brains.map((brain) => (
|
||||
<BrainListItem brain={brain} key={brain.id} />
|
||||
))}
|
||||
</div>
|
||||
<div className="m-2 mb flex flex-col">
|
||||
{isOnBrainsLibraryPage ? (
|
||||
<Link href="/brains-management" className="flex flex-row flex-1">
|
||||
<Button
|
||||
type="button"
|
||||
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
|
||||
>
|
||||
{t("brain_management_button_label")}
|
||||
</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Link
|
||||
href="/brains-management/library"
|
||||
className="flex flex-row flex-1"
|
||||
</div>
|
||||
<div
|
||||
data-testid="brains-list-items"
|
||||
className="flex-1 overflow-auto scrollbar h-full min-h-[50px]"
|
||||
>
|
||||
{brains.map((brain) => (
|
||||
<BrainListItem brain={brain} key={brain.id} />
|
||||
))}
|
||||
</div>
|
||||
<div className="p-2 mb flex flex-col">
|
||||
{isOnBrainsLibraryPage ? (
|
||||
<Link href="/brains-management" className="flex flex-row flex-1">
|
||||
<Button
|
||||
type="button"
|
||||
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
|
||||
>
|
||||
{t("brain_library_button_label")}
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<AddBrainModal triggerClassName="border-solid border-2 border-gray-300" />
|
||||
</div>
|
||||
{t("brain:brain_management_button_label")}
|
||||
</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Link href="/brains-management/library">
|
||||
<Button type="button" className="bg-primary text-white py-2 w-full">
|
||||
{t("brain_library_button_label")}
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Sidebar>
|
||||
);
|
||||
|
@ -14,15 +14,13 @@ export const BrainSearchBar = ({
|
||||
const { t } = useTranslation(["brain"]);
|
||||
|
||||
return (
|
||||
<div className="m-2">
|
||||
<Field
|
||||
name="brainsearch"
|
||||
placeholder={t("searchBrain")}
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Field
|
||||
name="brainsearch"
|
||||
placeholder={t("searchBrain")}
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -13,7 +13,7 @@ const BrainsLibrary = (): JSX.Element => {
|
||||
const { t } = useTranslation("brain");
|
||||
|
||||
return (
|
||||
<div className="flex flex-1 flex-col items-center m-5 md:m-20 border-2 border-gray-100 border-solid rounded-xl">
|
||||
<div className="flex flex-1 flex-col items-center">
|
||||
<div className="flex">
|
||||
<Field
|
||||
value={searchBarText}
|
||||
|
@ -12,7 +12,7 @@ export const ChatsList = (): JSX.Element => {
|
||||
useChatNotificationsSync();
|
||||
|
||||
return (
|
||||
<Sidebar showFooter={true}>
|
||||
<Sidebar showButtons={["myBrains", "user"]}>
|
||||
<div className="flex flex-col flex-1 h-full" data-testid="chats-list">
|
||||
<div className="pt-2">
|
||||
<NewChatButton />
|
||||
|
@ -7,16 +7,19 @@ import { SidebarHeader } from "@/lib/components/Sidebar/components/SidebarHeader
|
||||
import { useDevice } from "@/lib/hooks/useDevice";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { SidebarFooter } from "./components/SidebarFooter/SidebarFooter";
|
||||
import {
|
||||
SidebarFooter,
|
||||
SidebarFooterButtons,
|
||||
} from "./components/SidebarFooter/SidebarFooter";
|
||||
|
||||
type SidebarProps = {
|
||||
children: React.ReactNode;
|
||||
showFooter: boolean;
|
||||
showButtons?: SidebarFooterButtons[];
|
||||
};
|
||||
|
||||
export const Sidebar = ({
|
||||
children,
|
||||
showFooter,
|
||||
showButtons,
|
||||
}: SidebarProps): JSX.Element => {
|
||||
const { isMobile } = useDevice();
|
||||
const pathname = usePathname();
|
||||
@ -27,7 +30,7 @@ export const Sidebar = ({
|
||||
}, [isMobile, pathname]);
|
||||
|
||||
return (
|
||||
<MotionConfig transition={{ mass: 1, damping: 10 }}>
|
||||
<MotionConfig transition={{ mass: 1, damping: 10, duration: 0.2 }}>
|
||||
<motion.div
|
||||
drag="x"
|
||||
dragConstraints={{ right: 0, left: 0 }}
|
||||
@ -68,7 +71,7 @@ export const Sidebar = ({
|
||||
>
|
||||
<SidebarHeader setOpen={setOpen} />
|
||||
<div className="overflow-auto flex flex-col flex-1">{children}</div>
|
||||
{showFooter && <SidebarFooter />}
|
||||
{showButtons && <SidebarFooter showButtons={showButtons} />}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</MotionConfig>
|
||||
|
@ -16,7 +16,7 @@ vi.mock("@/lib/hooks/useDevice");
|
||||
const renderSidebar = async () => {
|
||||
await act(() =>
|
||||
render(
|
||||
<Sidebar showFooter={false}>
|
||||
<Sidebar>
|
||||
<div data-testid="sidebar-test-content">📦</div>
|
||||
</Sidebar>
|
||||
)
|
||||
@ -73,7 +73,6 @@ describe("Sidebar", () => {
|
||||
expect(closeSidebarButton);
|
||||
|
||||
fireEvent.click(closeSidebarButton);
|
||||
|
||||
await waitFor(() => expect(sidebarContent).not.toBeVisible());
|
||||
});
|
||||
});
|
||||
|
@ -2,12 +2,18 @@ import { BrainManagementButton } from "@/lib/components/Sidebar/components/Sideb
|
||||
|
||||
import { UserButton } from "./components/UserButton";
|
||||
|
||||
export const SidebarFooter = (): JSX.Element => {
|
||||
export type SidebarFooterButtons = "myBrains" | "user";
|
||||
|
||||
type SidebarFooterProps = {
|
||||
showButtons: SidebarFooterButtons[];
|
||||
};
|
||||
|
||||
export const SidebarFooter = ({showButtons}: SidebarFooterProps): JSX.Element => {
|
||||
return (
|
||||
<div className="bg-gray-50 dark:bg-gray-900 border-t dark:border-white/10 mt-auto p-2">
|
||||
<div className="max-w-screen-xl flex justify-center items-center flex-col">
|
||||
<BrainManagementButton />
|
||||
<UserButton />
|
||||
{showButtons.includes('myBrains') && <BrainManagementButton />}
|
||||
{showButtons.includes('user') && <UserButton />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -16,6 +16,7 @@ export const UserButton = (): JSX.Element => {
|
||||
<Image
|
||||
alt="gravatar"
|
||||
fill={true}
|
||||
sizes="32px"
|
||||
src={gravatarUrl}
|
||||
className="rounded-xl"
|
||||
/>
|
||||
|
@ -34,15 +34,16 @@
|
||||
"feed_brain_placeholder": "Choose which @brain you want to feed with these files",
|
||||
"feedingBrain": "Your newly added knowledge is being processed, you can keep chatting in the meantime !",
|
||||
"add_content_card_button_tooltip": "Add knowledge to a brain",
|
||||
"back_to_chat": "Back to chat",
|
||||
"onboarding": {
|
||||
"download_message_1": "Hi 👋🏻 Want to discover Quivr ? 😇",
|
||||
"download_message_2": "Step 1: Download “Quivr documentation”",
|
||||
"upload_message_1":"Congratulations on your first step 🥳",
|
||||
"upload_message_2":"Step 2: Now Drag and drop it on the chat or in the 📎",
|
||||
"upload_message_1": "Congratulations on your first step 🥳",
|
||||
"upload_message_2": "Step 2: Now Drag and drop it on the chat or in the 📎",
|
||||
"how_to_use_quivr": "How to user Quivr",
|
||||
"what_is_quivr":"What is Quivr ?",
|
||||
"what_is_quivr": "What is Quivr ?",
|
||||
"what_is_brain": "What is a brain ?",
|
||||
"last_step":"Last step 🥳",
|
||||
"ask_question_to_file":"Ask a question to your file. Ex : 'What are you talking about ?'"
|
||||
"last_step": "Last step 🥳",
|
||||
"ask_question_to_file": "Ask a question to your file. Ex : 'What are you talking about ?'"
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,8 @@
|
||||
"feed_brain_placeholder": "Elige cuál @cerebro quieres alimentar con estos archivos",
|
||||
"feedingBrain": "Su conocimiento recién agregado se está procesando, ¡puede seguir chateando mientras tanto!",
|
||||
"add_content_card_button_tooltip": "Agregar conocimiento a un cerebro",
|
||||
"onboarding":{
|
||||
"back_to_chat": "Volver al chat",
|
||||
"onboarding": {
|
||||
"download_message_1": "Hola 👋🏻 ¿Quieres descubrir Quivr? 😇",
|
||||
"download_message_2": "Paso 1: Descargar la documentación de “Quivr”",
|
||||
"upload_message_1": "¡Felicidades por tu primer paso 🥳!",
|
||||
|
@ -34,7 +34,8 @@
|
||||
"feed_brain_placeholder": "Choisissez le @cerveau que vous souhaitez nourrir avec ces fichiers",
|
||||
"feedingBrain": "Vos nouvelles connaissances sont en cours de traitement. Vous pouvez continuer à discuter en attendant !",
|
||||
"add_content_card_button_tooltip": "Ajouter des connaissances à un cerveau",
|
||||
"onboarding":{
|
||||
"back_to_chat": "Retour au chat",
|
||||
"onboarding": {
|
||||
"download_message_1": "Salut 👋🏻 Envie de découvrir Quivr ? 😇",
|
||||
"download_message_2": "Étape 1 : Téléchargez la documentation de “Quivr”",
|
||||
"upload_message_1": "Félicitations pour votre première étape 🥳!",
|
||||
|
@ -34,7 +34,8 @@
|
||||
"feed_brain_placeholder": "Escolha qual @cérebro você deseja alimentar com esses arquivos",
|
||||
"feedingBrain": "Seu conhecimento recém-adicionado está sendo processado, você pode continuar conversando enquanto isso!",
|
||||
"add_content_card_button_tooltip": "Adicionar conhecimento a um cérebro",
|
||||
"onboarding":{
|
||||
"back_to_chat": "Voltar para o chat",
|
||||
"onboarding": {
|
||||
"download_message_1": "Oi 👋🏻 Quer descobrir o Quivr? 😇",
|
||||
"download_message_2": "Passo 1: Baixe a documentação do 'Quivr'",
|
||||
"upload_message_1": "Parabéns pelo seu primeiro passo 🥳!",
|
||||
|
@ -34,7 +34,8 @@
|
||||
"feed_brain_placeholder": "Выберите, какой @мозг вы хотите питать этими файлами",
|
||||
"feedingBrain": "Ваш недавно добавленный знаний обрабатывается, вы можете продолжить общение в это время!",
|
||||
"add_content_card_button_tooltip": "Добавить знаний в мозг",
|
||||
"onboarding":{
|
||||
"back_to_chat": "Вернуться к чату",
|
||||
"onboarding": {
|
||||
"download_message_1": "Привет 👋🏻 Хочешь узнать о Quivr? 😇",
|
||||
"download_message_2": "Шаг 1: Скачайте документацию Quivr",
|
||||
"upload_message_1": "Поздравляем с первым шагом 🥳!",
|
||||
|
@ -35,7 +35,8 @@
|
||||
"feed_brain_placeholder": "选择要用这些文件喂养的 @大脑",
|
||||
"feedingBrain": "您新添加的知识正在处理中,同时您可以继续聊天!",
|
||||
"add_content_card_button_tooltip": "向大脑添加知识",
|
||||
"onboarding":{
|
||||
"back_to_chat": "返回聊天",
|
||||
"onboarding": {
|
||||
"download_message_1": "你好 👋🏻 想要发现 Quivr 吗? 😇",
|
||||
"download_message_2": "步骤 1:下载“Quivr 文档”",
|
||||
"upload_message_1": "恭喜您迈出第一步 🥳!",
|
||||
|
Loading…
Reference in New Issue
Block a user