import React, { useMemo, useRef } from 'react'; import { Box, Flex, Grid, useTheme, useDisclosure, Card, MenuButton, Image, Link } from '@chakra-ui/react'; import { useRouter } from 'next/router'; import { useDatasetStore } from '@/web/core/dataset/store/dataset'; import PageContainer from '@/components/PageContainer'; import { useConfirm } from '@/web/common/hooks/useConfirm'; import { AddIcon } from '@chakra-ui/icons'; import { useQuery } from '@tanstack/react-query'; import { delDatasetById, getDatasetPaths, putDatasetById, postCreateDataset, getCheckExportLimit } from '@/web/core/dataset/api'; import { useTranslation } from 'next-i18next'; import Avatar from '@/components/Avatar'; import MyIcon from '@/components/Icon'; import { serviceSideProps } from '@/web/common/utils/i18n'; import dynamic from 'next/dynamic'; import { FolderAvatarSrc, DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant'; import Tag from '@/components/Tag'; import MyMenu from '@/components/MyMenu'; import { useRequest } from '@/web/common/hooks/useRequest'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useEditTitle } from '@/web/common/hooks/useEditTitle'; import EditFolderModal, { useEditFolder } from '../component/EditFolderModal'; import { useDrag } from '@/web/common/hooks/useDrag'; import { useUserStore } from '@/web/support/user/useUserStore'; import PermissionIconText from '@/components/support/permission/IconText'; import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant'; import { DatasetItemType } from '@fastgpt/global/core/dataset/type'; import ParentPaths from '@/components/common/ParentPaths'; const CreateModal = dynamic(() => import('./component/CreateModal'), { ssr: false }); const MoveModal = dynamic(() => import('./component/MoveModal'), { ssr: false }); const Kb = () => { const { t } = useTranslation(); const theme = useTheme(); const router = useRouter(); const { parentId } = router.query as { parentId: string }; const { setLoading } = useSystemStore(); const { userInfo } = useUserStore(); const DeleteTipsMap = useRef({ [DatasetTypeEnum.folder]: t('dataset.deleteFolderTips'), [DatasetTypeEnum.dataset]: t('dataset.deleteDatasetTips') }); const { openConfirm, ConfirmModal } = useConfirm({ title: t('common.Delete Warning'), content: '' }); const { myDatasets, loadDatasets, setDatasets, updateDataset } = useDatasetStore(); const { onOpenModal: onOpenTitleModal, EditModal: EditTitleModal } = useEditTitle({ title: t('Rename') }); const { moveDataId, setMoveDataId, dragStartId, setDragStartId, dragTargetId, setDragTargetId } = useDrag(); const { isOpen: isOpenCreateModal, onOpen: onOpenCreateModal, onClose: onCloseCreateModal } = useDisclosure(); const { editFolderData, setEditFolderData } = useEditFolder(); /* 点击删除 */ const { mutate: onclickDelDataset } = useRequest({ mutationFn: async (id: string) => { setLoading(true); await delDatasetById(id); return id; }, onSuccess(id: string) { setDatasets(myDatasets.filter((item) => item._id !== id)); }, onSettled() { setLoading(false); }, successToast: t('common.Delete Success'), errorToast: t('dataset.Delete Dataset Error') }); // check export limit const { mutate: exportDataset } = useRequest({ mutationFn: async (dataset: DatasetItemType) => { setLoading(true); await getCheckExportLimit(dataset._id); const a = document.createElement('a'); a.href = `/api/core/dataset/exportAll?datasetId=${dataset._id}`; a.download = `${dataset.name}.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); }, onSettled() { setLoading(false); }, errorToast: t('dataset.Export Dataset Limit Error') }); const { data, refetch } = useQuery(['loadDataset', parentId], () => { return Promise.all([loadDatasets(parentId), getDatasetPaths(parentId)]); }); const paths = data?.[1] || []; return ( {/* url path */} ({ parentId: path.parentId, parentName: path.parentName }))} FirstPathDom={ {''} {t('dataset.My Dataset')} } onClick={(e) => { router.push({ query: { parentId: e } }); }} /> {/* create icon */} {userInfo?.team?.canWrite && ( {t('Create New')} } menuList={[ { child: ( {''} {t('Folder')} ), onClick: () => setEditFolderData({}) }, { child: ( {''} {t('Dataset')} ), onClick: onOpenCreateModal } ]} /> )} {myDatasets.map((dataset) => ( { setDragStartId(dataset._id); }} onDragOver={(e) => { e.preventDefault(); const targetId = e.currentTarget.getAttribute('data-drag-id'); if (!targetId) return; DatasetTypeEnum.folder && setDragTargetId(targetId); }} onDragLeave={(e) => { e.preventDefault(); setDragTargetId(undefined); }} onDrop={async (e) => { e.preventDefault(); if (!dragTargetId || !dragStartId || dragTargetId === dragStartId) return; // update parentId try { await putDatasetById({ id: dragStartId, parentId: dragTargetId }); refetch(); } catch (error) {} setDragTargetId(undefined); }} _hover={{ boxShadow: '1px 1px 10px rgba(0,0,0,0.2)', borderColor: 'transparent', '& .delete': { display: 'block' } }} onClick={() => { if (dataset.type === DatasetTypeEnum.folder) { router.push({ pathname: '/dataset/list', query: { parentId: dataset._id } }); } else if (dataset.type === DatasetTypeEnum.dataset) { router.push({ pathname: '/dataset/detail', query: { datasetId: dataset._id } }); } }} > {userInfo?.team.canWrite && dataset.isOwner && ( { e.stopPropagation(); }} > } menuList={[ ...(dataset.permission === PermissionTypeEnum.private ? [ { child: ( {t('permission.Set Public')} ), onClick: () => { updateDataset({ id: dataset._id, permission: PermissionTypeEnum.public }); } } ] : [ { child: ( {t('permission.Set Private')} ), onClick: () => { updateDataset({ id: dataset._id, permission: PermissionTypeEnum.private }); } } ]), { child: ( {t('Rename')} ), onClick: () => onOpenTitleModal({ defaultVal: dataset.name, onSuccess: (val) => { if (val === dataset.name || !val) return; updateDataset({ id: dataset._id, name: val }); } }) }, { child: ( {t('Move')} ), onClick: () => setMoveDataId(dataset._id) }, { child: ( {t('Export')} ), onClick: () => { exportDataset(dataset); } }, { child: ( {t('common.Delete')} ), onClick: () => { openConfirm( () => onclickDelDataset(dataset._id), undefined, DeleteTipsMap.current[dataset.type] )(); } } ]} /> )} {dataset.name} {dataset.tags.filter(Boolean).map((tag, i) => ( {tag} ))} {dataset.type === DatasetTypeEnum.folder ? ( {t('Folder')} ) : ( <> {dataset.vectorModel.name} )} ))} {myDatasets.length === 0 && ( 还没有知识库,快去创建一个吧! )} {isOpenCreateModal && } {!!editFolderData && ( setEditFolderData(undefined)} editCallback={async (name) => { try { if (editFolderData.id) { await putDatasetById({ id: editFolderData.id, name }); } else { await postCreateDataset({ parentId, name, type: DatasetTypeEnum.folder, avatar: FolderAvatarSrc, tags: '' }); } refetch(); } catch (error) { return Promise.reject(error); } }} isEdit={!!editFolderData.id} name={editFolderData.name} /> )} {!!moveDataId && ( setMoveDataId('')} onSuccess={() => { refetch(); setMoveDataId(''); }} /> )} ); }; export async function getServerSideProps(content: any) { return { props: { ...(await serviceSideProps(content)) } }; } export default Kb;