LibreChat/client/src/components/SidePanel/Agents/AgentFooter.tsx
Danny Avila 76d75030b9
🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804)
WIP: pre-granular-permissions commit

feat: Add category and support contact fields to Agent schema and UI components

Revert "feat: Add category and support contact fields to Agent schema and UI components"

This reverts commit c43a52b4c9.

Fix: Update import for renderHook in useAgentCategories.spec.tsx

fix: Update icon rendering in AgentCategoryDisplay tests to use empty spans

refactor: Improve category synchronization logic and clean up AgentConfig component

refactor: Remove unused UI flow translations from translation.json

feat: agent marketplace features

🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804)
2025-08-11 19:00:47 -04:00

102 lines
3.6 KiB
TypeScript

import { Spinner } from '@librechat/client';
import { useWatch, useFormContext } from 'react-hook-form';
import {
SystemRoles,
Permissions,
PermissionTypes,
PERMISSION_BITS,
} from 'librechat-data-provider';
import type { AgentForm, AgentPanelProps } from '~/common';
import { useLocalize, useAuthContext, useHasAccess, useResourcePermissions } from '~/hooks';
import GrantAccessDialog from './Sharing/GrantAccessDialog';
import { useUpdateAgentMutation } from '~/data-provider';
import AdvancedButton from './Advanced/AdvancedButton';
import VersionButton from './Version/VersionButton';
import DuplicateAgent from './DuplicateAgent';
import AdminSettings from './AdminSettings';
import DeleteButton from './DeleteButton';
import { Panel } from '~/common';
export default function AgentFooter({
activePanel,
createMutation,
updateMutation,
setActivePanel,
setCurrentAgentId,
}: Pick<
AgentPanelProps,
'setCurrentAgentId' | 'createMutation' | 'activePanel' | 'setActivePanel'
> & {
updateMutation: ReturnType<typeof useUpdateAgentMutation>;
}) {
const localize = useLocalize();
const { user } = useAuthContext();
const methods = useFormContext<AgentForm>();
const { control } = methods;
const agent = useWatch({ control, name: 'agent' });
const agent_id = useWatch({ control, name: 'id' });
const hasAccessToShareAgents = useHasAccess({
permissionType: PermissionTypes.AGENTS,
permission: Permissions.SHARED_GLOBAL,
});
const { hasPermission, isLoading: permissionsLoading } = useResourcePermissions(
'agent',
agent?._id || '',
);
const canShareThisAgent = hasPermission(PERMISSION_BITS.SHARE);
const canDeleteThisAgent = hasPermission(PERMISSION_BITS.DELETE);
const renderSaveButton = () => {
if (createMutation.isLoading || updateMutation.isLoading) {
return <Spinner className="icon-md" aria-hidden="true" />;
}
if (agent_id) {
return localize('com_ui_save');
}
return localize('com_ui_create');
};
const showButtons = activePanel === Panel.builder;
return (
<div className="mb-1 flex w-full flex-col gap-2">
{showButtons && <AdvancedButton setActivePanel={setActivePanel} />}
{showButtons && agent_id && <VersionButton setActivePanel={setActivePanel} />}
{user?.role === SystemRoles.ADMIN && showButtons && <AdminSettings />}
{/* Context Button */}
<div className="flex items-center justify-end gap-2">
{(agent?.author === user?.id || user?.role === SystemRoles.ADMIN || canDeleteThisAgent) &&
!permissionsLoading && (
<DeleteButton
agent_id={agent_id}
setCurrentAgentId={setCurrentAgentId}
createMutation={createMutation}
/>
)}
{(agent?.author === user?.id || user?.role === SystemRoles.ADMIN || canShareThisAgent) &&
hasAccessToShareAgents &&
!permissionsLoading && (
<GrantAccessDialog
agentDbId={agent?._id}
agentId={agent_id}
agentName={agent?.name ?? ''}
/>
)}
{agent && agent.author === user?.id && <DuplicateAgent agent_id={agent_id} />}
{/* Submit Button */}
<button
className="btn btn-primary focus:shadow-outline flex h-9 w-full items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500"
type="submit"
disabled={createMutation.isLoading || updateMutation.isLoading}
aria-busy={createMutation.isLoading || updateMutation.isLoading}
>
{renderSaveButton()}
</button>
</div>
</div>
);
}