mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-27 04:36:12 +01:00
refactor: Replace marketplace interface config with permission-based system
- Add MARKETPLACE permission type to handle marketplace access control - Update interface configuration to use role-based marketplace settings (admin/user) - Replace direct marketplace boolean config with permission-based checks - Modify frontend components to use marketplace permissions instead of interface config - Update agent query hooks to use marketplace permissions for determining permission levels - Add marketplace configuration structure similar to peoplePicker in YAML config - Backend now sets MARKETPLACE permissions based on interface configuration - When marketplace enabled: users get agents with EDIT permissions in dropdown lists (builder mode) - When marketplace disabled: users get agents with VIEW permissions in dropdown lists (browse mode)
This commit is contained in:
parent
73fb4181fe
commit
bbafa8e306
12 changed files with 128 additions and 15 deletions
|
|
@ -34,6 +34,10 @@ export default function NewChat({
|
|||
permissionType: PermissionTypes.AGENTS,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
const hasAccessToMarketplace = useHasAccess({
|
||||
permissionType: PermissionTypes.MARKETPLACE,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
|
||||
const clickHandler: React.MouseEventHandler<HTMLButtonElement> = useCallback(
|
||||
(e) => {
|
||||
|
|
@ -67,9 +71,8 @@ export default function NewChat({
|
|||
authContext?.isAuthenticated !== undefined &&
|
||||
(authContext?.isAuthenticated === false || authContext?.user !== undefined);
|
||||
|
||||
// Show agent marketplace when auth is ready and user has access
|
||||
// Note: endpointsConfig[agents] is null, but we can still show the marketplace
|
||||
const showAgentMarketplace = authReady && hasAccessToAgents;
|
||||
// Show agent marketplace when marketplace permission is enabled, auth is ready, and user has access to agents
|
||||
const showAgentMarketplace = authReady && hasAccessToAgents && hasAccessToMarketplace;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type t from 'librechat-data-provider';
|
|||
import type { ContextType } from '~/common';
|
||||
|
||||
import { useGetEndpointsQuery, useGetAgentCategoriesQuery } from '~/data-provider';
|
||||
import { useDocumentTitle } from '~/hooks';
|
||||
import { useDocumentTitle, useHasAccess } from '~/hooks';
|
||||
import useLocalize from '~/hooks/useLocalize';
|
||||
import { TooltipAnchor, Button } from '~/components/ui';
|
||||
import { NewChatIcon } from '~/components/svg';
|
||||
|
|
@ -19,6 +19,7 @@ import AgentDetail from './AgentDetail';
|
|||
import SearchBar from './SearchBar';
|
||||
import AgentGrid from './AgentGrid';
|
||||
import store from '~/store';
|
||||
import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
|
||||
interface AgentMarketplaceProps {
|
||||
className?: string;
|
||||
|
|
@ -168,6 +169,14 @@ const AgentMarketplace: React.FC<AgentMarketplaceProps> = ({ className = '' }) =
|
|||
|
||||
const fullCollapse = useMemo(() => localStorage.getItem('fullPanelCollapse') === 'true', []);
|
||||
|
||||
const hasAccessToMarketplace = useHasAccess({
|
||||
permissionType: PermissionTypes.MARKETPLACE,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
if (!hasAccessToMarketplace) {
|
||||
navigate('/not-found', { replace: true });
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className={`relative flex w-full grow overflow-hidden bg-presentation ${className}`}>
|
||||
<MarketplaceProvider>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import { EarthIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import {
|
||||
AgentCapabilities,
|
||||
defaultAgentFormValues,
|
||||
PERMISSION_BITS,
|
||||
} from 'librechat-data-provider';
|
||||
import { AgentCapabilities, defaultAgentFormValues } from 'librechat-data-provider';
|
||||
import type { UseMutationResult, QueryObserverResult } from '@tanstack/react-query';
|
||||
import type { Agent, AgentCreateParams } from 'librechat-data-provider';
|
||||
import type { TAgentCapabilities, AgentForm } from '~/common';
|
||||
import { cn, createProviderOption, processAgentOption, getDefaultAgentFormValues } from '~/utils';
|
||||
import { useListAgentsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import {
|
||||
useListAgentsQuery,
|
||||
useGetStartupConfig,
|
||||
useAgentListingDefaultPermissionLevel,
|
||||
} from '~/data-provider';
|
||||
import ControlCombobox from '~/components/ui/ControlCombobox';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
|
|
@ -32,8 +32,10 @@ export default function AgentSelect({
|
|||
const { control, reset } = useFormContext();
|
||||
|
||||
const { data: startupConfig } = useGetStartupConfig();
|
||||
const permissionLevel = useAgentListingDefaultPermissionLevel();
|
||||
|
||||
const { data: agents = null } = useListAgentsQuery(
|
||||
{ requiredPermission: PERMISSION_BITS.EDIT },
|
||||
{ requiredPermission: permissionLevel },
|
||||
{
|
||||
select: (res) =>
|
||||
res.data.map((agent) =>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,34 @@
|
|||
import { QueryKeys, dataService, EModelEndpoint, PERMISSION_BITS } from 'librechat-data-provider';
|
||||
import {
|
||||
QueryKeys,
|
||||
dataService,
|
||||
EModelEndpoint,
|
||||
PERMISSION_BITS,
|
||||
PermissionTypes,
|
||||
Permissions,
|
||||
} from 'librechat-data-provider';
|
||||
import { useQuery, useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMemo } from 'react';
|
||||
import type {
|
||||
QueryObserverResult,
|
||||
UseQueryOptions,
|
||||
UseInfiniteQueryOptions,
|
||||
} from '@tanstack/react-query';
|
||||
import type t from 'librechat-data-provider';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
|
||||
/**
|
||||
* Hook to determine the appropriate permission level for agent queries based on marketplace configuration
|
||||
*/
|
||||
export const useAgentListingDefaultPermissionLevel = () => {
|
||||
const hasMarketplaceAccess = useHasAccess({
|
||||
permissionType: PermissionTypes.MARKETPLACE,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
|
||||
// When marketplace is active: EDIT permissions (builder mode)
|
||||
// When marketplace is not active: VIEW permissions (browse mode)
|
||||
return hasMarketplaceAccess ? PERMISSION_BITS.EDIT : PERMISSION_BITS.VIEW;
|
||||
};
|
||||
|
||||
/**
|
||||
* AGENTS
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { PERMISSION_BITS, TAgentsMap } from 'librechat-data-provider';
|
||||
import { TAgentsMap } from 'librechat-data-provider';
|
||||
import { useMemo } from 'react';
|
||||
import { useListAgentsQuery } from '~/data-provider';
|
||||
import { useListAgentsQuery, useAgentListingDefaultPermissionLevel } from '~/data-provider';
|
||||
import { mapAgents } from '~/utils';
|
||||
|
||||
export default function useAgentsMap({
|
||||
|
|
@ -8,8 +8,10 @@ export default function useAgentsMap({
|
|||
}: {
|
||||
isAuthenticated: boolean;
|
||||
}): TAgentsMap | undefined {
|
||||
const permissionLevel = useAgentListingDefaultPermissionLevel();
|
||||
|
||||
const { data: agentsList = null } = useListAgentsQuery(
|
||||
{ requiredPermission: PERMISSION_BITS.EDIT },
|
||||
{ requiredPermission: permissionLevel },
|
||||
{
|
||||
select: (res) => mapAgents(res.data),
|
||||
enabled: isAuthenticated,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue