import React, { useMemo, useRef } from 'react'; import { Box, Flex, Grid, useDisclosure, Image, Button } 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 '@fastgpt/web/hooks/useConfirm'; import { AddIcon } from '@chakra-ui/icons'; import { useQuery } from '@tanstack/react-query'; import { delDatasetById, getDatasetPaths, putDatasetById, postCreateDataset } from '@/web/core/dataset/api'; import { checkTeamExportDatasetLimit } from '@/web/support/user/team/api'; import { useTranslation } from 'next-i18next'; import Avatar from '@/components/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { serviceSideProps } from '@/web/common/utils/i18n'; import dynamic from 'next/dynamic'; import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants'; import { FolderImgUrl, FolderIcon } from '@fastgpt/global/common/file/image/constants'; import MyMenu from '@/components/MyMenu'; import { useRequest } from '@fastgpt/web/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'; import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { getToken } from '@/web/support/user/auth'; const CreateModal = dynamic(() => import('./component/CreateModal'), { ssr: false }); const MoveModal = dynamic(() => import('./component/MoveModal'), { ssr: false }); const Kb = () => { const { t } = useTranslation(); const { toast } = useToast(); 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('core.dataset.Delete Confirm'), [DatasetTypeEnum.websiteDataset]: t('core.dataset.Delete Confirm') }); const { openConfirm, ConfirmModal } = useConfirm({ type: 'delete' }); 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 checkTeamExportDatasetLimit(dataset._id); const url = `/api/core/dataset/exportAll?datasetId=${dataset._id}`; const name = `${dataset.name}.csv`; localDownLoadWithToken(url, name, getToken()); }, onSettled() { setLoading(false); }, errorToast: t('dataset.Export Dataset Limit Error') }); const localDownLoadWithToken = (url: string | URL, filename: string, token: string) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.setRequestHeader("token", token); xhr.responseType = 'blob'; xhr.onload = function (e) { if (this.status == 200) { var blob = this.response; var a = document.createElement('a'); var url = URL.createObjectURL(blob); a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); } }; xhr.send(); }; const { data, refetch, isFetching } = useQuery( ['loadDataset', parentId], () => { return Promise.all([loadDatasets(parentId), getDatasetPaths(parentId)]); }, { onError(err) { toast({ status: 'error', title: t(getErrText(err)) }); } } ); const paths = data?.[1] || []; const formatDatasets = useMemo( () => myDatasets.map((item) => { return { ...item, label: DatasetTypeMap[item.type]?.label, icon: DatasetTypeMap[item.type]?.icon }; }), [myDatasets] ); return ( {/* url path */} ({ parentId: path.parentId, parentName: path.parentName }))} FirstPathDom={ {''} {t('core.dataset.My Dataset')} } onClick={(e) => { router.push({ query: { parentId: e } }); }} /> {/* create icon */} {userInfo?.team?.canWrite && ( {t('common.Create New')} } menuList={[ { label: ( {t('Folder')} ), onClick: () => setEditFolderData({}) }, { label: ( {''} {t('core.dataset.Dataset')} ), onClick: onOpenCreateModal } ]} /> )} {formatDatasets.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={{ borderColor: 'primary.300', boxShadow: '1.5', '& .delete': { display: 'block' } }} onClick={() => { if (dataset.type === DatasetTypeEnum.folder) { router.push({ pathname: '/dataset/list', query: { parentId: dataset._id } }); } else { router.push({ pathname: '/dataset/detail', query: { datasetId: dataset._id } }); } }} > {userInfo?.team.canWrite && dataset.isOwner && ( { e.stopPropagation(); }} > } menuList={[ ...(dataset.permission === PermissionTypeEnum.private ? [ { label: ( {t('permission.Set Public')} ), onClick: () => { updateDataset({ id: dataset._id, permission: PermissionTypeEnum.public }); } } ] : [ { label: ( {t('permission.Set Private')} ), onClick: () => { updateDataset({ id: dataset._id, permission: PermissionTypeEnum.private }); } } ]), { label: ( {t('Rename')} ), onClick: () => onOpenTitleModal({ defaultVal: dataset.name, onSuccess: (val) => { if (val === dataset.name || !val) return; updateDataset({ id: dataset._id, name: val }); } }) }, { label: ( {t('Move')} ), onClick: () => setMoveDataId(dataset._id) }, { label: ( {t('Export')} ), onClick: () => { exportDataset(dataset); } }, { label: ( {t('common.Delete')} ), type: 'danger', onClick: () => { openConfirm( () => onclickDelDataset(dataset._id), undefined, DeleteTipsMap.current[dataset.type] )(); } } ]} /> )} {dataset.name} {dataset.intro || (dataset.type === DatasetTypeEnum.folder ? t('core.dataset.Folder placeholder') : t('core.dataset.Intro Placeholder'))} {dataset.type !== DatasetTypeEnum.folder && ( )} ))} {myDatasets.length === 0 && ( {t('core.dataset.Empty Dataset Tips')} )} {isOpenCreateModal && } {!!editFolderData && ( setEditFolderData(undefined)} editCallback={async (name) => { try { await postCreateDataset({ parentId, name, type: DatasetTypeEnum.folder, avatar: FolderImgUrl, intro: '' }); refetch(); } catch (error) { return Promise.reject(error); } }} isEdit={false} /> )} {!!moveDataId && ( setMoveDataId('')} onSuccess={() => { refetch(); setMoveDataId(''); }} /> )} ); }; export async function getServerSideProps(content: any) { return { props: { ...(await serviceSideProps(content)) } }; } export default Kb;