import React, { useState, useEffect, useMemo } from 'react'; import { Share2Icon, Users, Loader, Shield, Link, CopyCheck } from 'lucide-react'; import { Permissions, ResourceType, PermissionTypes, AccessRoleIds } from 'librechat-data-provider'; import { useGetResourcePermissionsQuery, useUpdateResourcePermissionsMutation, } from 'librechat-data-provider/react-query'; import { Button, OGDialog, OGDialogTitle, OGDialogClose, OGDialogContent, OGDialogTrigger, useToastContext, } from '@librechat/client'; import type { TPrincipal } from 'librechat-data-provider'; import { useLocalize, useCopyToClipboard, useHasAccess } from '~/hooks'; import ManagePermissionsDialog from './ManagePermissionsDialog'; import PublicSharingToggle from './PublicSharingToggle'; import AccessRolesPicker from './AccessRolesPicker'; import { cn, removeFocusOutlines } from '~/utils'; import { PeoplePicker } from './PeoplePicker'; export default function GrantAccessDialog({ agentName, onGrantAccess, resourceType = ResourceType.AGENT, agentDbId, agentId, }: { agentDbId?: string | null; agentId?: string | null; agentName?: string; onGrantAccess?: (shares: TPrincipal[], isPublic: boolean, publicRole: AccessRoleIds) => void; resourceType?: ResourceType; }) { const localize = useLocalize(); const { showToast } = useToastContext(); // Check if user has permission to access people picker const canViewUsers = useHasAccess({ permissionType: PermissionTypes.PEOPLE_PICKER, permission: Permissions.VIEW_USERS, }); const canViewGroups = useHasAccess({ permissionType: PermissionTypes.PEOPLE_PICKER, permission: Permissions.VIEW_GROUPS, }); const hasPeoplePickerAccess = canViewUsers || canViewGroups; /** Type filter based on permissions */ const peoplePickerTypeFilter = useMemo(() => { if (canViewUsers && canViewGroups) { return null; // Both types allowed } else if (canViewUsers) { return 'user' as const; } else if (canViewGroups) { return 'group' as const; } return null; }, [canViewUsers, canViewGroups]); const { data: permissionsData, // isLoading: isLoadingPermissions, // error: permissionsError, } = useGetResourcePermissionsQuery(resourceType, agentDbId!, { enabled: !!agentDbId, }); const updatePermissionsMutation = useUpdateResourcePermissionsMutation(); const [newShares, setNewShares] = useState([]); const [defaultPermissionId, setDefaultPermissionId] = useState( AccessRoleIds.AGENT_VIEWER, ); const [isModalOpen, setIsModalOpen] = useState(false); const [isCopying, setIsCopying] = useState(false); const agentUrl = `${window.location.origin}/c/new?agent_id=${agentId}`; const copyAgentUrl = useCopyToClipboard({ text: agentUrl }); const currentShares: TPrincipal[] = permissionsData?.principals?.map((principal) => ({ type: principal.type, id: principal.id, name: principal.name, email: principal.email, source: principal.source, avatar: principal.avatar, description: principal.description, accessRoleId: principal.accessRoleId, })) || []; const currentIsPublic = permissionsData?.public ?? false; const currentPublicRole = permissionsData?.publicAccessRoleId || AccessRoleIds.AGENT_VIEWER; const [isPublic, setIsPublic] = useState(false); const [publicRole, setPublicRole] = useState(AccessRoleIds.AGENT_VIEWER); useEffect(() => { if (permissionsData && isModalOpen) { setIsPublic(currentIsPublic ?? false); setPublicRole(currentPublicRole); } }, [permissionsData, isModalOpen, currentIsPublic, currentPublicRole]); if (!agentDbId) { return null; } const handleGrantAccess = async () => { try { const sharesToAdd = newShares.map((share) => ({ ...share, accessRoleId: defaultPermissionId, })); const allShares = [...currentShares, ...sharesToAdd]; await updatePermissionsMutation.mutateAsync({ resourceType, resourceId: agentDbId, data: { updated: sharesToAdd, removed: [], public: isPublic, publicAccessRoleId: isPublic ? publicRole : undefined, }, }); if (onGrantAccess) { onGrantAccess(allShares, isPublic, publicRole); } showToast({ message: `Access granted successfully to ${newShares.length} ${newShares.length === 1 ? 'person' : 'people'}${isPublic ? ' and made public' : ''}`, status: 'success', }); setNewShares([]); setDefaultPermissionId(AccessRoleIds.AGENT_VIEWER); setIsPublic(false); setPublicRole(AccessRoleIds.AGENT_VIEWER); setIsModalOpen(false); } catch (error) { console.error('Error granting access:', error); showToast({ message: 'Failed to grant access. Please try again.', status: 'error', }); } }; const handleCancel = () => { setNewShares([]); setDefaultPermissionId(AccessRoleIds.AGENT_VIEWER); setIsPublic(false); setPublicRole(AccessRoleIds.AGENT_VIEWER); setIsModalOpen(false); }; const totalCurrentShares = currentShares.length + (currentIsPublic ? 1 : 0); const submitButtonActive = newShares.length > 0 || isPublic !== currentIsPublic || publicRole !== currentPublicRole; return (
{localize('com_ui_share_var', { 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'), })}
{hasPeoplePickerAccess && ( <>
)}
{hasPeoplePickerAccess && ( )} {agentId && ( )}
); }