+ {/* Search Bar with Default Permission Setting */}
+ {hasPeoplePickerAccess && (
+
- {hasPeoplePickerAccess && (
-
- )}
{resourceId && resourceUrl && (
diff --git a/client/src/components/Sharing/GenericManagePermissionsDialog.tsx b/client/src/components/Sharing/GenericManagePermissionsDialog.tsx
deleted file mode 100644
index 5d9b26c17b..0000000000
--- a/client/src/components/Sharing/GenericManagePermissionsDialog.tsx
+++ /dev/null
@@ -1,339 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { useGetAccessRolesQuery } from 'librechat-data-provider/react-query';
-import { Settings, Users, Loader, UserCheck, Trash2, Shield } from 'lucide-react';
-import {
- Button,
- OGDialog,
- OGDialogTitle,
- OGDialogClose,
- OGDialogContent,
- OGDialogTrigger,
- useToastContext,
-} from '@librechat/client';
-import type { TPrincipal, ResourceType, AccessRoleIds } from 'librechat-data-provider';
-import { useResourcePermissionState } from '~/hooks/Sharing';
-import PublicSharingToggle from './PublicSharingToggle';
-import { SelectedPrincipalsList } from './PeoplePicker';
-import { useLocalize } from '~/hooks';
-
-export default function GenericManagePermissionsDialog({
- resourceDbId,
- resourceName,
- resourceType,
- onUpdatePermissions,
- children,
-}: {
- resourceDbId: string;
- resourceName?: string;
- resourceType: ResourceType;
- onUpdatePermissions?: (
- shares: TPrincipal[],
- isPublic: boolean,
- publicRole: AccessRoleIds,
- ) => void;
- children?: React.ReactNode;
-}) {
- const localize = useLocalize();
- const { showToast } = useToastContext();
- const [isModalOpen, setIsModalOpen] = useState(false);
- const [hasChanges, setHasChanges] = useState(false);
-
- const {
- config,
- permissionsData,
- isLoadingPermissions,
- permissionsError,
- updatePermissionsMutation,
- currentShares,
- currentIsPublic,
- currentPublicRole,
- isPublic: managedIsPublic,
- setIsPublic: setManagedIsPublic,
- publicRole: managedPublicRole,
- setPublicRole: setManagedPublicRole,
- } = useResourcePermissionState(resourceType, resourceDbId, isModalOpen);
-
- const { data: accessRoles } = useGetAccessRolesQuery(resourceType);
-
- const [managedShares, setManagedShares] = useState
([]);
-
- useEffect(() => {
- if (permissionsData && isModalOpen) {
- const shares = permissionsData.principals || [];
- setManagedShares(shares);
- setHasChanges(false);
- }
- }, [permissionsData, isModalOpen]);
-
- if (!resourceDbId) {
- return null;
- }
-
- if (!config) {
- console.error(`Unsupported resource type: ${resourceType}`);
- return null;
- }
-
- if (permissionsError) {
- return {localize('com_ui_permissions_failed_load')}
;
- }
-
- const handleRemoveShare = (idOnTheSource: string) => {
- setManagedShares(managedShares.filter((s) => s.idOnTheSource !== idOnTheSource));
- setHasChanges(true);
- };
-
- const handleRoleChange = (idOnTheSource: string, newRole: string) => {
- setManagedShares(
- managedShares.map((s) =>
- s.idOnTheSource === idOnTheSource ? { ...s, accessRoleId: newRole } : s,
- ),
- );
- setHasChanges(true);
- };
-
- const handleSaveChanges = async () => {
- try {
- const originalSharesMap = new Map(
- currentShares.map((share) => [`${share.type}-${share.idOnTheSource}`, share]),
- );
- const managedSharesMap = new Map(
- managedShares.map((share) => [`${share.type}-${share.idOnTheSource}`, share]),
- );
-
- const updated = managedShares.filter((share) => {
- const key = `${share.type}-${share.idOnTheSource}`;
- const original = originalSharesMap.get(key);
- return !original || original.accessRoleId !== share.accessRoleId;
- });
-
- const removed = currentShares.filter((share) => {
- const key = `${share.type}-${share.idOnTheSource}`;
- return !managedSharesMap.has(key);
- });
-
- await updatePermissionsMutation.mutateAsync({
- resourceType,
- resourceId: resourceDbId,
- data: {
- updated,
- removed,
- public: managedIsPublic,
- publicAccessRoleId: managedIsPublic ? managedPublicRole : undefined,
- },
- });
-
- if (onUpdatePermissions) {
- onUpdatePermissions(managedShares, managedIsPublic, managedPublicRole);
- }
-
- showToast({
- message: localize('com_ui_permissions_updated_success'),
- status: 'success',
- });
-
- setIsModalOpen(false);
- } catch (error) {
- console.error('Error updating permissions:', error);
- showToast({
- message: localize('com_ui_permissions_failed_update'),
- status: 'error',
- });
- }
- };
-
- const handleCancel = () => {
- setManagedShares(currentShares);
- setManagedIsPublic(currentIsPublic);
- setManagedPublicRole(currentPublicRole || config?.defaultViewerRoleId || '');
- setIsModalOpen(false);
- };
-
- const handleRevokeAll = () => {
- setManagedShares([]);
- setManagedIsPublic(false);
- setHasChanges(true);
- };
- const handlePublicToggle = (isPublic: boolean) => {
- setManagedIsPublic(isPublic);
- setHasChanges(true);
- if (!isPublic) {
- setManagedPublicRole(config?.defaultViewerRoleId);
- }
- };
- const handlePublicRoleChange = (role: string) => {
- setManagedPublicRole(role);
- setHasChanges(true);
- };
- const totalShares = managedShares.length + (managedIsPublic ? 1 : 0);
- const originalTotalShares = currentShares.length + (currentIsPublic ? 1 : 0);
-
- /** Check if there's at least one owner (user, group, or public with owner role) */
- const hasAtLeastOneOwner =
- managedShares.some((share) => share.accessRoleId === config?.defaultOwnerRoleId) ||
- (managedIsPublic && managedPublicRole === config?.defaultOwnerRoleId);
-
- let peopleLabel = localize('com_ui_people');
- if (managedShares.length === 1) {
- peopleLabel = localize('com_ui_person');
- }
-
- const buttonAriaLabel = config?.getManageMessage(resourceName);
- const dialogTitle = config?.getManageMessage(resourceName);
-
- let publicSuffix = '';
- if (managedIsPublic) {
- publicSuffix = localize('com_ui_and_public');
- }
-
- const TriggerComponent = children ? (
- children
- ) : (
-
-
- {localize('com_ui_manage')}
- {originalTotalShares > 0 && `( ${originalTotalShares} )`}
-
- );
-
- return (
-
- {TriggerComponent}
-
-
-
-
-
- {dialogTitle}
-
-
-
-
-
-
-
-
- {localize('com_ui_current_access')}
-
-
- {(() => {
- if (totalShares === 0) {
- return localize('com_ui_no_users_groups_access');
- }
- return localize('com_ui_shared_with_count', {
- 0: managedShares.length,
- 1: peopleLabel,
- 2: publicSuffix,
- });
- })()}
-
-
- {(managedShares.length > 0 || managedIsPublic) && (
-
-
- {localize('com_ui_revoke_all')}
-
- )}
-
-
-
- {(() => {
- if (isLoadingPermissions) {
- return (
-
-
-
- {localize('com_ui_loading_permissions')}
-
-
- );
- }
-
- if (managedShares.length > 0) {
- return (
-
-
-
- {localize('com_ui_user_group_permissions')} ({managedShares.length})
-
- handleRoleChange(id, newRole)}
- />
-
- );
- }
-
- return (
-
-
-
- {localize('com_ui_no_individual_access')}
-
-
- );
- })()}
-
-
-
- {localize('com_ui_public_access')}
-
-
-
-
-
-
-
- {localize('com_ui_cancel')}
-
-
-
- {updatePermissionsMutation.isLoading ? (
-
-
- {localize('com_ui_saving')}
-
- ) : (
- localize('com_ui_save_changes')
- )}
-
-
-
- {hasChanges && (
-
- * {localize('com_ui_unsaved_changes')}
-
- )}
-
- {!hasAtLeastOneOwner && hasChanges && (
-
- * {localize('com_ui_at_least_one_owner_required')}
-
- )}
-
-
-
- );
-}
diff --git a/client/src/components/Sharing/GrantAccessDialog.tsx b/client/src/components/Sharing/GrantAccessDialog.tsx
deleted file mode 100644
index beb69265e3..0000000000
--- a/client/src/components/Sharing/GrantAccessDialog.tsx
+++ /dev/null
@@ -1,295 +0,0 @@
-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 (
-
-
-
-
-
- {totalCurrentShares > 0 && (
-
- {totalCurrentShares}
-
- )}
-
-
-
-
-
-
-
-
- {localize('com_ui_share_var', {
- 0:
- agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
- })}
-
-
-
-
- {hasPeoplePickerAccess && (
- <>
-
-
-
-
-
-
-
-
-
-
-
- >
- )}
-
-
-
- {hasPeoplePickerAccess && (
-
- )}
- {agentId && (
- {
- if (isCopying) return;
- copyAgentUrl(setIsCopying);
- showToast({
- message: localize('com_ui_agent_url_copied'),
- status: 'success',
- });
- }}
- disabled={isCopying}
- className={cn('shrink-0', isCopying ? 'cursor-default' : '')}
- aria-label={localize('com_ui_copy_url_to_clipboard')}
- title={
- isCopying
- ? localize('com_ui_agent_url_copied')
- : localize('com_ui_copy_url_to_clipboard')
- }
- >
- {isCopying ? : }
-
- )}
-
-
-
-
- {localize('com_ui_cancel')}
-
-
-
- {updatePermissionsMutation.isLoading ? (
-
-
- {localize('com_ui_granting')}
-
- ) : (
- localize('com_ui_grant_access')
- )}
-
-
-
-
-
-
- );
-}
diff --git a/client/src/components/Sharing/ManagePermissionsDialog.tsx b/client/src/components/Sharing/ManagePermissionsDialog.tsx
index 490022b7de..7d5f88750a 100644
--- a/client/src/components/Sharing/ManagePermissionsDialog.tsx
+++ b/client/src/components/Sharing/ManagePermissionsDialog.tsx
@@ -1,14 +1,14 @@
import React, { useState, useEffect } from 'react';
import { AccessRoleIds, ResourceType } from 'librechat-data-provider';
-import { Settings, Users, Loader, UserCheck, Trash2, Shield } from 'lucide-react';
+import { Settings, Users, UserCheck, Trash2, Shield } from 'lucide-react';
import {
- useGetAccessRolesQuery,
useGetResourcePermissionsQuery,
useUpdateResourcePermissionsMutation,
} from 'librechat-data-provider/react-query';
import type { TPrincipal } from 'librechat-data-provider';
import {
Button,
+ Spinner,
OGDialog,
OGDialogTitle,
OGDialogClose,
@@ -46,10 +46,6 @@ export default function ManagePermissionsDialog({
} = useGetResourcePermissionsQuery(resourceType, agentDbId, {
enabled: !!agentDbId,
});
- const {
- data: accessRoles,
- // isLoading,
- } = useGetAccessRolesQuery(resourceType);
const updatePermissionsMutation = useUpdateResourcePermissionsMutation();
@@ -267,7 +263,7 @@ export default function ManagePermissionsDialog({
if (isLoadingPermissions) {
return (
-
+
{localize('com_ui_loading_permissions')}
@@ -285,7 +281,7 @@ export default function ManagePermissionsDialog({
handleRoleChange(id, newRole)}
/>
@@ -302,17 +298,12 @@ export default function ManagePermissionsDialog({
);
})()}
-
-
- {localize('com_ui_public_access')}
-
-
-
+
@@ -332,7 +323,7 @@ export default function ManagePermissionsDialog({
>
{updatePermissionsMutation.isLoading ? (
-
+
{localize('com_ui_saving')}
) : (
diff --git a/client/src/components/Sharing/PeoplePicker/SearchPicker.tsx b/client/src/components/Sharing/PeoplePicker/SearchPicker.tsx
index e4266f4c83..6bbc5613b3 100644
--- a/client/src/components/Sharing/PeoplePicker/SearchPicker.tsx
+++ b/client/src/components/Sharing/PeoplePicker/SearchPicker.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
+import { Search } from 'lucide-react';
import debounce from 'lodash/debounce';
-import { Search, X } from 'lucide-react';
import * as Ariakit from '@ariakit/react';
import { Spinner, Skeleton } from '@librechat/client';
import { useLocalize } from '~/hooks';
@@ -78,7 +78,7 @@ export function SearchPicker({
@@ -110,7 +110,7 @@ export function SearchPicker({
value={localQuery}
// autoSelect
placeholder={placeholder || localize('com_ui_select_options')}
- className="m-0 mr-0 w-full rounded-md border-none bg-transparent p-0 py-2 pl-9 pr-3 text-sm leading-tight text-text-primary placeholder-text-secondary placeholder-opacity-100 focus:outline-none focus-visible:outline-none group-focus-within:placeholder-text-primary group-hover:placeholder-text-primary"
+ className="h-10 w-full rounded-lg bg-transparent pl-10 text-sm leading-tight text-text-primary placeholder-text-secondary placeholder-opacity-100 focus:outline-none focus-visible:outline-none group-focus-within:placeholder-text-primary group-hover:placeholder-text-primary"
/>
diff --git a/client/src/components/Sharing/PeoplePicker/SelectedPrincipalsList.tsx b/client/src/components/Sharing/PeoplePicker/SelectedPrincipalsList.tsx
index 3ff26870ec..ae8fd11892 100644
--- a/client/src/components/Sharing/PeoplePicker/SelectedPrincipalsList.tsx
+++ b/client/src/components/Sharing/PeoplePicker/SelectedPrincipalsList.tsx
@@ -1,17 +1,17 @@
-import React, { useState, useId } from 'react';
-import * as Ariakit from '@ariakit/react/menu';
-import { Button, DropdownPopup } from '@librechat/client';
-import { Users, X, ExternalLink, ChevronDown } from 'lucide-react';
-import type { TPrincipal, TAccessRole, AccessRoleIds } from 'librechat-data-provider';
-import { getRoleLocalizationKeys } from '~/utils';
+import React from 'react';
+import { Button } from '@librechat/client';
+import { Users, X, ExternalLink } from 'lucide-react';
+import type { TPrincipal, AccessRoleIds } from 'librechat-data-provider';
+import { ResourceType } from 'librechat-data-provider';
import PrincipalAvatar from '../PrincipalAvatar';
+import AccessRolesPicker from '../AccessRolesPicker';
import { useLocalize } from '~/hooks';
interface SelectedPrincipalsListProps {
principles: TPrincipal[];
onRemoveHandler: (idOnTheSource: string) => void;
onRoleChange?: (idOnTheSource: string, newRoleId: AccessRoleIds) => void;
- availableRoles?: Omit[];
+ resourceType?: ResourceType;
className?: string;
}
@@ -20,7 +20,7 @@ export default function SelectedPrincipalsList({
onRemoveHandler,
className = '',
onRoleChange,
- availableRoles,
+ resourceType = ResourceType.AGENT,
}: SelectedPrincipalsListProps) {
const localize = useLocalize();
@@ -71,12 +71,13 @@ export default function SelectedPrincipalsList({
{!!share.accessRoleId && !!onRoleChange && (
-
{
onRoleChange?.(share.idOnTheSource!, newRole);
}}
- availableRoles={availableRoles ?? []}
+ className="min-w-0"
/>
)}
);
}
-
-interface RoleSelectorProps {
- currentRole: AccessRoleIds;
- onRoleChange: (newRole: AccessRoleIds) => void;
- availableRoles: Omit[];
-}
-
-function RoleSelector({ currentRole, onRoleChange, availableRoles }: RoleSelectorProps) {
- const menuId = useId();
- const [isMenuOpen, setIsMenuOpen] = useState(false);
- const localize = useLocalize();
-
- const getLocalizedRoleName = (roleId: AccessRoleIds) => {
- const keys = getRoleLocalizationKeys(roleId);
- return localize(keys.name);
- };
-
- return (
-
- {getLocalizedRoleName(currentRole)}
-
-
- }
- items={availableRoles?.map((role) => ({
- id: role.accessRoleId,
- label: getLocalizedRoleName(role.accessRoleId),
- onClick: () => onRoleChange(role.accessRoleId),
- }))}
- menuId={menuId}
- className="z-50 [pointer-events:auto]"
- />
- );
-}
diff --git a/client/src/components/Sharing/PeoplePicker/UnifiedPeopleSearch.tsx b/client/src/components/Sharing/PeoplePicker/UnifiedPeopleSearch.tsx
new file mode 100644
index 0000000000..74019216d8
--- /dev/null
+++ b/client/src/components/Sharing/PeoplePicker/UnifiedPeopleSearch.tsx
@@ -0,0 +1,83 @@
+import React, { useState, useMemo } from 'react';
+import type { TPrincipal, PrincipalSearchParams } from 'librechat-data-provider';
+import { useSearchPrincipalsQuery } from 'librechat-data-provider/react-query';
+import PeoplePickerSearchItem from './PeoplePickerSearchItem';
+import { SearchPicker } from './SearchPicker';
+import { useLocalize } from '~/hooks';
+
+interface UnifiedPeopleSearchProps {
+ onAddPeople: (principals: TPrincipal[]) => void;
+ placeholder?: string;
+ className?: string;
+ typeFilter?: 'user' | 'group' | null;
+ excludeIds?: string[];
+}
+
+export default function UnifiedPeopleSearch({
+ onAddPeople,
+ placeholder,
+ className = '',
+ typeFilter = null,
+ excludeIds = [],
+}: UnifiedPeopleSearchProps) {
+ const localize = useLocalize();
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const searchParams: PrincipalSearchParams = useMemo(
+ () => ({
+ q: searchQuery,
+ limit: 30,
+ ...(typeFilter && { type: typeFilter }),
+ }),
+ [searchQuery, typeFilter],
+ );
+
+ const {
+ data: searchResponse,
+ isLoading: queryIsLoading,
+ error,
+ } = useSearchPrincipalsQuery(searchParams, {
+ enabled: searchQuery.length >= 2,
+ });
+
+ const isLoading = searchQuery.length >= 2 && queryIsLoading;
+
+ const selectableResults = useMemo(() => {
+ const results = searchResponse?.results || [];
+
+ return results.filter(
+ (result) => result.idOnTheSource && !excludeIds.includes(result.idOnTheSource),
+ );
+ }, [searchResponse?.results, excludeIds]);
+
+ if (error) {
+ console.error('Principal search error:', error);
+ }
+
+ const handlePick = (principal: TPrincipal) => {
+ // Immediately add the selected person to the unified list
+ onAddPeople([principal]);
+ };
+
+ return (
+
+
+ options={selectableResults.map((s) => ({
+ ...s,
+ id: s.id ?? undefined,
+ key: s.idOnTheSource || 'unknown' + 'picker_key',
+ value: s.idOnTheSource || 'Unknown',
+ }))}
+ renderOptions={(o) => }
+ placeholder={placeholder || localize('com_ui_search_default_placeholder')}
+ query={searchQuery}
+ onQueryChange={(query: string) => {
+ setSearchQuery(query);
+ }}
+ onPick={handlePick}
+ isLoading={isLoading}
+ label=""
+ />
+
+ );
+}
diff --git a/client/src/components/Sharing/PeoplePicker/index.ts b/client/src/components/Sharing/PeoplePicker/index.ts
index cc89a024df..c1b8ace82e 100644
--- a/client/src/components/Sharing/PeoplePicker/index.ts
+++ b/client/src/components/Sharing/PeoplePicker/index.ts
@@ -1,3 +1,4 @@
export { default as PeoplePicker } from './PeoplePicker';
export { default as PeoplePickerSearchItem } from './PeoplePickerSearchItem';
export { default as SelectedPrincipalsList } from './SelectedPrincipalsList';
+export { default as UnifiedPeopleSearch } from './UnifiedPeopleSearch';
diff --git a/client/src/components/Sharing/PublicSharingToggle.tsx b/client/src/components/Sharing/PublicSharingToggle.tsx
index fa5fc0ebb3..eba2002b2d 100644
--- a/client/src/components/Sharing/PublicSharingToggle.tsx
+++ b/client/src/components/Sharing/PublicSharingToggle.tsx
@@ -1,8 +1,8 @@
import React from 'react';
-import { Switch } from '@librechat/client';
import { Globe, Shield } from 'lucide-react';
-import type { AccessRoleIds } from 'librechat-data-provider';
import { ResourceType } from 'librechat-data-provider';
+import { Switch, InfoHoverCard, ESide, Label } from '@librechat/client';
+import type { AccessRoleIds } from 'librechat-data-provider';
import AccessRolesPicker from './AccessRolesPicker';
import { useLocalize } from '~/hooks';
@@ -22,17 +22,16 @@ export default function PublicSharingToggle({
const localize = useLocalize();
return (
-
-
-
-
-
-
+
+ {/* Main toggle section */}
+
+
+
+
+
+
+ {/* Permission level section */}
{isPublic && (
-
-
-
-
+
+
+
+
+
+
+
-
)}
diff --git a/client/src/components/Sharing/index.ts b/client/src/components/Sharing/index.ts
index e3f5c5bcf5..e04d7c7efe 100644
--- a/client/src/components/Sharing/index.ts
+++ b/client/src/components/Sharing/index.ts
@@ -1,6 +1,5 @@
export { default as AccessRolesPicker } from './AccessRolesPicker';
export { default as GenericGrantAccessDialog } from './GenericGrantAccessDialog';
-export { default as GenericManagePermissionsDialog } from './GenericManagePermissionsDialog';
export { default as ManagePermissionsDialog } from './ManagePermissionsDialog';
export { default as PrincipalAvatar } from './PrincipalAvatar';
export { default as PublicSharingToggle } from './PublicSharingToggle';
diff --git a/client/src/components/SidePanel/Agents/AgentPanel.tsx b/client/src/components/SidePanel/Agents/AgentPanel.tsx
index 75120215eb..a617ba197b 100644
--- a/client/src/components/SidePanel/Agents/AgentPanel.tsx
+++ b/client/src/components/SidePanel/Agents/AgentPanel.tsx
@@ -135,7 +135,7 @@ export default function AgentPanel() {
} else {
showToast({
message: localize('com_ui_agent_version_duplicate', { versionIndex: versionIndex + 1 }),
- status: 'error',
+ status: 'warning',
duration: 10000,
});
}
diff --git a/client/src/locales/en/translation.json b/client/src/locales/en/translation.json
index d286b1cfc8..73e08f6961 100644
--- a/client/src/locales/en/translation.json
+++ b/client/src/locales/en/translation.json
@@ -697,6 +697,10 @@
"com_ui_user": "User",
"com_ui_group": "Group",
"com_ui_search_above_to_add": "Search above to add users or groups",
+ "com_ui_search_add_people": "Search & Add People",
+ "com_ui_default_permission_level": "Default Permission Level",
+ "com_ui_manage_access": "Manage Access",
+ "com_ui_search_above_to_add_people": "Search above to add people",
"com_ui_azure_ad": "Entra ID",
"com_ui_remove_user": "Remove {{0}}",
"com_ui_create": "Create",
diff --git a/client/tsconfig.json b/client/tsconfig.json
index 59ea7f46cd..04923f4e1b 100644
--- a/client/tsconfig.json
+++ b/client/tsconfig.json
@@ -34,6 +34,8 @@
"../e2e/**/*",
"test/setupTests.js",
"env.d.ts",
- "../config/translations/**/*.ts"
-, "../packages/client/src/hooks/useDelayedRender.tsx" ]
+ "../config/translations/**/*.ts",
+ "../packages/client/src/hooks/useDelayedRender.tsx",
+ "../packages/client/src/components/InfoHoverCard.tsx"
+ ]
}