mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-22 19:30:15 +01:00
chore: add missing default role schema values for people picker perms, cleanup typing
This commit is contained in:
parent
8e003083dc
commit
b680ba2c75
11 changed files with 47 additions and 69 deletions
|
|
@ -4,8 +4,8 @@ import {
|
|||
SystemRoles,
|
||||
Permissions,
|
||||
ResourceType,
|
||||
PermissionTypes,
|
||||
PermissionBits,
|
||||
PermissionTypes,
|
||||
} from 'librechat-data-provider';
|
||||
import { Button } from '@librechat/client';
|
||||
import type { TPromptGroup } from 'librechat-data-provider';
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export default function GenericGrantAccessDialog({
|
|||
resourceId?: string | null;
|
||||
resourceName?: string;
|
||||
resourceType: ResourceType;
|
||||
onGrantAccess?: (shares: TPrincipal[], isPublic: boolean, publicRole: AccessRoleIds) => void;
|
||||
onGrantAccess?: (shares: TPrincipal[], isPublic: boolean, publicRole?: AccessRoleIds) => void;
|
||||
disabled?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default function GenericManagePermissionsDialog({
|
|||
onUpdatePermissions?: (
|
||||
shares: TPrincipal[],
|
||||
isPublic: boolean,
|
||||
publicRole: AccessRoleIds,
|
||||
publicRole?: AccessRoleIds,
|
||||
) => void;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
|
|
@ -84,7 +84,7 @@ export default function GenericManagePermissionsDialog({
|
|||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const handleRoleChange = (idOnTheSource: string, newRole: string) => {
|
||||
const handleRoleChange = (idOnTheSource: string, newRole: AccessRoleIds) => {
|
||||
setManagedShares(
|
||||
managedShares.map((s) =>
|
||||
s.idOnTheSource === idOnTheSource ? { ...s, accessRoleId: newRole } : s,
|
||||
|
|
@ -162,7 +162,7 @@ export default function GenericManagePermissionsDialog({
|
|||
setManagedPublicRole(config?.defaultViewerRoleId);
|
||||
}
|
||||
};
|
||||
const handlePublicRoleChange = (role: string) => {
|
||||
const handlePublicRoleChange = (role: AccessRoleIds) => {
|
||||
setManagedPublicRole(role);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ResourceType, AccessRoleIds } from 'librechat-data-provider';
|
||||
import { Share2Icon, Users, Loader, Shield, Link, CopyCheck } from 'lucide-react';
|
||||
import { Permissions, ResourceType, PermissionTypes, AccessRoleIds } from 'librechat-data-provider';
|
||||
import {
|
||||
useGetResourcePermissionsQuery,
|
||||
useUpdateResourcePermissionsMutation,
|
||||
|
|
@ -15,7 +15,7 @@ import {
|
|||
useToastContext,
|
||||
} from '@librechat/client';
|
||||
import type { TPrincipal } from 'librechat-data-provider';
|
||||
import { useLocalize, useCopyToClipboard, useHasAccess } from '~/hooks';
|
||||
import { useLocalize, useCopyToClipboard, usePeoplePickerPermissions } from '~/hooks';
|
||||
import ManagePermissionsDialog from './ManagePermissionsDialog';
|
||||
import PublicSharingToggle from './PublicSharingToggle';
|
||||
import AccessRolesPicker from './AccessRolesPicker';
|
||||
|
|
@ -37,29 +37,7 @@ export default function GrantAccessDialog({
|
|||
}) {
|
||||
const localize = useLocalize();
|
||||
const { showToast } = useToastContext();
|
||||
|
||||
// Check if user has permission to access people picker
|
||||
const canViewUsers = useHasAccess({
|
||||
permissionType: PermissionTypes.PEOPLE_PICKER,
|
||||
permission: Permissions.VIEW_USERS,
|
||||
});
|
||||
const canViewGroups = useHasAccess({
|
||||
permissionType: PermissionTypes.PEOPLE_PICKER,
|
||||
permission: Permissions.VIEW_GROUPS,
|
||||
});
|
||||
const hasPeoplePickerAccess = canViewUsers || canViewGroups;
|
||||
|
||||
/** Type filter based on permissions */
|
||||
const peoplePickerTypeFilter = useMemo(() => {
|
||||
if (canViewUsers && canViewGroups) {
|
||||
return null; // Both types allowed
|
||||
} else if (canViewUsers) {
|
||||
return 'user' as const;
|
||||
} else if (canViewGroups) {
|
||||
return 'group' as const;
|
||||
}
|
||||
return null;
|
||||
}, [canViewUsers, canViewGroups]);
|
||||
const { hasPeoplePickerAccess, peoplePickerTypeFilter } = usePeoplePickerPermissions();
|
||||
|
||||
const {
|
||||
data: permissionsData,
|
||||
|
|
@ -72,7 +50,7 @@ export default function GrantAccessDialog({
|
|||
const updatePermissionsMutation = useUpdateResourcePermissionsMutation();
|
||||
|
||||
const [newShares, setNewShares] = useState<TPrincipal[]>([]);
|
||||
const [defaultPermissionId, setDefaultPermissionId] = useState<string>(
|
||||
const [defaultPermissionId, setDefaultPermissionId] = useState<AccessRoleIds>(
|
||||
AccessRoleIds.AGENT_VIEWER,
|
||||
);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import { PrincipalType } from 'librechat-data-provider';
|
||||
import type { TPrincipal, PrincipalSearchParams } from 'librechat-data-provider';
|
||||
import { useSearchPrincipalsQuery } from 'librechat-data-provider/react-query';
|
||||
import PeoplePickerSearchItem from './PeoplePickerSearchItem';
|
||||
|
|
@ -10,7 +11,7 @@ interface PeoplePickerProps {
|
|||
onSelectionChange: (principals: TPrincipal[]) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
typeFilter?: 'user' | 'group' | null;
|
||||
typeFilter?: PrincipalType.USER | PrincipalType.GROUP | PrincipalType.ROLE | null;
|
||||
}
|
||||
|
||||
export default function PeoplePicker({
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export default function PublicSharingToggle({
|
|||
resourceType = ResourceType.AGENT,
|
||||
}: {
|
||||
isPublic: boolean;
|
||||
publicRole: AccessRoleIds;
|
||||
publicRole?: AccessRoleIds;
|
||||
onPublicToggle: (isPublic: boolean) => void;
|
||||
onPublicRoleChange: (role: AccessRoleIds) => void;
|
||||
resourceType?: ResourceType;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import {
|
|||
SystemRoles,
|
||||
Permissions,
|
||||
ResourceType,
|
||||
PermissionTypes,
|
||||
PermissionBits,
|
||||
PermissionTypes,
|
||||
} from 'librechat-data-provider';
|
||||
import type { AgentForm, AgentPanelProps } from '~/common';
|
||||
import { useLocalize, useAuthContext, useHasAccess, useResourcePermissions } from '~/hooks';
|
||||
|
|
@ -43,7 +43,7 @@ export default function AgentFooter({
|
|||
permission: Permissions.SHARED_GLOBAL,
|
||||
});
|
||||
const { hasPermission, isLoading: permissionsLoading } = useResourcePermissions(
|
||||
'agent',
|
||||
ResourceType.AGENT,
|
||||
agent?._id || '',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useMemo } from 'react';
|
||||
import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
import { PermissionTypes, PrincipalType, Permissions } from 'librechat-data-provider';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
|
||||
/**
|
||||
|
|
@ -17,21 +17,33 @@ export const usePeoplePickerPermissions = () => {
|
|||
permission: Permissions.VIEW_GROUPS,
|
||||
});
|
||||
|
||||
const hasPeoplePickerAccess = canViewUsers || canViewGroups;
|
||||
const canViewRoles = useHasAccess({
|
||||
permissionType: PermissionTypes.PEOPLE_PICKER,
|
||||
permission: Permissions.VIEW_ROLES,
|
||||
});
|
||||
|
||||
const peoplePickerTypeFilter = useMemo(() => {
|
||||
if (canViewUsers && canViewGroups) {
|
||||
return null; // Both types allowed
|
||||
const hasPeoplePickerAccess = canViewUsers || canViewGroups || canViewRoles;
|
||||
|
||||
const peoplePickerTypeFilter:
|
||||
| PrincipalType.USER
|
||||
| PrincipalType.GROUP
|
||||
| PrincipalType.ROLE
|
||||
| null = useMemo(() => {
|
||||
if (canViewUsers && canViewGroups && canViewRoles) {
|
||||
return null; // All types allowed
|
||||
} else if (canViewUsers) {
|
||||
return 'user' as const;
|
||||
return PrincipalType.USER;
|
||||
} else if (canViewGroups) {
|
||||
return 'group' as const;
|
||||
return PrincipalType.GROUP;
|
||||
} else if (canViewRoles) {
|
||||
return PrincipalType.ROLE;
|
||||
}
|
||||
return null;
|
||||
}, [canViewUsers, canViewGroups]);
|
||||
}, [canViewUsers, canViewGroups, canViewRoles]);
|
||||
|
||||
return {
|
||||
canViewUsers,
|
||||
canViewRoles,
|
||||
canViewGroups,
|
||||
hasPeoplePickerAccess,
|
||||
peoplePickerTypeFilter,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ export enum SystemRoles {
|
|||
USER = 'USER',
|
||||
}
|
||||
|
||||
// The role schema now only needs to reference the permissions schema.
|
||||
export const roleSchema = z.object({
|
||||
name: z.string(),
|
||||
permissions: permissionsSchema,
|
||||
|
|
@ -38,7 +37,6 @@ export const roleSchema = z.object({
|
|||
|
||||
export type TRole = z.infer<typeof roleSchema>;
|
||||
|
||||
// Define default roles using the new structure.
|
||||
const defaultRolesSchema = z.object({
|
||||
[SystemRoles.ADMIN]: roleSchema.extend({
|
||||
name: z.literal(SystemRoles.ADMIN),
|
||||
|
|
@ -80,6 +78,7 @@ const defaultRolesSchema = z.object({
|
|||
[PermissionTypes.PEOPLE_PICKER]: peoplePickerPermissionsSchema.extend({
|
||||
[Permissions.VIEW_USERS]: z.boolean().default(true),
|
||||
[Permissions.VIEW_GROUPS]: z.boolean().default(true),
|
||||
[Permissions.VIEW_ROLES]: z.boolean().default(true),
|
||||
}),
|
||||
[PermissionTypes.MARKETPLACE]: z.object({
|
||||
[Permissions.USE]: z.boolean().default(false),
|
||||
|
|
@ -137,6 +136,7 @@ export const roleDefaults = defaultRolesSchema.parse({
|
|||
[PermissionTypes.PEOPLE_PICKER]: {
|
||||
[Permissions.VIEW_USERS]: true,
|
||||
[Permissions.VIEW_GROUPS]: true,
|
||||
[Permissions.VIEW_ROLES]: true,
|
||||
},
|
||||
[PermissionTypes.MARKETPLACE]: {
|
||||
[Permissions.USE]: true,
|
||||
|
|
@ -163,6 +163,7 @@ export const roleDefaults = defaultRolesSchema.parse({
|
|||
[PermissionTypes.PEOPLE_PICKER]: {
|
||||
[Permissions.VIEW_USERS]: false,
|
||||
[Permissions.VIEW_GROUPS]: false,
|
||||
[Permissions.VIEW_ROLES]: false,
|
||||
},
|
||||
[PermissionTypes.MARKETPLACE]: {
|
||||
[Permissions.USE]: false,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { InfiniteData } from '@tanstack/react-query';
|
||||
import type { AccessRoleIds } from '../accessPermissions';
|
||||
import type * as p from '../accessPermissions';
|
||||
import type * as a from '../types/agents';
|
||||
import type * as s from '../schemas';
|
||||
import type * as t from '../types';
|
||||
|
|
@ -129,28 +129,14 @@ export type MemoriesResponse = {
|
|||
export type PrincipalSearchParams = {
|
||||
q: string;
|
||||
limit?: number;
|
||||
type?: 'user' | 'group';
|
||||
};
|
||||
|
||||
export type PrincipalSearchResult = {
|
||||
id?: string | null;
|
||||
type: 'user' | 'group';
|
||||
name: string;
|
||||
email?: string;
|
||||
username?: string;
|
||||
avatar?: string;
|
||||
provider?: string;
|
||||
source: 'local' | 'entra';
|
||||
memberCount?: number;
|
||||
description?: string;
|
||||
idOnTheSource?: string;
|
||||
type?: p.PrincipalType.USER | p.PrincipalType.GROUP | p.PrincipalType.ROLE;
|
||||
};
|
||||
|
||||
export type PrincipalSearchResponse = {
|
||||
query: string;
|
||||
limit: number;
|
||||
type?: 'user' | 'group';
|
||||
results: PrincipalSearchResult[];
|
||||
type?: p.PrincipalType.USER | p.PrincipalType.GROUP | p.PrincipalType.ROLE;
|
||||
results: p.TPrincipalSearchResult[];
|
||||
count: number;
|
||||
sources: {
|
||||
local: number;
|
||||
|
|
@ -159,7 +145,7 @@ export type PrincipalSearchResponse = {
|
|||
};
|
||||
|
||||
export type AccessRole = {
|
||||
accessRoleId: AccessRoleIds;
|
||||
accessRoleId: p.AccessRoleIds;
|
||||
name: string;
|
||||
description: string;
|
||||
permBits: number;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import type { Document, Types } from 'mongoose';
|
|||
import { PrincipalType, PrincipalModel, ResourceType } from 'librechat-data-provider';
|
||||
|
||||
export type AclEntry = {
|
||||
/** The type of principal ('user', 'group', 'public') */
|
||||
/** The type of principal (PrincipalType.USER, PrincipalType.GROUP, PrincipalType.PUBLIC) */
|
||||
principalType: PrincipalType;
|
||||
/** The ID of the principal (null for 'public', string for 'role') */
|
||||
/** The ID of the principal (null for PrincipalType.PUBLIC, string for PrincipalType.ROLE) */
|
||||
principalId?: Types.ObjectId | string;
|
||||
/** The model name for the principal ('User' or 'Group') */
|
||||
/** The model name for the principal (`PrincipalModel`) */
|
||||
principalModel?: PrincipalModel;
|
||||
/** The type of resource ('agent', 'project', 'file', 'promptGroup') */
|
||||
/** The type of resource (`ResourceType`) */
|
||||
resourceType: ResourceType;
|
||||
/** The ID of the resource */
|
||||
resourceId: Types.ObjectId;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue