* fix: remove DefaultTeam (#4037) * fix :Get application bound knowledge base information logical rewrite (#4057) * fix :Get application bound knowledge base information logical rewrite * fix :Get application bound knowledge base information logical rewrite * fix :Get application bound knowledge base information logical rewrite * fix :Get application bound knowledge base information logical rewrite * update package * fix: import dataset step error;perf: ai proxy avatar (#4074) * perf: pg config params * perf: ai proxy avatar * fix: import dataset step error * feat: data input ux * perf: app dataset rewite * fix: 文本提取不支持arrayString,arrayNumber等jsonSchema (#4079) * update doc ;perf: model test (#4098) * perf: extract array * update doc * perf: model test * perf: model test * perf: think tag parse (#4102) * chat quote reader (#3912) * init chat quote full text reader * linked structure * dataset data linked * optimize code * fix ts build * test finish * delete log * fix * fix ts * fix ts * remove nextId * initial scroll * fix * fix * perf: chunk read (#4109) * package * perf: chunk read * feat: api dataset support pdf parse;fix: chunk reader auth (#4117) * feat: api dataset support pdf parse * fix: chunk reader auth * feat: invitation link (#3979) * feat: invitation link schema and apis * feat: add invitation link * feat: member status: active, leave, forbidden * fix: expires show hours and minutes * feat: invalid invitation link hint * fix: typo * chore: fix typo & i18n * fix * pref: fe * feat: add ttl index for 30-day-clean-up * perf: invite member code (#4118) * perf: invite member code * fix: ts * fix: model test channel id;fix: quote reader (#4123) * fix: model test channel id * fix: quote reader * fix chat quote reader (#4125) * perf: model test;perf: sidebar trigger (#4127) * fix: import dataset step error;perf: ai proxy avatar (#4074) * perf: pg config params * perf: ai proxy avatar * fix: import dataset step error * feat: data input ux * perf: app dataset rewite * perf: model test * perf: sidebar trigger * lock * update nanoid version * fix: select component ux * fix: ts * fix: vitest * remove test * fix: prompt toolcall ui (#4139) * load log error adapt * fix: prompt toolcall ui * perf: commercial function tip * update package * pref: copy link (#4147) * fix(i18n): namespace (#4143) * hiden dataset source (#4152) * hiden dataset source * perf: reader * chore: move all tests into a single folder (#4160) * fix modal close scroll (#4162) * fix modal close scroll * update refresh * feat: rerank modal select and weight (#4164) * fix loadInitData refresh (#4169) * fix * fix * form input number default & api dataset max token * feat: mix search weight (#4170) * feat: mix search weight * feat: svg render * fix: avatar error remove (#4173) * fix: avatar error remove * fix: index * fix: guide * fix: auth * update package;fix: input data model ui (#4181) * update package * fix: ts * update config * update jieba package * add type sign * fix: input data ui * fix: page title refresh (#4186) * fix: ts * update jieba package * fix: page title refresh * fix: remove member length check when opening invite create modal (#4193) * add env to check internal ip (#4187) * fix: ts * update jieba package * add env to check internal ip * package * fix: jieba * reset package * update config * fix: jieba package * init shell * init version * change team reload * update jieba package (#4200) * update jieba package * package * update package * remove invalid code * action * package (#4201) * package * update package * remove invalid code * package * remove i18n tip (#4202) * doc (#4205) * fix: i18n (#4208) * fix: next config (#4207) * reset package * i18n * update config * i18n * remove log --------- Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com> Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com> Co-authored-by: shilin <39396378+shilin66@users.noreply.github.com> Co-authored-by: heheer <heheer@sealos.io>
279 lines
10 KiB
TypeScript
279 lines
10 KiB
TypeScript
import MemberTag from '@/components/support/user/team/Info/MemberTag';
|
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
|
import { getInvitationLinkList, putUpdateInvitationInfo } from '@/web/support/user/team/api';
|
|
import { useUserStore } from '@/web/support/user/useUserStore';
|
|
import {
|
|
Box,
|
|
Button,
|
|
Divider,
|
|
Flex,
|
|
Grid,
|
|
HStack,
|
|
ModalBody,
|
|
ModalFooter,
|
|
Table,
|
|
TableContainer,
|
|
Tbody,
|
|
Td,
|
|
Th,
|
|
Thead,
|
|
Tr,
|
|
useDisclosure
|
|
} from '@chakra-ui/react';
|
|
import AvatarGroup from '@fastgpt/web/components/common/Avatar/AvatarGroup';
|
|
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
|
import Icon from '@fastgpt/web/components/common/Icon';
|
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
|
import MyPopover from '@fastgpt/web/components/common/MyPopover';
|
|
import Tag from '@fastgpt/web/components/common/Tag';
|
|
import { useCopyData } from '@fastgpt/web/hooks/useCopyData';
|
|
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
|
import format from 'date-fns/format';
|
|
import { useTranslation } from 'next-i18next';
|
|
import dynamic from 'next/dynamic';
|
|
import { useCallback } from 'react';
|
|
|
|
const CreateInvitationModal = dynamic(() => import('./CreateInvitationModal'));
|
|
|
|
const InviteModal = ({
|
|
teamId,
|
|
onClose,
|
|
onSuccess
|
|
}: {
|
|
teamId: string;
|
|
onClose: () => void;
|
|
onSuccess: () => void;
|
|
}) => {
|
|
const { t } = useTranslation();
|
|
|
|
const {
|
|
data: invitationLinkList,
|
|
loading: isLoadingLink,
|
|
runAsync: refetchInvitationLinkList
|
|
} = useRequest2(() => getInvitationLinkList(), {
|
|
manual: false
|
|
});
|
|
|
|
const { isOpen: isOpenCreate, onOpen: onOpenCreate, onClose: onCloseCreate } = useDisclosure();
|
|
|
|
const isLoading = isLoadingLink;
|
|
const { copyData } = useCopyData();
|
|
const { userInfo } = useUserStore();
|
|
const { feConfigs } = useSystemStore();
|
|
|
|
const onCopy = useCallback(
|
|
(linkId: string) => {
|
|
const url = location.origin + `/account/team?invitelinkid=${linkId}`;
|
|
const teamName = userInfo?.team.teamName;
|
|
const systemName = feConfigs.systemTitle;
|
|
const userName = userInfo?.team.memberName;
|
|
copyData(
|
|
t('account_team:invitation_copy_link', {
|
|
teamName,
|
|
systemName,
|
|
userName,
|
|
url
|
|
})
|
|
);
|
|
},
|
|
[copyData]
|
|
);
|
|
|
|
const { runAsync: onForbid, loading: forbiding } = useRequest2(
|
|
(linkId: string) =>
|
|
putUpdateInvitationInfo({
|
|
linkId,
|
|
forbidden: true
|
|
}),
|
|
{
|
|
manual: true,
|
|
onSuccess: refetchInvitationLinkList,
|
|
successToast: t('account_team:forbid_success')
|
|
}
|
|
);
|
|
|
|
return (
|
|
<MyModal
|
|
isLoading={isLoading}
|
|
isOpen
|
|
iconSrc="common/inviteLight"
|
|
iconColor="primary.600"
|
|
title={t('account_team:invite_member')}
|
|
overflow={'unset'}
|
|
onClose={onClose}
|
|
w={'100%'}
|
|
maxW={['90vw', '820px']}
|
|
>
|
|
<ModalBody maxH="500px">
|
|
<Flex alignItems={'center'} justifyContent={'space-between'} mb={4}>
|
|
<HStack>
|
|
<Icon name="common/list" w="16px" />
|
|
<Box ml="6px" fontSize="md">
|
|
{t('account_team:invitation_link_list')}
|
|
</Box>
|
|
</HStack>
|
|
<Button onClick={onOpenCreate}>{t('account_team:create_invitation_link')}</Button>
|
|
</Flex>
|
|
<TableContainer overflowY={'auto'}>
|
|
<Table fontSize={'sm'} overflow={'unset'}>
|
|
<Thead>
|
|
<Tr bgColor={'white !important'}>
|
|
<Th borderLeftRadius="6px" bgColor="myGray.100">
|
|
{t('account_team:invitation_link_description')}
|
|
</Th>
|
|
<Th bgColor="myGray.100">{t('account_team:expires')}</Th>
|
|
<Th bgColor="myGray.100">{t('account_team:used_times_limit')}</Th>
|
|
<Th bgColor="myGray.100">{t('account_team:invited')}</Th>
|
|
<Th bgColor="myGray.100" borderRightRadius="6px">
|
|
{t('common:common.Action')}
|
|
</Th>
|
|
</Tr>
|
|
</Thead>
|
|
{!!invitationLinkList?.length && (
|
|
<Tbody overflow={'unset'}>
|
|
{invitationLinkList?.map((item) => {
|
|
const isForbidden = item.forbidden || new Date(item.expires) < new Date();
|
|
return (
|
|
<Tr key={item._id} overflow={'unset'}>
|
|
<Td maxW="200px" minW="100px">
|
|
{item.description}
|
|
</Td>
|
|
<Td>
|
|
{isForbidden ? (
|
|
<Tag colorSchema="gray">{t('account_team:has_forbidden')}</Tag>
|
|
) : (
|
|
format(new Date(item.expires), 'yyyy-MM-dd HH:mm')
|
|
)}
|
|
</Td>
|
|
<Td>
|
|
{item.usedTimesLimit === -1
|
|
? t('account_team:unlimited')
|
|
: item.usedTimesLimit}
|
|
</Td>
|
|
<Td>
|
|
{item.members.length > 0 && (
|
|
<MyPopover
|
|
w="fit-content"
|
|
Trigger={
|
|
<Box
|
|
borderRadius="md"
|
|
cursor="pointer"
|
|
_hover={{ bg: 'myGray.100' }}
|
|
p="1.5"
|
|
w="fit-content"
|
|
>
|
|
<AvatarGroup max={3} avatars={item.members.map((i) => i.avatar)} />
|
|
</Box>
|
|
}
|
|
trigger="click"
|
|
closeOnBlur={true}
|
|
>
|
|
{() => (
|
|
<Box py="4" maxH="200px" w="fit-content">
|
|
<Flex mx="4" justifyContent="center" alignItems={'center'}>
|
|
<Box>{t('account_team:has_invited')}</Box>
|
|
<Box
|
|
ml="auto"
|
|
bg="myGray.200"
|
|
px="2"
|
|
borderRadius="md"
|
|
fontSize="sm"
|
|
>
|
|
{item.members.length}
|
|
</Box>
|
|
</Flex>
|
|
<Divider my="2" mx="4" />
|
|
<Grid
|
|
w="fit-content"
|
|
mt="2"
|
|
gridRowGap="4"
|
|
gridTemplateColumns="1fr 1fr"
|
|
overflow="auto"
|
|
alignItems="center"
|
|
mx="4"
|
|
>
|
|
{item.members.map((member) => (
|
|
<Box key={member.tmbId} justifySelf="start">
|
|
<MemberTag name={member.name} avatar={member.avatar} />
|
|
</Box>
|
|
))}
|
|
</Grid>
|
|
</Box>
|
|
)}
|
|
</MyPopover>
|
|
)}
|
|
</Td>
|
|
<Td>
|
|
{!isForbidden && (
|
|
<>
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
onClick={() => onCopy(item._id)}
|
|
color="myGray.900"
|
|
>
|
|
<Icon name="common/link" w="16px" mr="1" />
|
|
{t('account_team:copy_link')}
|
|
</Button>
|
|
<MyPopover
|
|
placement="bottom-end"
|
|
Trigger={
|
|
<Button variant="outline" ml="10px" size="sm" color="myGray.900">
|
|
<Icon name="common/lineStop" w="16px" mr="1" />
|
|
{t('account_team:forbidden')}
|
|
</Button>
|
|
}
|
|
closeOnBlur={true}
|
|
>
|
|
{({ onClose: onClosePopover }) => (
|
|
<Box p={4}>
|
|
<Box fontWeight={400} whiteSpace="pre-wrap">
|
|
{t('account_team:forbid_hint')}
|
|
</Box>
|
|
<Flex gap={2} mt={2} justifyContent={'flex-end'}>
|
|
<Button variant="outline" onClick={onClosePopover}>
|
|
{t('common:common.Cancel')}
|
|
</Button>
|
|
<Button
|
|
isLoading={forbiding}
|
|
variant="outline"
|
|
colorScheme="red"
|
|
onClick={() => {
|
|
onForbid(item._id);
|
|
onClosePopover();
|
|
}}
|
|
>
|
|
{t('account_team:confirm_forbidden')}
|
|
</Button>
|
|
</Flex>
|
|
</Box>
|
|
)}
|
|
</MyPopover>
|
|
</>
|
|
)}
|
|
</Td>
|
|
</Tr>
|
|
);
|
|
})}
|
|
</Tbody>
|
|
)}
|
|
</Table>
|
|
{!invitationLinkList?.length && <EmptyTip />}
|
|
</TableContainer>
|
|
</ModalBody>
|
|
<ModalFooter justifyContent={'flex-start'}>
|
|
<Tag colorSchema="blue" marginBlock="2">
|
|
<Box>{t('account_team:invitation_link_auto_clean_hint')}</Box>
|
|
</Tag>
|
|
</ModalFooter>
|
|
{isOpenCreate && (
|
|
<CreateInvitationModal
|
|
onClose={() => Promise.all([onCloseCreate(), refetchInvitationLinkList()])}
|
|
/>
|
|
)}
|
|
</MyModal>
|
|
);
|
|
};
|
|
|
|
export default InviteModal;
|