feat: add app log permission (#4932)

* feat: add app log permission

* fix: org search bug
This commit is contained in:
Finley Ge
2025-05-30 17:09:29 +08:00
committed by archer
parent 5a5367d30b
commit d7b9f94270
10 changed files with 119 additions and 73 deletions

View File

@@ -46,16 +46,22 @@ function MemberModal({
const collaboratorList = useContextSelector(CollaboratorContext, (v) => v.collaboratorList);
const [filterClass, setFilterClass] = useState<'member' | 'org' | 'group'>();
const {
paths,
paths: orgPaths,
onClickOrg,
members: orgMembers,
MemberScrollData: OrgMemberScrollData,
onPathClick,
onPathClick: onOrgPathClick,
orgs,
searchKey,
setSearchKey
} = useOrg({ withPermission: false });
const onExpandOrg = (org: OrgListItemType) => {
setFilterClass('org');
setSearchKey('');
onClickOrg(org);
};
const {
data: members,
ScrollData: TeamMemberScrollData,
@@ -104,8 +110,8 @@ function MemberModal({
permissionList?.read?.value
);
const perLabel = useMemo(() => {
if (selectedPermission === undefined) return '';
return getPerLabelList(selectedPermission!).join('、');
if (selectedPermission === undefined) return [];
return getPerLabelList(selectedPermission!);
}, [getPerLabelList, selectedPermission]);
const onUpdateCollaborators = useContextSelector(
@@ -194,6 +200,7 @@ function MemberModal({
placeholder={t('user:search_group_org_user')}
bgColor="myGray.50"
onChange={(e) => setSearchKey(e.target.value)}
value={searchKey}
/>
<Flex flexDirection="column" mt="3" overflow={'auto'} flex={'1 0 0'} h={0}>
@@ -238,21 +245,21 @@ function MemberModal({
? t('user:team.org.org')
: t('user:team.group.group')
},
...paths
...orgPaths
]}
onClick={(parentId) => {
if (parentId === '') {
setFilterClass(undefined);
onPathClick('');
onOrgPathClick('');
} else if (
parentId === 'member' ||
parentId === 'org' ||
parentId === 'group'
) {
setFilterClass(parentId);
onPathClick('');
onOrgPathClick('');
} else {
onPathClick(parentId);
onOrgPathClick(parentId);
}
}}
rootName={t('common:Team')}
@@ -329,8 +336,8 @@ function MemberModal({
bgColor: 'myGray.200'
}}
onClick={(e) => {
onClickOrg(org);
// setPath(getOrgChildrenPath(org));
// onClickOrg(org);
onExpandOrg(org);
e.stopPropagation();
}}
/>
@@ -438,7 +445,7 @@ function MemberModal({
borderRadius={'md'}
h={'32px'}
>
{t(perLabel as any)}
{perLabel.map((item) => t(item as any)).join('、')}
<ChevronDownIcon fontSize={'md'} />
</Flex>
}

View File

@@ -7,7 +7,8 @@ import {
Radio,
useOutsideClick,
HStack,
MenuButton
MenuButton,
Checkbox
} from '@chakra-ui/react';
import React, { useMemo, useRef, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
@@ -89,19 +90,21 @@ function PermissionSelect({
return permissionList['read'].value;
}, [permissionList, value]);
// const selectedMultipleValues = useMemo(() => {
// const per = new Permission({ per: value });
//
// return permissionSelectList.multipleCheckBoxList
// .filter((item) => {
// return per.checkPer(item.value);
// })
// .map((item) => item.value);
// }, [permissionSelectList.multipleCheckBoxList, value]);
const selectedMultipleValues = useMemo(() => {
const per = new Permission({ per: value });
const onSelectPer = (per: PermissionValueType) => {
if (per === value) return;
onChange(per);
return permissionSelectList.multipleCheckBoxList
.filter((item) => {
return per.checkPer(item.value);
})
.map((item) => item.value);
}, [permissionSelectList.multipleCheckBoxList, value]);
const onSelectPer = (perValue: PermissionValueType) => {
if (perValue === value) return;
const per = new Permission({ per: perValue });
per.addPer(...selectedMultipleValues);
onChange(per.value);
setIsOpen(false);
};
@@ -184,50 +187,61 @@ function PermissionSelect({
);
})}
{/* <MyDivider my={3} />
<MyDivider my={2} />
{multipleValues.length > 0 && <Box m="4">其他权限(多选)</Box>} */}
{/* {permissionSelectList.multipleCheckBoxList.length > 0 && (
<Box m="4">其他权限(多选)</Box>
)} */}
{/* The list of multiple select permissions */}
{/* {list
.filter((item) => item.type === 'multiple')
.map((item) => {
const change = () => {
if (checkPermission(valueState, item.value)) {
setValueState(new Permission(valueState).remove(item.value).value);
} else {
setValueState(new Permission(valueState).add(item.value).value);
}
};
return (
<Flex
key={item.value}
{...(checkPermission(valueState, item.value)
? {
color: 'primary.500',
bg: 'myWhite.300'
}
: {})}
whiteSpace="pre-wrap"
flexDirection="row"
justifyContent="start"
p="2"
_hover={{
bg: 'myGray.50'
}}
>
<Checkbox
size="lg"
isChecked={checkPermission(valueState, item.value)}
onChange={change}
/>
<Flex px="4" flexDirection="column" onClick={change}>
<Box fontWeight="500">{item.name}</Box>
<Box fontWeight="400">{item.description}</Box>
</Flex>
{permissionSelectList.multipleCheckBoxList.map((item) => {
const isChecked = selectedMultipleValues.includes(item.value);
const isDisabled = new Permission({ per: selectedSingleValue }).checkPer(item.value);
const change = () => {
if (isDisabled) return;
const per = new Permission({ per: value });
if (isChecked) {
per.removePer(item.value);
} else {
per.addPer(item.value);
}
onChange(per.value);
};
return (
<Flex
key={item.value}
{...(isChecked
? {
color: 'primary.500',
bg: 'myWhite.300'
}
: {})}
whiteSpace="pre-wrap"
flexDirection="row"
justifyContent="start"
p="2"
_hover={{
bg: 'myGray.50'
}}
{...(isDisabled
? {
cursor: 'not-allowed',
opacity: 0.5
}
: {})}
>
<Checkbox
size="lg"
isChecked={isChecked}
onChange={change}
isDisabled={isDisabled}
/>
<Flex px="4" flexDirection="column" onClick={change}>
<Box fontWeight="500">{t(item.name as any)}</Box>
<Box fontWeight="400">{t(item.description as any)}</Box>
</Flex>
);
})}*/}
</Flex>
);
})}
{onDelete && (
<>
<MyDivider my={2} h={'2px'} borderColor={'myGray.200'} />

View File

@@ -35,10 +35,10 @@ const RouteTab = () => {
{
label: t('app:publish_channel'),
id: TabEnum.publish
},
{ label: t('app:chat_logs'), id: TabEnum.logs }
}
]
: [])
: []),
...(appDetail.permission.hasLogPer ? [{ label: t('app:chat_logs'), id: TabEnum.logs }] : [])
],
[appDetail.permission.hasManagePer, appDetail.type]
);

View File

@@ -18,6 +18,7 @@ import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSc
import type { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
import { type AIChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import { AppLogPermissionVal } from '@fastgpt/global/support/permission/app/constant';
const formatJsonString = (data: any) => {
return JSON.stringify(data).replace(/"/g, '""').replace(/\n/g, '\\n');
@@ -44,7 +45,7 @@ async function handler(req: ApiRequestProps<ExportChatLogsBody, {}>, res: NextAp
throw new Error('缺少参数');
}
const { teamId } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
const { teamId } = await authApp({ req, authToken: true, appId, per: AppLogPermissionVal });
const teamMemberWithContact = await MongoTeamMember.aggregate([
{ $match: { teamId: new Types.ObjectId(teamId) } },

View File

@@ -13,6 +13,7 @@ import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
import { type PaginationResponse } from '@fastgpt/web/common/fetch/type';
import { addSourceMember } from '@fastgpt/service/support/user/utils';
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
import { AppLogPermissionVal } from '@fastgpt/global/support/permission/app/constant';
async function handler(
req: NextApiRequest,
@@ -33,7 +34,7 @@ async function handler(
}
// 凭证校验
const { teamId } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
const { teamId } = await authApp({ req, authToken: true, appId, per: AppLogPermissionVal });
const where = {
teamId: new Types.ObjectId(teamId),