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:
@@ -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);
|
||||
Reference in New Issue
Block a user