chat / client /src /components /Sharing /PeoplePicker /SelectedPrincipalsList.tsx
helloya20's picture
Upload 2345 files
f0743f4 verified
import React from 'react';
import { Button, useMediaQuery } from '@librechat/client';
import { Users, X, ExternalLink } from 'lucide-react';
import { ResourceType } from 'librechat-data-provider';
import type { TPrincipal, AccessRoleIds } from 'librechat-data-provider';
import AccessRolesPicker from '~/components/Sharing/AccessRolesPicker';
import PrincipalAvatar from '~/components/Sharing/PrincipalAvatar';
import { useLocalize } from '~/hooks';
interface SelectedPrincipalsListProps {
principles: TPrincipal[];
onRemoveHandler: (idOnTheSource: string) => void;
onRoleChange?: (idOnTheSource: string, newRoleId: AccessRoleIds) => void;
resourceType?: ResourceType;
className?: string;
}
export default function SelectedPrincipalsList({
principles,
onRemoveHandler,
className = '',
onRoleChange,
resourceType = ResourceType.AGENT,
}: SelectedPrincipalsListProps) {
const localize = useLocalize();
const isMobile = useMediaQuery('(max-width: 768px)');
const getPrincipalDisplayInfo = (principal: TPrincipal) => {
const displayName = principal.name || localize('com_ui_unknown');
const subtitle = isMobile
? `${principal.type} (${principal.source || 'local'})`
: principal.email || `${principal.type} (${principal.source || 'local'})`;
return { displayName, subtitle };
};
if (principles.length === 0) {
return (
<div className={`space-y-3 ${className}`}>
<div className="rounded-lg border border-dashed border-border-medium py-8 text-center text-muted-foreground">
<Users className="mx-auto mb-2 h-8 w-8 opacity-50" />
<p className="mt-1 text-xs">{localize('com_ui_search_above_to_add_all')}</p>
</div>
</div>
);
}
return (
<div className={`space-y-3 ${className}`}>
<div className="space-y-2">
{principles.map((share) => {
const { displayName, subtitle } = getPrincipalDisplayInfo(share);
return (
<div
key={share.idOnTheSource + '-principalList'}
className="bg-surface flex items-center justify-between rounded-2xl border border-border p-3"
>
<div className="flex min-w-0 flex-1 items-center gap-3">
<PrincipalAvatar principal={share} size="md" />
<div className="min-w-0 flex-1">
<div className="truncate text-sm font-medium">{displayName}</div>
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<span>{subtitle}</span>
{share.source === 'entra' && (
<>
<ExternalLink className="h-3 w-3" />
<span>{localize('com_ui_azure_ad')}</span>
</>
)}
</div>
</div>
</div>
<div className="flex flex-shrink-0 items-center gap-2">
{!!share.accessRoleId && !!onRoleChange && (
<AccessRolesPicker
resourceType={resourceType}
selectedRoleId={share.accessRoleId}
onRoleChange={(newRole) => {
onRoleChange?.(share.idOnTheSource!, newRole);
}}
className="min-w-0"
/>
)}
<Button
variant="outline"
onClick={() => onRemoveHandler(share.idOnTheSource!)}
className="h-9 w-9 p-0 hover:border-destructive/10 hover:bg-destructive/10 hover:text-destructive"
aria-label={localize('com_ui_remove_user', { 0: displayName })}
>
<X className="h-4 w-4" />
</Button>
</div>
</div>
);
})}
</div>
</div>
);
}