mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-21 02:40:14 +01:00
refactor: organize Sharing/Agent components, improve type safety for resource types and access role ids, rename enums to PascalCase refactor: organize Sharing/Agent components, improve type safety for resource types and access role ids chore: move sharing related components to dedicated "Sharing" directory chore: remove PublicSharingToggle component and update index exports chore: move non-sidepanel agent components to `~/components/Agents` chore: move AgentCategoryDisplay component with tests chore: remove commented out code refactor: change PERMISSION_BITS from const to enum for better type safety refactor: reorganize imports in GenericGrantAccessDialog and update index exports for hooks refactor: update type definitions to use ACCESS_ROLE_IDS for improved type safety refactor: remove unused canAccessPromptResource middleware and related code refactor: remove unused prompt access roles from createAccessRoleMethods refactor: update resourceType in AclEntry type definition to remove unused 'prompt' value refactor: introduce ResourceType enum and update resourceType usage across data provider files for improved type safety refactor: update resourceType usage to ResourceType enum across sharing and permissions components for improved type safety refactor: standardize resourceType usage to ResourceType enum across agent and prompt models, permissions controller, and middleware for enhanced type safety refactor: update resourceType references from PROMPT_GROUP to PROMPTGROUP for consistency across models, middleware, and components refactor: standardize access role IDs and resource type usage across agent, file, and prompt models for improved type safety and consistency chore: add typedefs for TUpdateResourcePermissionsRequest and TUpdateResourcePermissionsResponse to enhance type definitions chore: move SearchPicker to PeoplePicker dir refactor: implement debouncing for query changes in SearchPicker for improved performance chore: fix typing, import order for agent admin settings fix: agent admin settings, prevent agent form submission refactor: rename `ACCESS_ROLE_IDS` to `AccessRoleIds` refactor: replace PermissionBits with PERMISSION_BITS refactor: replace PERMISSION_BITS with PermissionBits
189 lines
6.7 KiB
TypeScript
189 lines
6.7 KiB
TypeScript
import { memo, useState, useRef, useMemo, useCallback, KeyboardEvent } from 'react';
|
|
import { EarthIcon, Pen } from 'lucide-react';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import { PermissionBits, type TPromptGroup } from 'librechat-data-provider';
|
|
import {
|
|
Input,
|
|
Label,
|
|
Button,
|
|
OGDialog,
|
|
OGDialogTrigger,
|
|
OGDialogTemplate,
|
|
TrashIcon,
|
|
} from '@librechat/client';
|
|
import { useDeletePromptGroup, useUpdatePromptGroup } from '~/data-provider';
|
|
import CategoryIcon from '~/components/Prompts/Groups/CategoryIcon';
|
|
import { useLocalize, useResourcePermissions } from '~/hooks';
|
|
import { cn } from '~/utils';
|
|
|
|
interface DashGroupItemProps {
|
|
group: TPromptGroup;
|
|
instanceProjectId?: string;
|
|
}
|
|
|
|
function DashGroupItemComponent({ group, instanceProjectId }: DashGroupItemProps) {
|
|
const params = useParams();
|
|
const navigate = useNavigate();
|
|
const localize = useLocalize();
|
|
|
|
const blurTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
const [nameInputValue, setNameInputValue] = useState(group.name);
|
|
|
|
const { hasPermission } = useResourcePermissions('promptGroup', group._id || '');
|
|
const canEdit = hasPermission(PermissionBits.EDIT);
|
|
const canDelete = hasPermission(PermissionBits.DELETE);
|
|
|
|
const isGlobalGroup = useMemo(
|
|
() => instanceProjectId && group.projectIds?.includes(instanceProjectId),
|
|
[group.projectIds, instanceProjectId],
|
|
);
|
|
|
|
const updateGroup = useUpdatePromptGroup({
|
|
onMutate: () => {
|
|
if (blurTimeoutRef.current) {
|
|
clearTimeout(blurTimeoutRef.current);
|
|
}
|
|
},
|
|
});
|
|
|
|
const deleteGroup = useDeletePromptGroup({
|
|
onSuccess: (_response, variables) => {
|
|
if (variables.id === group._id) {
|
|
navigate('/d/prompts');
|
|
}
|
|
},
|
|
});
|
|
|
|
const { isLoading } = updateGroup;
|
|
|
|
const handleSaveRename = useCallback(() => {
|
|
console.log(group._id ?? '', { name: nameInputValue });
|
|
updateGroup.mutate({ id: group._id ?? '', payload: { name: nameInputValue } });
|
|
}, [group._id, nameInputValue, updateGroup]);
|
|
|
|
const handleKeyDown = useCallback(
|
|
(e: KeyboardEvent<HTMLDivElement>) => {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
navigate(`/d/prompts/${group._id}`, { replace: true });
|
|
}
|
|
},
|
|
[group._id, navigate],
|
|
);
|
|
|
|
const triggerDelete = useCallback(() => {
|
|
deleteGroup.mutate({ id: group._id ?? '' });
|
|
}, [group._id, deleteGroup]);
|
|
|
|
const handleContainerClick = useCallback(() => {
|
|
navigate(`/d/prompts/${group._id}`, { replace: true });
|
|
}, [group._id, navigate]);
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'mx-2 my-2 flex cursor-pointer rounded-lg border border-border-light bg-surface-primary p-3 shadow-sm transition-all duration-300 ease-in-out hover:bg-surface-secondary',
|
|
params.promptId === group._id && 'bg-surface-hover',
|
|
)}
|
|
onClick={handleContainerClick}
|
|
onKeyDown={handleKeyDown}
|
|
role="button"
|
|
tabIndex={0}
|
|
aria-label={`${group.name} prompt group`}
|
|
>
|
|
<div className="flex w-full items-center justify-between">
|
|
<div className="flex items-center gap-2 truncate pr-2">
|
|
<CategoryIcon category={group.category ?? ''} className="icon-lg" aria-hidden="true" />
|
|
|
|
<Label className="text-md cursor-pointer truncate font-semibold text-text-primary">
|
|
{group.name}
|
|
</Label>
|
|
</div>
|
|
|
|
<div className="flex h-full items-center gap-2">
|
|
{isGlobalGroup && (
|
|
<EarthIcon
|
|
className="icon-md text-green-500"
|
|
aria-label={localize('com_ui_global_group')}
|
|
/>
|
|
)}
|
|
{canEdit && (
|
|
<OGDialog>
|
|
<OGDialogTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
onClick={(e) => e.stopPropagation()}
|
|
className="h-8 w-8 p-0 hover:bg-surface-hover"
|
|
aria-label={localize('com_ui_rename_prompt') + ' ' + group.name}
|
|
>
|
|
<Pen className="icon-sm text-text-primary" aria-hidden="true" />
|
|
</Button>
|
|
</OGDialogTrigger>
|
|
<OGDialogTemplate
|
|
showCloseButton={false}
|
|
title={localize('com_ui_rename_prompt')}
|
|
className="w-11/12 max-w-lg"
|
|
main={
|
|
<div className="flex w-full flex-col items-center gap-2">
|
|
<div className="grid w-full items-center gap-2">
|
|
<Input
|
|
value={nameInputValue}
|
|
onChange={(e) => setNameInputValue(e.target.value)}
|
|
className="w-full"
|
|
aria-label={localize('com_ui_rename_prompt') + ' ' + group.name}
|
|
/>
|
|
</div>
|
|
</div>
|
|
}
|
|
selection={{
|
|
selectHandler: handleSaveRename,
|
|
selectClasses:
|
|
'bg-surface-submit hover:bg-surface-submit-hover text-white disabled:hover:bg-surface-submit',
|
|
selectText: localize('com_ui_save'),
|
|
isLoading,
|
|
}}
|
|
/>
|
|
</OGDialog>
|
|
)}
|
|
|
|
{canDelete && (
|
|
<OGDialog>
|
|
<OGDialogTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
className="h-8 w-8 p-0 hover:bg-surface-hover"
|
|
onClick={(e) => e.stopPropagation()}
|
|
aria-label={localize('com_ui_delete_prompt') + ' ' + group.name}
|
|
>
|
|
<TrashIcon className="icon-sm text-text-primary" aria-hidden="true" />
|
|
</Button>
|
|
</OGDialogTrigger>
|
|
<OGDialogTemplate
|
|
showCloseButton={false}
|
|
title={localize('com_ui_delete_prompt')}
|
|
className="w-11/12 max-w-lg"
|
|
main={
|
|
<div className="flex w-full flex-col items-center gap-2">
|
|
<div className="grid w-full items-center gap-2">
|
|
<Label htmlFor="confirm-delete" className="text-left text-sm font-medium">
|
|
{localize('com_ui_delete_confirm')} <strong>{group.name}</strong>
|
|
</Label>
|
|
</div>
|
|
</div>
|
|
}
|
|
selection={{
|
|
selectHandler: triggerDelete,
|
|
selectClasses:
|
|
'bg-red-600 dark:bg-red-600 hover:bg-red-700 dark:hover:bg-red-800 text-white',
|
|
selectText: localize('com_ui_delete'),
|
|
}}
|
|
/>
|
|
</OGDialog>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default memo(DashGroupItemComponent);
|