Permission (#1687)

Co-authored-by: Archer <545436317@qq.com>
Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
Archer
2024-06-04 17:52:00 +08:00
committed by GitHub
parent fcb915c988
commit 19c8a06d51
109 changed files with 2291 additions and 1091 deletions

View File

@@ -0,0 +1,243 @@
import {
ButtonProps,
Flex,
Menu,
MenuButton,
MenuList,
Box,
Radio,
useOutsideClick
} from '@chakra-ui/react';
import React, { useMemo, useRef, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { PermissionValueType } from '@fastgpt/global/support/permission/type';
import { useContextSelector } from 'use-context-selector';
import { Permission } from '@fastgpt/global/support/permission/controller';
import { CollaboratorContext } from './context';
import { useTranslation } from 'next-i18next';
import MyDivider from '@fastgpt/web/components/common/MyDivider';
export type PermissionSelectProps = {
value?: PermissionValueType;
onChange: (value: PermissionValueType) => void;
trigger?: 'hover' | 'click';
offset?: [number, number];
Button: React.ReactNode;
onDelete?: () => void;
} & Omit<ButtonProps, 'onChange' | 'value'>;
const MenuStyle = {
py: 2,
px: 3,
_hover: {
bg: 'myGray.50'
},
borderRadius: 'md',
cursor: 'pointer',
fontSize: 'sm'
};
function PermissionSelect({
value,
onChange,
trigger = 'click',
offset = [0, 5],
Button,
width = 'auto',
onDelete,
...props
}: PermissionSelectProps) {
const { t } = useTranslation();
const { permissionList } = useContextSelector(CollaboratorContext, (v) => v);
const ref = useRef<HTMLDivElement>(null);
const closeTimer = useRef<any>();
const [isOpen, setIsOpen] = useState(false);
const permissionSelectList = useMemo(() => {
const list = Object.entries(permissionList).map(([key, value]) => {
return {
name: value.name,
value: value.value,
description: value.description,
checkBoxType: value.checkBoxType
};
});
return {
singleCheckBoxList: list.filter((item) => item.checkBoxType === 'single'),
multipleCheckBoxList: list.filter((item) => item.checkBoxType === 'multiple')
};
}, [permissionList]);
const selectedSingleValue = useMemo(() => {
const per = new Permission({ per: value });
if (per.hasManagePer) return permissionList['manage'].value;
if (per.hasWritePer) return permissionList['write'].value;
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]);
useOutsideClick({
ref: ref,
handler: () => {
setIsOpen(false);
}
});
return (
<Menu offset={offset} isOpen={isOpen} autoSelect={false} direction={'ltr'}>
<Box
ref={ref}
onMouseEnter={() => {
if (trigger === 'hover') {
setIsOpen(true);
}
clearTimeout(closeTimer.current);
}}
onMouseLeave={() => {
if (trigger === 'hover') {
closeTimer.current = setTimeout(() => {
setIsOpen(false);
}, 100);
}
}}
>
<Box
position={'relative'}
onClickCapture={() => {
if (trigger === 'click') {
setIsOpen(!isOpen);
}
}}
>
<MenuButton
w={'100%'}
h={'100%'}
position={'absolute'}
top={0}
right={0}
bottom={0}
left={0}
/>
<Box position={'relative'} cursor={'pointer'} userSelect={'none'}>
{Button}
</Box>
</Box>
<MenuList
minW={isOpen ? `${width}px !important` : 0}
p="3"
border={'1px solid #fff'}
boxShadow={
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
}
zIndex={99}
overflowY={'auto'}
>
{/* The list of single select permissions */}
{permissionSelectList.singleCheckBoxList.map((item) => {
const change = () => {
const per = new Permission({ per: value });
per.removePer(selectedSingleValue);
per.addPer(item.value);
onChange(per.value);
setIsOpen(false);
};
return (
<Flex
key={item.value}
{...(selectedSingleValue === item.value
? {
color: 'primary.600'
}
: {})}
{...MenuStyle}
onClick={change}
maxW={['70vw', '300px']}
>
<Radio size="lg" isChecked={selectedSingleValue === item.value} />
<Box ml={4}>
<Box>{item.name}</Box>
<Box color={'myGray.500'}>{item.description}</Box>
</Box>
</Flex>
);
})}
{/* <MyDivider my={3} />
{multipleValues.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>
</Flex>
);
})}*/}
{onDelete && (
<>
<MyDivider my={2} h={'2px'} borderColor={'myGray.200'} />
<Flex
{...MenuStyle}
onClick={() => {
onDelete();
setIsOpen(false);
}}
>
<MyIcon name="delete" w="20px" color="red.600" />
<Box color="red.600">{t('common.Delete')}</Box>
</Flex>
</>
)}
</MenuList>
</Box>
</Menu>
);
}
export default React.memo(PermissionSelect);