mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-07-17 16:43:37 +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:
@ -0,0 +1,38 @@
|
|||||||
|
"""server default chosen assistants
|
||||||
|
|
||||||
|
Revision ID: 35e6853a51d5
|
||||||
|
Revises: c99d76fcd298
|
||||||
|
Create Date: 2024-09-13 13:20:32.885317
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "35e6853a51d5"
|
||||||
|
down_revision = "c99d76fcd298"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
DEFAULT_ASSISTANTS = [-2, -1, 0]
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.alter_column(
|
||||||
|
"user",
|
||||||
|
"chosen_assistants",
|
||||||
|
type_=postgresql.JSONB(astext_type=sa.Text()),
|
||||||
|
nullable=False,
|
||||||
|
server_default=sa.text(f"'{DEFAULT_ASSISTANTS}'::jsonb"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.alter_column(
|
||||||
|
"user",
|
||||||
|
"chosen_assistants",
|
||||||
|
type_=postgresql.JSONB(astext_type=sa.Text()),
|
||||||
|
nullable=True,
|
||||||
|
server_default=None,
|
||||||
|
)
|
@ -122,7 +122,7 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
|
|||||||
# if specified, controls the assistants that are shown to the user + their order
|
# if specified, controls the assistants that are shown to the user + their order
|
||||||
# if not specified, all assistants are shown
|
# if not specified, all assistants are shown
|
||||||
chosen_assistants: Mapped[list[int]] = mapped_column(
|
chosen_assistants: Mapped[list[int]] = mapped_column(
|
||||||
postgresql.JSONB(), nullable=True
|
postgresql.JSONB(), nullable=False, default=[-2, -1, 0]
|
||||||
)
|
)
|
||||||
|
|
||||||
oidc_expiry: Mapped[datetime.datetime] = mapped_column(
|
oidc_expiry: Mapped[datetime.datetime] = mapped_column(
|
||||||
|
@ -210,6 +210,22 @@ def update_persona_shared_users(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def update_persona_public_status(
|
||||||
|
persona_id: int,
|
||||||
|
is_public: bool,
|
||||||
|
db_session: Session,
|
||||||
|
user: User | None,
|
||||||
|
) -> None:
|
||||||
|
persona = fetch_persona_by_id(
|
||||||
|
db_session=db_session, persona_id=persona_id, user=user, get_editable=True
|
||||||
|
)
|
||||||
|
if user and user.role != UserRole.ADMIN and persona.user_id != user.id:
|
||||||
|
raise ValueError("You don't have permission to modify this persona")
|
||||||
|
|
||||||
|
persona.is_public = is_public
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
|
||||||
def get_prompts(
|
def get_prompts(
|
||||||
user_id: UUID | None,
|
user_id: UUID | None,
|
||||||
db_session: Session,
|
db_session: Session,
|
||||||
@ -551,6 +567,7 @@ def update_persona_visibility(
|
|||||||
persona = fetch_persona_by_id(
|
persona = fetch_persona_by_id(
|
||||||
db_session=db_session, persona_id=persona_id, user=user, get_editable=True
|
db_session=db_session, persona_id=persona_id, user=user, get_editable=True
|
||||||
)
|
)
|
||||||
|
|
||||||
persona.is_visible = is_visible
|
persona.is_visible = is_visible
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ from uuid import UUID
|
|||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
|
from fastapi import HTTPException
|
||||||
from fastapi import Query
|
from fastapi import Query
|
||||||
from fastapi import UploadFile
|
from fastapi import UploadFile
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@ -20,6 +21,7 @@ from danswer.db.persona import get_personas
|
|||||||
from danswer.db.persona import mark_persona_as_deleted
|
from danswer.db.persona import mark_persona_as_deleted
|
||||||
from danswer.db.persona import mark_persona_as_not_deleted
|
from danswer.db.persona import mark_persona_as_not_deleted
|
||||||
from danswer.db.persona import update_all_personas_display_priority
|
from danswer.db.persona import update_all_personas_display_priority
|
||||||
|
from danswer.db.persona import update_persona_public_status
|
||||||
from danswer.db.persona import update_persona_shared_users
|
from danswer.db.persona import update_persona_shared_users
|
||||||
from danswer.db.persona import update_persona_visibility
|
from danswer.db.persona import update_persona_visibility
|
||||||
from danswer.file_store.file_store import get_default_file_store
|
from danswer.file_store.file_store import get_default_file_store
|
||||||
@ -43,6 +45,10 @@ class IsVisibleRequest(BaseModel):
|
|||||||
is_visible: bool
|
is_visible: bool
|
||||||
|
|
||||||
|
|
||||||
|
class IsPublicRequest(BaseModel):
|
||||||
|
is_public: bool
|
||||||
|
|
||||||
|
|
||||||
@admin_router.patch("/{persona_id}/visible")
|
@admin_router.patch("/{persona_id}/visible")
|
||||||
def patch_persona_visibility(
|
def patch_persona_visibility(
|
||||||
persona_id: int,
|
persona_id: int,
|
||||||
@ -58,6 +64,25 @@ def patch_persona_visibility(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@basic_router.patch("/{persona_id}/public")
|
||||||
|
def patch_user_presona_public_status(
|
||||||
|
persona_id: int,
|
||||||
|
is_public_request: IsPublicRequest,
|
||||||
|
user: User | None = Depends(current_user),
|
||||||
|
db_session: Session = Depends(get_session),
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
update_persona_public_status(
|
||||||
|
persona_id=persona_id,
|
||||||
|
is_public=is_public_request.is_public,
|
||||||
|
db_session=db_session,
|
||||||
|
user=user,
|
||||||
|
)
|
||||||
|
except ValueError as e:
|
||||||
|
logger.exception("Failed to update persona public status")
|
||||||
|
raise HTTPException(status_code=403, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
@admin_router.put("/display-priority")
|
@admin_router.put("/display-priority")
|
||||||
def patch_persona_display_priority(
|
def patch_persona_display_priority(
|
||||||
display_priority_request: DisplayPriorityRequest,
|
display_priority_request: DisplayPriorityRequest,
|
||||||
|
@ -12,6 +12,7 @@ command=python danswer/background/update.py
|
|||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
autorestart=true
|
autorestart=true
|
||||||
|
|
||||||
|
|
||||||
# Background jobs that must be run async due to long time to completion
|
# Background jobs that must be run async due to long time to completion
|
||||||
# NOTE: due to an issue with Celery + SQLAlchemy
|
# NOTE: due to an issue with Celery + SQLAlchemy
|
||||||
# (https://github.com/celery/celery/issues/7007#issuecomment-1740139367)
|
# (https://github.com/celery/celery/issues/7007#issuecomment-1740139367)
|
||||||
@ -37,11 +38,9 @@ autorestart=true
|
|||||||
# Job scheduler for periodic tasks
|
# Job scheduler for periodic tasks
|
||||||
[program:celery_beat]
|
[program:celery_beat]
|
||||||
command=celery -A danswer.background.celery.celery_run:celery_app beat
|
command=celery -A danswer.background.celery.celery_run:celery_app beat
|
||||||
--loglevel=INFO
|
|
||||||
--logfile=/var/log/celery_beat_supervisor.log
|
--logfile=/var/log/celery_beat_supervisor.log
|
||||||
environment=LOG_FILE_NAME=celery_beat
|
environment=LOG_FILE_NAME=celery_beat
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
autorestart=true
|
|
||||||
|
|
||||||
# Listens for Slack messages and responds with answers
|
# Listens for Slack messages and responds with answers
|
||||||
# for all channels that the DanswerBot has been added to.
|
# for all channels that the DanswerBot has been added to.
|
||||||
|
@ -8,7 +8,11 @@ import { usePopup } from "@/components/admin/connectors/Popup";
|
|||||||
import { useState, useMemo, useEffect } from "react";
|
import { useState, useMemo, useEffect } from "react";
|
||||||
import { UniqueIdentifier } from "@dnd-kit/core";
|
import { UniqueIdentifier } from "@dnd-kit/core";
|
||||||
import { DraggableTable } from "@/components/table/DraggableTable";
|
import { DraggableTable } from "@/components/table/DraggableTable";
|
||||||
import { deletePersona, personaComparator } from "./lib";
|
import {
|
||||||
|
deletePersona,
|
||||||
|
personaComparator,
|
||||||
|
togglePersonaVisibility,
|
||||||
|
} from "./lib";
|
||||||
import { FiEdit2 } from "react-icons/fi";
|
import { FiEdit2 } from "react-icons/fi";
|
||||||
import { TrashIcon } from "@/components/icons/icons";
|
import { TrashIcon } from "@/components/icons/icons";
|
||||||
import { getCurrentUser } from "@/lib/user";
|
import { getCurrentUser } from "@/lib/user";
|
||||||
@ -31,22 +35,6 @@ function PersonaTypeDisplay({ persona }: { persona: Persona }) {
|
|||||||
return <Text>Personal {persona.owner && <>({persona.owner.email})</>}</Text>;
|
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({
|
export function PersonasTable({
|
||||||
allPersonas,
|
allPersonas,
|
||||||
editablePersonas,
|
editablePersonas,
|
||||||
|
@ -320,6 +320,38 @@ export function personaComparator(a: Persona, b: Persona) {
|
|||||||
return closerToZeroNegativesFirstComparator(a.id, b.id);
|
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) {
|
export function checkPersonaRequiresImageGeneration(persona: Persona) {
|
||||||
for (const tool of persona.tools) {
|
for (const tool of persona.tools) {
|
||||||
if (tool.name === "ImageGenerationTool") {
|
if (tool.name === "ImageGenerationTool") {
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
import { User } from "@/lib/types";
|
import { User } from "@/lib/types";
|
||||||
import { Persona } from "../admin/assistants/interfaces";
|
import { Persona } from "../admin/assistants/interfaces";
|
||||||
import { checkUserOwnsAssistant } from "@/lib/assistants/checkOwnership";
|
import { checkUserOwnsAssistant } from "@/lib/assistants/checkOwnership";
|
||||||
import {
|
import { FiLock, FiUnlock } from "react-icons/fi";
|
||||||
FiImage,
|
|
||||||
FiLock,
|
|
||||||
FiMoreHorizontal,
|
|
||||||
FiSearch,
|
|
||||||
FiUnlock,
|
|
||||||
} from "react-icons/fi";
|
|
||||||
import { CustomTooltip } from "@/components/tooltip/CustomTooltip";
|
|
||||||
|
|
||||||
export function AssistantSharedStatusDisplay({
|
export function AssistantSharedStatusDisplay({
|
||||||
assistant,
|
assistant,
|
||||||
@ -56,20 +49,6 @@ export function AssistantSharedStatusDisplay({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,15 @@ import { Persona } from "@/app/admin/assistants/interfaces";
|
|||||||
import { Divider, Text } from "@tremor/react";
|
import { Divider, Text } from "@tremor/react";
|
||||||
import {
|
import {
|
||||||
FiEdit2,
|
FiEdit2,
|
||||||
|
FiFigma,
|
||||||
FiMenu,
|
FiMenu,
|
||||||
|
FiMinus,
|
||||||
FiMoreHorizontal,
|
FiMoreHorizontal,
|
||||||
FiPlus,
|
FiPlus,
|
||||||
FiSearch,
|
FiSearch,
|
||||||
|
FiShare,
|
||||||
FiShare2,
|
FiShare2,
|
||||||
|
FiToggleLeft,
|
||||||
FiTrash,
|
FiTrash,
|
||||||
FiX,
|
FiX,
|
||||||
} from "react-icons/fi";
|
} from "react-icons/fi";
|
||||||
@ -50,11 +54,14 @@ import {
|
|||||||
verticalListSortingStrategy,
|
verticalListSortingStrategy,
|
||||||
} from "@dnd-kit/sortable";
|
} from "@dnd-kit/sortable";
|
||||||
import { useSortable } from "@dnd-kit/sortable";
|
import { useSortable } from "@dnd-kit/sortable";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
|
||||||
|
|
||||||
import { DragHandle } from "@/components/table/DragHandle";
|
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 { DeleteEntityModal } from "@/components/modals/DeleteEntityModal";
|
||||||
|
import { MakePublicAssistantModal } from "@/app/chat/modal/MakePublicAssistantModal";
|
||||||
|
|
||||||
function DraggableAssistantListItem(props: any) {
|
function DraggableAssistantListItem(props: any) {
|
||||||
const {
|
const {
|
||||||
@ -81,7 +88,7 @@ function DraggableAssistantListItem(props: any) {
|
|||||||
<DragHandle />
|
<DragHandle />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow">
|
<div className="flex-grow">
|
||||||
<AssistantListItem del {...props} />
|
<AssistantListItem {...props} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -95,6 +102,7 @@ function AssistantListItem({
|
|||||||
isVisible,
|
isVisible,
|
||||||
setPopup,
|
setPopup,
|
||||||
deleteAssistant,
|
deleteAssistant,
|
||||||
|
shareAssistant,
|
||||||
}: {
|
}: {
|
||||||
assistant: Persona;
|
assistant: Persona;
|
||||||
user: User | null;
|
user: User | null;
|
||||||
@ -102,7 +110,7 @@ function AssistantListItem({
|
|||||||
allAssistantIds: string[];
|
allAssistantIds: string[];
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
deleteAssistant: Dispatch<SetStateAction<Persona | null>>;
|
deleteAssistant: Dispatch<SetStateAction<Persona | null>>;
|
||||||
|
shareAssistant: Dispatch<SetStateAction<Persona | null>>;
|
||||||
setPopup: (popupSpec: PopupSpec | null) => void;
|
setPopup: (popupSpec: PopupSpec | null) => void;
|
||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
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>
|
</DefaultPopover>
|
||||||
</div>
|
</div>
|
||||||
@ -290,6 +310,9 @@ export function AssistantsList({
|
|||||||
assistant.id.toString()
|
assistant.id.toString()
|
||||||
);
|
);
|
||||||
const [deletingPersona, setDeletingPersona] = useState<Persona | null>(null);
|
const [deletingPersona, setDeletingPersona] = useState<Persona | null>(null);
|
||||||
|
const [makePublicPersona, setMakePublicPersona] = useState<Persona | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const { popup, setPopup } = usePopup();
|
const { popup, setPopup } = usePopup();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -307,7 +330,7 @@ export function AssistantsList({
|
|||||||
|
|
||||||
async function handleDragEnd(event: DragEndEvent) {
|
async function handleDragEnd(event: DragEndEvent) {
|
||||||
const { active, over } = event;
|
const { active, over } = event;
|
||||||
|
filteredAssistants;
|
||||||
if (over && active.id !== over.id) {
|
if (over && active.id !== over.id) {
|
||||||
setFilteredAssistants((assistants) => {
|
setFilteredAssistants((assistants) => {
|
||||||
const oldIndex = assistants.findIndex(
|
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">
|
<div className="mx-auto mobile:w-[90%] desktop:w-searchbar-xs 2xl:w-searchbar-sm 3xl:w-searchbar">
|
||||||
<AssistantsPageTitle>My Assistants</AssistantsPageTitle>
|
<AssistantsPageTitle>My Assistants</AssistantsPageTitle>
|
||||||
|
|
||||||
@ -403,6 +440,7 @@ export function AssistantsList({
|
|||||||
{filteredAssistants.map((assistant, index) => (
|
{filteredAssistants.map((assistant, index) => (
|
||||||
<DraggableAssistantListItem
|
<DraggableAssistantListItem
|
||||||
deleteAssistant={setDeletingPersona}
|
deleteAssistant={setDeletingPersona}
|
||||||
|
shareAssistant={setMakePublicPersona}
|
||||||
key={assistant.id}
|
key={assistant.id}
|
||||||
assistant={assistant}
|
assistant={assistant}
|
||||||
user={user}
|
user={user}
|
||||||
@ -431,6 +469,7 @@ export function AssistantsList({
|
|||||||
{ownedButHiddenAssistants.map((assistant, index) => (
|
{ownedButHiddenAssistants.map((assistant, index) => (
|
||||||
<AssistantListItem
|
<AssistantListItem
|
||||||
deleteAssistant={setDeletingPersona}
|
deleteAssistant={setDeletingPersona}
|
||||||
|
shareAssistant={setMakePublicPersona}
|
||||||
key={assistant.id}
|
key={assistant.id}
|
||||||
assistant={assistant}
|
assistant={assistant}
|
||||||
user={user}
|
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