mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-17 07:58:08 +01:00
style: AccessRolesPicker to use DropdownPopup, theming, import order, localization refactor: Update localization keys for Agent Marketplace in NewChat component, remove duplicate key style: Adjust layout and font size in NewChat component for Agent Marketplace button style: theming in AgentGrid style: Update theming and text colors across Agent components for improved consistency chore: import order style: Replace Dialog with OGDialog and update content components in AgentDetail refactor: Simplify AgentDetail component by removing dropdown menu and replacing it with a copy link button style: Enhance scrollbar visibility and layout in AgentMarketplace and CategoryTabs components style: Adjust layout in AgentMarketplace component by removing unnecessary padding from the container style: Refactor layout in AgentMarketplace component by reorganizing hero section and sticky wrapper for improved structure with collapsible header effect style: Improve responsiveness and layout in AgentMarketplace component by adjusting header visibility and modifying container styles based on screen size fix: Update localization key for no categories message in CategoryTabs component and corresponding test style: Add className prop to OpenSidebar component for improved styling flexibility and update Header to utilize it for responsive design style: Enhance layout and scrolling behavior in CategoryTabs component by adding scroll snap properties and adjusting class names for improved user experience style: Update AgentGrid component layout and skeleton structure for improved visual consistency and responsiveness
122 lines
4.1 KiB
TypeScript
122 lines
4.1 KiB
TypeScript
import React from 'react';
|
|
import * as Ariakit from '@ariakit/react';
|
|
import { ChevronDown } from 'lucide-react';
|
|
import { DropdownPopup } from '@librechat/client';
|
|
import { ACCESS_ROLE_IDS } from 'librechat-data-provider';
|
|
import { useGetAccessRolesQuery } from 'librechat-data-provider/react-query';
|
|
import type { AccessRole } from 'librechat-data-provider';
|
|
import type * as t from '~/common';
|
|
import { useLocalize } from '~/hooks';
|
|
import { cn } from '~/utils';
|
|
|
|
interface AccessRolesPickerProps {
|
|
resourceType?: string;
|
|
selectedRoleId?: string;
|
|
onRoleChange: (roleId: string) => void;
|
|
className?: string;
|
|
}
|
|
|
|
export default function AccessRolesPicker({
|
|
resourceType = 'agent',
|
|
selectedRoleId = ACCESS_ROLE_IDS.AGENT_VIEWER,
|
|
onRoleChange,
|
|
className = '',
|
|
}: AccessRolesPickerProps) {
|
|
const localize = useLocalize();
|
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
|
|
// Fetch access roles from API
|
|
const { data: accessRoles, isLoading: rolesLoading } = useGetAccessRolesQuery(resourceType);
|
|
|
|
// Helper function to get localized role name and description
|
|
const getLocalizedRoleInfo = (roleId: string) => {
|
|
switch (roleId) {
|
|
case 'agent_viewer':
|
|
return {
|
|
name: localize('com_ui_role_viewer'),
|
|
description: localize('com_ui_role_viewer_desc'),
|
|
};
|
|
case 'agent_editor':
|
|
return {
|
|
name: localize('com_ui_role_editor'),
|
|
description: localize('com_ui_role_editor_desc'),
|
|
};
|
|
case 'agent_manager':
|
|
return {
|
|
name: localize('com_ui_role_manager'),
|
|
description: localize('com_ui_role_manager_desc'),
|
|
};
|
|
case 'agent_owner':
|
|
return {
|
|
name: localize('com_ui_role_owner'),
|
|
description: localize('com_ui_role_owner_desc'),
|
|
};
|
|
default:
|
|
return {
|
|
name: localize('com_ui_unknown'),
|
|
description: localize('com_ui_unknown'),
|
|
};
|
|
}
|
|
};
|
|
|
|
// Find the currently selected role
|
|
const selectedRole = accessRoles?.find((role) => role.accessRoleId === selectedRoleId);
|
|
const selectedRoleInfo = selectedRole ? getLocalizedRoleInfo(selectedRole.accessRoleId) : null;
|
|
|
|
if (rolesLoading || !accessRoles) {
|
|
return (
|
|
<div className={className}>
|
|
<div className="flex items-center justify-center py-2">
|
|
<div className="h-4 w-4 animate-spin rounded-full border-2 border-border-light border-t-blue-600"></div>
|
|
<span className="ml-2 text-sm text-text-secondary">{localize('com_ui_loading')}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const dropdownItems: t.MenuItemProps[] = accessRoles.map((role: AccessRole) => {
|
|
const localizedInfo = getLocalizedRoleInfo(role.accessRoleId);
|
|
return {
|
|
id: role.accessRoleId,
|
|
label: localizedInfo.name,
|
|
onClick: () => {
|
|
onRoleChange(role.accessRoleId);
|
|
setIsOpen(false);
|
|
},
|
|
render: (props) => (
|
|
<button {...props}>
|
|
<div className="flex flex-col items-start gap-0.5 text-left">
|
|
<span className="font-medium text-text-primary">{localizedInfo.name}</span>
|
|
<span className="text-xs text-text-secondary">{localizedInfo.description}</span>
|
|
</div>
|
|
</button>
|
|
),
|
|
};
|
|
});
|
|
|
|
return (
|
|
<div className={className}>
|
|
<DropdownPopup
|
|
menuId="access-roles-menu"
|
|
isOpen={isOpen}
|
|
setIsOpen={setIsOpen}
|
|
trigger={
|
|
<Ariakit.MenuButton
|
|
aria-label={selectedRoleInfo?.description || 'Select role'}
|
|
className={cn(
|
|
'flex items-center justify-between gap-2 rounded-lg border border-border-light bg-surface-primary px-3 py-2 text-sm transition-colors hover:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-ring-primary',
|
|
'min-w-[200px]',
|
|
)}
|
|
>
|
|
<span className="font-medium">
|
|
{selectedRoleInfo?.name || localize('com_ui_select')}
|
|
</span>
|
|
<ChevronDown className="h-4 w-4 text-text-secondary" />
|
|
</Ariakit.MenuButton>
|
|
}
|
|
items={dropdownItems}
|
|
className="w-[280px]"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|