mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-09-22 17:16:20 +02:00
Allow users to share assistants (#2434)
* enable assistant sharing * functional * remove logs * revert ports * remove accidental update * minor updates to copy * update formatting * update for merge queue
This commit is contained in:
@@ -8,7 +8,11 @@ import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { useState, useMemo, useEffect } from "react";
|
||||
import { UniqueIdentifier } from "@dnd-kit/core";
|
||||
import { DraggableTable } from "@/components/table/DraggableTable";
|
||||
import { deletePersona, personaComparator } from "./lib";
|
||||
import {
|
||||
deletePersona,
|
||||
personaComparator,
|
||||
togglePersonaVisibility,
|
||||
} from "./lib";
|
||||
import { FiEdit2 } from "react-icons/fi";
|
||||
import { TrashIcon } from "@/components/icons/icons";
|
||||
import { getCurrentUser } from "@/lib/user";
|
||||
@@ -31,22 +35,6 @@ function PersonaTypeDisplay({ persona }: { persona: Persona }) {
|
||||
return <Text>Personal {persona.owner && <>({persona.owner.email})</>}</Text>;
|
||||
}
|
||||
|
||||
const togglePersonaVisibility = async (
|
||||
personaId: number,
|
||||
isVisible: boolean
|
||||
) => {
|
||||
const response = await fetch(`/api/admin/persona/${personaId}/visible`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is_visible: !isVisible,
|
||||
}),
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
export function PersonasTable({
|
||||
allPersonas,
|
||||
editablePersonas,
|
||||
|
@@ -320,6 +320,38 @@ export function personaComparator(a: Persona, b: Persona) {
|
||||
return closerToZeroNegativesFirstComparator(a.id, b.id);
|
||||
}
|
||||
|
||||
export const togglePersonaVisibility = async (
|
||||
personaId: number,
|
||||
isVisible: boolean
|
||||
) => {
|
||||
const response = await fetch(`/api/persona/${personaId}/visible`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is_visible: !isVisible,
|
||||
}),
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
export const togglePersonaPublicStatus = async (
|
||||
personaId: number,
|
||||
isPublic: boolean
|
||||
) => {
|
||||
const response = await fetch(`/api/persona/${personaId}/public`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is_public: isPublic,
|
||||
}),
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
export function checkPersonaRequiresImageGeneration(persona: Persona) {
|
||||
for (const tool of persona.tools) {
|
||||
if (tool.name === "ImageGenerationTool") {
|
||||
|
@@ -1,14 +1,7 @@
|
||||
import { User } from "@/lib/types";
|
||||
import { Persona } from "../admin/assistants/interfaces";
|
||||
import { checkUserOwnsAssistant } from "@/lib/assistants/checkOwnership";
|
||||
import {
|
||||
FiImage,
|
||||
FiLock,
|
||||
FiMoreHorizontal,
|
||||
FiSearch,
|
||||
FiUnlock,
|
||||
} from "react-icons/fi";
|
||||
import { CustomTooltip } from "@/components/tooltip/CustomTooltip";
|
||||
import { FiLock, FiUnlock } from "react-icons/fi";
|
||||
|
||||
export function AssistantSharedStatusDisplay({
|
||||
assistant,
|
||||
@@ -56,20 +49,6 @@ export function AssistantSharedStatusDisplay({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="relative mt-4 text-xs flex text-subtle">
|
||||
<span className="font-medium">Powers:</span>{" "}
|
||||
{assistant.tools.length == 0 ? (
|
||||
<p className="ml-2">None</p>
|
||||
) : (
|
||||
assistant.tools.map((tool, ind) => {
|
||||
if (tool.name === "SearchTool") {
|
||||
return <FiSearch key={ind} className="ml-1 h-3 w-3 my-auto" />;
|
||||
} else if (tool.name === "ImageGenerationTool") {
|
||||
return <FiImage key={ind} className="ml-1 h-3 w-3 my-auto" />;
|
||||
}
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -6,11 +6,15 @@ import { Persona } from "@/app/admin/assistants/interfaces";
|
||||
import { Divider, Text } from "@tremor/react";
|
||||
import {
|
||||
FiEdit2,
|
||||
FiFigma,
|
||||
FiMenu,
|
||||
FiMinus,
|
||||
FiMoreHorizontal,
|
||||
FiPlus,
|
||||
FiSearch,
|
||||
FiShare,
|
||||
FiShare2,
|
||||
FiToggleLeft,
|
||||
FiTrash,
|
||||
FiX,
|
||||
} from "react-icons/fi";
|
||||
@@ -50,11 +54,14 @@ import {
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable";
|
||||
import { useSortable } from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
|
||||
import { DragHandle } from "@/components/table/DragHandle";
|
||||
import { deletePersona } from "@/app/admin/assistants/lib";
|
||||
import {
|
||||
deletePersona,
|
||||
togglePersonaPublicStatus,
|
||||
} from "@/app/admin/assistants/lib";
|
||||
import { DeleteEntityModal } from "@/components/modals/DeleteEntityModal";
|
||||
import { MakePublicAssistantModal } from "@/app/chat/modal/MakePublicAssistantModal";
|
||||
|
||||
function DraggableAssistantListItem(props: any) {
|
||||
const {
|
||||
@@ -81,7 +88,7 @@ function DraggableAssistantListItem(props: any) {
|
||||
<DragHandle />
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<AssistantListItem del {...props} />
|
||||
<AssistantListItem {...props} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -95,6 +102,7 @@ function AssistantListItem({
|
||||
isVisible,
|
||||
setPopup,
|
||||
deleteAssistant,
|
||||
shareAssistant,
|
||||
}: {
|
||||
assistant: Persona;
|
||||
user: User | null;
|
||||
@@ -102,7 +110,7 @@ function AssistantListItem({
|
||||
allAssistantIds: string[];
|
||||
isVisible: boolean;
|
||||
deleteAssistant: Dispatch<SetStateAction<Persona | null>>;
|
||||
|
||||
shareAssistant: Dispatch<SetStateAction<Persona | null>>;
|
||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
@@ -258,6 +266,18 @@ function AssistantListItem({
|
||||
) : (
|
||||
<></>
|
||||
),
|
||||
isOwnedByUser ? (
|
||||
<div
|
||||
key="delete"
|
||||
className="flex items-center gap-x-2"
|
||||
onClick={() => shareAssistant(assistant)}
|
||||
>
|
||||
{assistant.is_public ? <FiMinus /> : <FiPlus />} Make{" "}
|
||||
{assistant.is_public ? "Private" : "Public"}
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
),
|
||||
]}
|
||||
</DefaultPopover>
|
||||
</div>
|
||||
@@ -290,6 +310,9 @@ export function AssistantsList({
|
||||
assistant.id.toString()
|
||||
);
|
||||
const [deletingPersona, setDeletingPersona] = useState<Persona | null>(null);
|
||||
const [makePublicPersona, setMakePublicPersona] = useState<Persona | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const { popup, setPopup } = usePopup();
|
||||
const router = useRouter();
|
||||
@@ -307,7 +330,7 @@ export function AssistantsList({
|
||||
|
||||
async function handleDragEnd(event: DragEndEvent) {
|
||||
const { active, over } = event;
|
||||
|
||||
filteredAssistants;
|
||||
if (over && active.id !== over.id) {
|
||||
setFilteredAssistants((assistants) => {
|
||||
const oldIndex = assistants.findIndex(
|
||||
@@ -351,6 +374,20 @@ export function AssistantsList({
|
||||
/>
|
||||
)}
|
||||
|
||||
{makePublicPersona && (
|
||||
<MakePublicAssistantModal
|
||||
isPublic={makePublicPersona.is_public}
|
||||
onClose={() => setMakePublicPersona(null)}
|
||||
onShare={async (newPublicStatus: boolean) => {
|
||||
await togglePersonaPublicStatus(
|
||||
makePublicPersona.id,
|
||||
newPublicStatus
|
||||
);
|
||||
router.refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="mx-auto mobile:w-[90%] desktop:w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar">
|
||||
<AssistantsPageTitle>My Assistants</AssistantsPageTitle>
|
||||
|
||||
@@ -403,6 +440,7 @@ export function AssistantsList({
|
||||
{filteredAssistants.map((assistant, index) => (
|
||||
<DraggableAssistantListItem
|
||||
deleteAssistant={setDeletingPersona}
|
||||
shareAssistant={setMakePublicPersona}
|
||||
key={assistant.id}
|
||||
assistant={assistant}
|
||||
user={user}
|
||||
@@ -431,6 +469,7 @@ export function AssistantsList({
|
||||
{ownedButHiddenAssistants.map((assistant, index) => (
|
||||
<AssistantListItem
|
||||
deleteAssistant={setDeletingPersona}
|
||||
shareAssistant={setMakePublicPersona}
|
||||
key={assistant.id}
|
||||
assistant={assistant}
|
||||
user={user}
|
||||
|
72
web/src/app/chat/modal/MakePublicAssistantModal.tsx
Normal file
72
web/src/app/chat/modal/MakePublicAssistantModal.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { ModalWrapper } from "@/components/modals/ModalWrapper";
|
||||
import { Button, Divider, Text } from "@tremor/react";
|
||||
|
||||
export function MakePublicAssistantModal({
|
||||
isPublic,
|
||||
onShare,
|
||||
onClose,
|
||||
}: {
|
||||
isPublic: boolean;
|
||||
onShare: (shared: boolean) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
return (
|
||||
<ModalWrapper onClose={onClose} modalClassName="max-w-3xl">
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-bold text-emphasis">
|
||||
{isPublic ? "Public Assistant" : "Make Assistant Public"}
|
||||
</h2>
|
||||
|
||||
<Text>
|
||||
This assistant is currently{" "}
|
||||
<span className="font-semibold">
|
||||
{isPublic ? "public" : "private"}
|
||||
</span>
|
||||
.
|
||||
{isPublic
|
||||
? " Anyone can currently access this assistant."
|
||||
: " Only you can access this assistant."}
|
||||
</Text>
|
||||
|
||||
<Divider />
|
||||
|
||||
{isPublic ? (
|
||||
<div className="space-y-4">
|
||||
<Text>
|
||||
To restrict access to this assistant, you can make it private
|
||||
again.
|
||||
</Text>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await onShare?.(false);
|
||||
onClose();
|
||||
}}
|
||||
size="sm"
|
||||
color="red"
|
||||
>
|
||||
Make Assistant Private
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<Text>
|
||||
Making this assistant public will allow anyone with the link to
|
||||
view and use it. Ensure that all content and capabilities of the
|
||||
assistant are safe to share.
|
||||
</Text>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await onShare?.(true);
|
||||
onClose();
|
||||
}}
|
||||
size="sm"
|
||||
color="green"
|
||||
>
|
||||
Make Assistant Public
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user