mirror of
https://github.com/QuivrHQ/quivr.git
synced 2024-12-15 09:32:22 +03:00
Shareable Brains - 2 (#601)
* feat(brains): add fetching indicator * feat: add brain share modal
This commit is contained in:
parent
22ea64e67c
commit
8749ffd0bd
@ -1,17 +1,17 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FaBrain } from "react-icons/fa";
|
import { FaBrain } from "react-icons/fa";
|
||||||
import { MdCheck, MdDelete } from "react-icons/md";
|
import { MdCheck } from "react-icons/md";
|
||||||
|
|
||||||
import Button from "@/lib/components/ui/Button";
|
|
||||||
import Field from "@/lib/components/ui/Field";
|
import Field from "@/lib/components/ui/Field";
|
||||||
import Popover from "@/lib/components/ui/Popover";
|
import Popover from "@/lib/components/ui/Popover";
|
||||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
|
|
||||||
import { AddBrainModal } from "./AddBrainModal";
|
import { AddBrainModal } from "./components/AddBrainModal";
|
||||||
|
import { BrainActions } from "./components/BrainActions/BrainActions";
|
||||||
|
|
||||||
export const BrainsDropDown = (): JSX.Element => {
|
export const BrainsDropDown = (): JSX.Element => {
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const { allBrains, setActiveBrain, currentBrain, deleteBrain } =
|
const { allBrains, isFetchingBrains, setActiveBrain, currentBrain } =
|
||||||
useBrainContext();
|
useBrainContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -41,6 +41,11 @@ export const BrainsDropDown = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
<div className="overflow-auto scrollbar flex flex-col h-48 mt-5">
|
<div className="overflow-auto scrollbar flex flex-col h-48 mt-5">
|
||||||
{/* List of brains */}
|
{/* List of brains */}
|
||||||
|
{isFetchingBrains && (
|
||||||
|
<div className="flex items-center justify-center h-full">
|
||||||
|
<p className="text-gray-500">Loading...</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{allBrains.map((brain) => {
|
{allBrains.map((brain) => {
|
||||||
if (brain.name.includes(searchQuery)) {
|
if (brain.name.includes(searchQuery)) {
|
||||||
return (
|
return (
|
||||||
@ -68,13 +73,7 @@ export const BrainsDropDown = (): JSX.Element => {
|
|||||||
</span>
|
</span>
|
||||||
<span className="flex-1">{brain.name}</span>
|
<span className="flex-1">{brain.name}</span>
|
||||||
</button>
|
</button>
|
||||||
<Button
|
<BrainActions brainId={brain.id} />
|
||||||
className="group-hover:visible invisible absolute right-0 hover:text-red-500 transition-[colors,opacity]"
|
|
||||||
onClick={() => void deleteBrain(brain.id)}
|
|
||||||
variant={"tertiary"}
|
|
||||||
>
|
|
||||||
<MdDelete className="text-xl" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import Field from "@/lib/components/ui/Field";
|
|||||||
import Modal from "@/lib/components/ui/Modal";
|
import Modal from "@/lib/components/ui/Modal";
|
||||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
|
|
||||||
const AddBrainModal = (): JSX.Element => {
|
export const AddBrainModal = (): JSX.Element => {
|
||||||
const [newBrainName, setNewBrainName] = useState("");
|
const [newBrainName, setNewBrainName] = useState("");
|
||||||
const [isPending, setIsPending] = useState(false);
|
const [isPending, setIsPending] = useState(false);
|
||||||
|
|
||||||
@ -56,5 +56,3 @@ const AddBrainModal = (): JSX.Element => {
|
|||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { AddBrainModal };
|
|
@ -0,0 +1,28 @@
|
|||||||
|
import { UUID } from "crypto";
|
||||||
|
import { MdDelete } from "react-icons/md";
|
||||||
|
|
||||||
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
|
|
||||||
|
import { ShareBrain } from "./ShareBrain";
|
||||||
|
|
||||||
|
type BrainActionsProps = {
|
||||||
|
brainId: UUID;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BrainActions = ({ brainId }: BrainActionsProps): JSX.Element => {
|
||||||
|
const { deleteBrain } = useBrainContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute right-0 flex flex-row">
|
||||||
|
<ShareBrain brainId={brainId} />
|
||||||
|
<Button
|
||||||
|
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
|
||||||
|
onClick={() => void deleteBrain(brainId)}
|
||||||
|
variant={"tertiary"}
|
||||||
|
>
|
||||||
|
<MdDelete className="text-xl" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,47 @@
|
|||||||
|
import { UUID } from "crypto";
|
||||||
|
import { MdContentPaste, MdShare } from "react-icons/md";
|
||||||
|
|
||||||
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
import Modal from "@/lib/components/ui/Modal";
|
||||||
|
import { useToast } from "@/lib/hooks";
|
||||||
|
|
||||||
|
type ShareBrainModalProps = {
|
||||||
|
brainId: UUID;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ShareBrain = ({ brainId }: ShareBrainModalProps): JSX.Element => {
|
||||||
|
const { publish } = useToast();
|
||||||
|
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
|
const brainShareLink = `${baseUrl}/brain_subscription_invitation=${brainId}`;
|
||||||
|
|
||||||
|
const handleCopyInvitationLink = async () => {
|
||||||
|
await navigator.clipboard.writeText(brainShareLink);
|
||||||
|
publish({
|
||||||
|
variant: "success",
|
||||||
|
text: "Copied to clipboard",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
Trigger={
|
||||||
|
<Button
|
||||||
|
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
|
||||||
|
onClick={() => void 0}
|
||||||
|
variant={"tertiary"}
|
||||||
|
>
|
||||||
|
<MdShare className="text-xl" />
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
title="Share brain"
|
||||||
|
>
|
||||||
|
<div className="flex flex-row align-center my-5">
|
||||||
|
<p>{brainShareLink}</p>
|
||||||
|
<Button onClick={() => void handleCopyInvitationLink()}>
|
||||||
|
<MdContentPaste />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from "./BrainActions";
|
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./AddBrainModal";
|
||||||
|
export * from "./BrainActions";
|
@ -1,4 +1 @@
|
|||||||
import { AddBrainModal } from "./AddBrainModal";
|
export * from "./BrainsDropDown";
|
||||||
import { BrainsDropDown } from "./BrainsDropDown";
|
|
||||||
|
|
||||||
export { BrainsDropDown, AddBrainModal };
|
|
||||||
|
@ -12,6 +12,7 @@ interface ModalProps {
|
|||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
Trigger: ReactNode;
|
Trigger: ReactNode;
|
||||||
CloseTrigger?: ReactNode;
|
CloseTrigger?: ReactNode;
|
||||||
|
opened?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Modal = ({
|
const Modal = ({
|
||||||
@ -20,8 +21,9 @@ const Modal = ({
|
|||||||
children,
|
children,
|
||||||
Trigger,
|
Trigger,
|
||||||
CloseTrigger,
|
CloseTrigger,
|
||||||
|
opened = false,
|
||||||
}: ModalProps): JSX.Element => {
|
}: ModalProps): JSX.Element => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(opened);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.Root onOpenChange={setOpen}>
|
<Dialog.Root onOpenChange={setOpen}>
|
||||||
|
@ -103,6 +103,5 @@ export const useBrainProvider = () => {
|
|||||||
setDefaultBrain,
|
setDefaultBrain,
|
||||||
fetchAndSetActiveBrain,
|
fetchAndSetActiveBrain,
|
||||||
isFetchingBrains,
|
isFetchingBrains,
|
||||||
setIsFetchingBrains,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user