Dataset frontend style adjusting (#1820)

* feat: dataset controllers

feat: dataset schema

fix: add missing type to dataset schema
Signed-off-by: FinleyGe <m13203533462@163.com>

* chore: use new auth method

Signed-off-by: FinleyGe <m13203533462@163.com>

* feat: finish the dataset permission

fix: ts errors
Signed-off-by: FinleyGe <m13203533462@163.com>

* chore: adjust the code

* chore: adjust the code

* chore: dataset fe adjusting

* fix: double delete confirm

---------

Signed-off-by: FinleyGe <m13203533462@163.com>
This commit is contained in:
Finley Ge
2024-06-24 14:58:44 +08:00
committed by GitHub
parent a9ab9ebe8e
commit 4a33e04a08
11 changed files with 12200 additions and 9324 deletions

View File

@@ -15,11 +15,11 @@
"@chakra-ui/cli": "^2.4.1", "@chakra-ui/cli": "^2.4.1",
"husky": "^8.0.3", "husky": "^8.0.3",
"i18next": "23.10.0", "i18next": "23.10.0",
"lint-staged": "^13.2.1", "lint-staged": "^13.3.0",
"next-i18next": "15.2.0", "next-i18next": "15.2.0",
"prettier": "3.2.4", "prettier": "3.2.4",
"react-i18next": "13.5.0", "react-i18next": "13.5.0",
"zhlint": "^0.7.1" "zhlint": "^0.7.4"
}, },
"lint-staged": { "lint-staged": {
"./**/**/*.{ts,tsx,scss}": "npm run format-code", "./**/**/*.{ts,tsx,scss}": "npm run format-code",

View File

@@ -1,11 +1,12 @@
import { DatasetDataIndexItemType, DatasetSchemaType } from './type'; import { DatasetDataIndexItemType, DatasetSchemaType } from './type';
import { TrainingModeEnum, DatasetCollectionTypeEnum } from './constants'; import { TrainingModeEnum, DatasetCollectionTypeEnum } from './constants';
import type { LLMModelItemType } from '../ai/model.d'; import type { LLMModelItemType } from '../ai/model.d';
import { ParentIdType } from 'common/parentFolder/type';
/* ================= dataset ===================== */ /* ================= dataset ===================== */
export type DatasetUpdateBody = { export type DatasetUpdateBody = {
id: string; id: string;
parentId?: string; parentId?: ParentIdType;
name?: string; name?: string;
avatar?: string; avatar?: string;
intro?: string; intro?: string;

View File

@@ -1128,6 +1128,7 @@
"Create Folder": "Create Folder", "Create Folder": "Create Folder",
"Create manual collection": "Create manual collection", "Create manual collection": "Create manual collection",
"Delete Dataset Error": "Delete Dataset Error", "Delete Dataset Error": "Delete Dataset Error",
"Edit Info": "Edit Information",
"Edit Folder": "Edit Folder", "Edit Folder": "Edit Folder",
"Export": "Export", "Export": "Export",
"Export Dataset Limit Error": "Export Dataset Error", "Export Dataset Limit Error": "Export Dataset Error",

View File

@@ -1137,6 +1137,7 @@
"Create Folder": "创建文件夹", "Create Folder": "创建文件夹",
"Create manual collection": "创建手动数据集", "Create manual collection": "创建手动数据集",
"Delete Dataset Error": "删除知识库异常", "Delete Dataset Error": "删除知识库异常",
"Edit Info": "编辑信息",
"Edit Folder": "编辑文件夹", "Edit Folder": "编辑文件夹",
"Export": "导出", "Export": "导出",
"Export Dataset Limit Error": "导出数据失败", "Export Dataset Limit Error": "导出数据失败",

21047
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@ import {
} from '@fastgpt/global/support/permission/constant'; } from '@fastgpt/global/support/permission/constant';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema'; import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils'; import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
import { DatasetDefaultPermission } from '@fastgpt/global/support/permission/dataset/constant';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const { parentId, type } = req.query as { parentId?: string; type?: DatasetTypeEnum }; const { parentId, type } = req.query as { parentId?: string; type?: DatasetTypeEnum };
@@ -71,7 +72,7 @@ async function handler(req: NextApiRequest) {
type: item.type, type: item.type,
permission: item.permission, permission: item.permission,
vectorModel: getVectorModel(item.vectorModel), vectorModel: getVectorModel(item.vectorModel),
defaultPermission: item.defaultPermission defaultPermission: item.defaultPermission ?? DatasetDefaultPermission
})) }))
); );

View File

@@ -59,7 +59,7 @@ const Detail = ({ datasetId, currentTab }: Props) => {
<Slider currentTab={currentTab} /> <Slider currentTab={currentTab} />
{!!datasetDetail._id && ( {!!datasetDetail._id && (
<Box flex={'1 0 0'} pb={0}> <Box flex={'1 0 0'} pb={0} overflow={'auto'}>
{currentTab === TabEnum.collectionCard && ( {currentTab === TabEnum.collectionCard && (
<CollectionPageContextProvider> <CollectionPageContextProvider>
<CollectionCard /> <CollectionCard />

View File

@@ -1,23 +1,30 @@
import { useDrag } from '@/web/common/hooks/useDrag'; import React, { useMemo, useRef, useState } from 'react';
import { delDatasetById, getDatasetById, putDatasetById } from '@/web/core/dataset/api'; import {
delDatasetById,
getDatasetById,
putDatasetById,
postCreateDataset
} from '@/web/core/dataset/api';
import { EditFolderFormType } from '@fastgpt/web/components/common/MyModal/EditFolderModal';
import { FolderImgUrl } from '@fastgpt/global/common/file/image/constants';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useDatasetStore } from '@/web/core/dataset/store/dataset'; import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { Box, Flex, Grid } from '@chakra-ui/react'; import { FolderIcon } from '@fastgpt/global/common/file/image/constants';
import { Box, Flex, Grid, Button, Image, useDisclosure } from '@chakra-ui/react';
import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants'; import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
import MyMenu from '@fastgpt/web/components/common/MyMenu'; import MyMenu from '@fastgpt/web/components/common/MyMenu';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import React, { useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import PermissionIconText from '@/components/support/permission/IconText'; import PermissionIconText from '@/components/support/permission/IconText';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag'; import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { DatasetItemType } from '@fastgpt/global/core/dataset/type'; import { DatasetItemType } from '@fastgpt/global/core/dataset/type';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useToast } from '@fastgpt/web/hooks/useToast'; import { useToast } from '@fastgpt/web/hooks/useToast';
import { checkTeamExportDatasetLimit } from '@/web/support/user/team/api'; import { checkTeamExportDatasetLimit } from '@/web/support/user/team/api';
import { downloadFetch } from '@/web/common/system/utils'; import { downloadFetch } from '@/web/common/system/utils';
import { useTranslation } from 'next-i18next';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { EditResourceInfoFormType } from '@/components/common/Modal/EditResourceModal'; import { EditResourceInfoFormType } from '@/components/common/Modal/EditResourceModal';
@@ -34,18 +41,53 @@ import {
postUpdateDatasetCollaborators postUpdateDatasetCollaborators
} from '@/web/core/dataset/api/collaborator'; } from '@/web/core/dataset/api/collaborator';
import FolderSlideCard from '@/components/common/folder/SlideCard'; import FolderSlideCard from '@/components/common/folder/SlideCard';
import { useQuery } from '@tanstack/react-query';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import { useFolderDrag } from '@/components/common/folder/useFolderDrag';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { useI18n } from '@/web/context/I18n';
import { useTranslation } from 'react-i18next';
import { AddIcon } from '@chakra-ui/icons';
const MoveModal = dynamic(() => import('./MoveModal'), { ssr: false }); const CreateModal = dynamic(() => import('./CreateModal'));
const EditFolderModal = dynamic(
() => import('@fastgpt/web/components/common/MyModal/EditFolderModal')
);
function List() { function List() {
const { setLoading, isPc } = useSystemStore(); const { setLoading, isPc } = useSystemStore();
const { toast } = useToast(); const { toast } = useToast();
const { t } = useTranslation(); const { t } = useTranslation();
const { refetch } = useContextSelector(DatasetContext, (v) => v); const { commonT } = useI18n();
const { refetchDatasets, setMoveDatasetId, refetchPaths } = useContextSelector(
DatasetContext,
(v) => v
);
const [editPerDatasetIndex, setEditPerDatasetIndex] = useState<number>(); const [editPerDatasetIndex, setEditPerDatasetIndex] = useState<number>();
const { myDatasets, loadMyDatasets, setMyDatasets } = useDatasetStore(); const { myDatasets, loadMyDatasets, setMyDatasets } = useDatasetStore();
const { userInfo } = useUserStore();
const {
isOpen: isOpenCreateModal,
onOpen: onOpenCreateModal,
onClose: onCloseCreateModal
} = useDisclosure();
const { getBoxProps } = useFolderDrag({
activeStyles: {
borderColor: 'primary.600'
},
onDrop: async (dragId: string, targetId: string) => {
setLoading(true);
try {
await putDatasetById({
id: dragId,
parentId: targetId
});
refetchDatasets();
} catch (error) {}
setLoading(false);
}
});
const editPerDataset = useMemo( const editPerDataset = useMemo(
() => (editPerDatasetIndex !== undefined ? myDatasets[editPerDatasetIndex] : undefined), () => (editPerDatasetIndex !== undefined ? myDatasets[editPerDatasetIndex] : undefined),
@@ -54,11 +96,14 @@ function List() {
const router = useRouter(); const router = useRouter();
const { parentId } = router.query as { parentId: string }; const { parentId = null } = router.query as { parentId?: string | null };
const { data: folderDetail, refetch: refetchFolderDetail } = useQuery( const { data: folderDetail, runAsync: refetchFolderDetail } = useRequest2(
['folderDetail', parentId, myDatasets], () => (parentId ? getDatasetById(parentId) : Promise.resolve(undefined)),
() => (parentId ? getDatasetById(parentId) : undefined) {
manual: false,
refreshDeps: [parentId, myDatasets]
}
); );
const { mutate: exportDataset } = useRequest({ const { mutate: exportDataset } = useRequest({
@@ -83,7 +128,7 @@ function List() {
errorToast: t('dataset.Export Dataset Limit Error') errorToast: t('dataset.Export Dataset Limit Error')
}); });
const { mutate: onclickDelDataset } = useRequest({ const { mutate: onDelDataset } = useRequest({
mutationFn: async (id: string) => { mutationFn: async (id: string) => {
setLoading(true); setLoading(true);
await delDatasetById(id); await delDatasetById(id);
@@ -91,6 +136,7 @@ function List() {
}, },
onSuccess(id: string) { onSuccess(id: string) {
setMyDatasets(myDatasets.filter((item) => item._id !== id)); setMyDatasets(myDatasets.filter((item) => item._id !== id));
router.push('/dataset/list');
}, },
onSettled() { onSettled() {
setLoading(false); setLoading(false);
@@ -109,9 +155,6 @@ function List() {
[DatasetTypeEnum.externalFile]: t('core.dataset.Delete Confirm') [DatasetTypeEnum.externalFile]: t('core.dataset.Delete Confirm')
}); });
const { moveDataId, setMoveDataId, dragStartId, setDragStartId, dragTargetId, setDragTargetId } =
useDrag();
const formatDatasets = useMemo( const formatDatasets = useMemo(
() => () =>
myDatasets.map((item) => { myDatasets.map((item) => {
@@ -128,17 +171,25 @@ function List() {
type: 'delete' type: 'delete'
}); });
const onDeleteDataset = (id: string) => { const onClickDeleteDataset = (id: string) => {
openConfirm( openConfirm(
() => onclickDelDataset(id), () => onDelDataset(id),
undefined, undefined,
DeleteTipsMap.current[DatasetTypeEnum.dataset] DeleteTipsMap.current[DatasetTypeEnum.dataset]
)(); )();
}; };
const [editFolderData, setEditFolderData] = useState<EditFolderFormType>();
return ( return (
<> <>
<Flex> <Flex
{...(parentId
? {
px: '8'
}
: {})}
>
{formatDatasets.length > 0 && ( {formatDatasets.length > 0 && (
<Grid <Grid
flexGrow={1} flexGrow={1}
@@ -158,46 +209,21 @@ function List() {
</Flex> </Flex>
} }
> >
<Box <MyBox
display={'flex'} display={'flex'}
flexDirection={'column'} flexDirection={'column'}
py={3} py={3}
px={5} px={5}
cursor={'pointer'} cursor={'pointer'}
borderWidth={1.5} borderWidth={1.5}
borderColor={dragTargetId === dataset._id ? 'primary.600' : 'borderColor.low'}
bg={'white'} bg={'white'}
borderRadius={'md'} borderRadius={'md'}
minH={'130px'} minH={'130px'}
position={'relative'} position={'relative'}
data-drag-id={dataset.type === DatasetTypeEnum.folder ? dataset._id : undefined} {...getBoxProps({
draggable dataId: dataset._id,
onDragStart={() => { isFolder: dataset.type === DatasetTypeEnum.folder
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={{ _hover={{
borderColor: 'primary.300', borderColor: 'primary.300',
boxShadow: '1.5', boxShadow: '1.5',
@@ -229,10 +255,10 @@ function List() {
{dataset.permission.hasWritePer && ( {dataset.permission.hasWritePer && (
<Box <Box
className="more" className="more"
display="none" display={['', 'none']}
position={'absolute'} position={'absolute'}
top={3} top={3.5}
right={3} right={4}
borderRadius={'md'} borderRadius={'md'}
_hover={{ _hover={{
color: 'primary.500', color: 'primary.500',
@@ -276,9 +302,20 @@ function List() {
{ {
icon: 'common/file/move', icon: 'common/file/move',
label: t('Move'), label: t('Move'),
onClick: () => setMoveDataId(dataset._id) onClick: () => setMoveDatasetId(dataset._id)
}, },
...(dataset.type !== DatasetTypeEnum.folder
? [
{
icon: 'export',
label: t('Export'),
onClick: () => {
exportDataset(dataset);
}
}
]
: []),
...(dataset.permission.hasManagePer ...(dataset.permission.hasManagePer
? [ ? [
{ {
@@ -309,13 +346,7 @@ function List() {
icon: 'delete', icon: 'delete',
label: t('common.Delete'), label: t('common.Delete'),
type: 'danger' as 'danger', type: 'danger' as 'danger',
onClick: () => { onClick: () => onClickDeleteDataset(dataset._id)
openConfirm(
() => onclickDelDataset(dataset._id),
undefined,
DeleteTipsMap.current[dataset.type]
)();
}
} }
] ]
} }
@@ -356,7 +387,7 @@ function List() {
<DatasetTypeTag type={dataset.type} py={1} px={2} /> <DatasetTypeTag type={dataset.type} py={1} px={2} />
)} )}
</Flex> </Flex>
</Box> </MyBox>
</MyTooltip> </MyTooltip>
))} ))}
</Grid> </Grid>
@@ -364,6 +395,44 @@ function List() {
{myDatasets.length === 0 && ( {myDatasets.length === 0 && (
<EmptyTip pt={'35vh'} text={t('core.dataset.Empty Dataset Tips')} flexGrow="1"></EmptyTip> <EmptyTip pt={'35vh'} text={t('core.dataset.Empty Dataset Tips')} flexGrow="1"></EmptyTip>
)} )}
{userInfo?.team?.permission.hasWritePer && (
<MyMenu
offset={[-30, 5]}
width={120}
Button={
<Button variant={'primaryOutline'} px={0}>
<Flex alignItems={'center'} px={'20px'}>
<AddIcon mr={2} />
<Box>{t('common.Create New')}</Box>
</Flex>
</Button>
}
menuList={[
{
children: [
{
label: (
<Flex>
<MyIcon name={FolderIcon} w={'20px'} mr={1} />
{t('Folder')}
</Flex>
),
onClick: () => setEditFolderData({})
},
{
label: (
<Flex>
<Image src={'/imgs/workflow/db.png'} alt={''} w={'20px'} mr={1} />
{t('core.dataset.Dataset')}
</Flex>
),
onClick: onOpenCreateModal
}
]
}
]}
/>
)}
{!!folderDetail && isPc && ( {!!folderDetail && isPc && (
<Box pt={[4, 6]} ml={[4, 6]}> <Box pt={[4, 6]} ml={[4, 6]}>
@@ -378,9 +447,9 @@ function List() {
intro: folderDetail.intro intro: folderDetail.intro
}); });
}} }}
onMove={() => setMoveDataId(folderDetail._id)} onMove={() => setMoveDatasetId(folderDetail._id)}
deleteTip={t('dataset.deleteFolderTips')} deleteTip={t('dataset.deleteFolderTips')}
onDelete={() => onDeleteDataset(folderDetail._id)} onDelete={() => onDelDataset(folderDetail._id)}
defaultPer={{ defaultPer={{
value: folderDetail.defaultPermission, value: folderDetail.defaultPermission,
defaultValue: DatasetDefaultPermission, defaultValue: DatasetDefaultPermission,
@@ -424,7 +493,7 @@ function List() {
{editedDataset && ( {editedDataset && (
<EditResourceModal <EditResourceModal
{...editedDataset} {...editedDataset}
title={''} title={commonT('dataset.Edit Info')}
onClose={() => setEditedDataset(undefined)} onClose={() => setEditedDataset(undefined)}
onEdit={async (data) => { onEdit={async (data) => {
await putDatasetById({ await putDatasetById({
@@ -433,25 +502,14 @@ function List() {
intro: data.intro, intro: data.intro,
avatar: data.avatar avatar: data.avatar
}); });
loadMyDatasets(parentId); loadMyDatasets(parentId ? parentId : undefined);
refetchFolderDetail(); refetchFolderDetail();
refetchPaths();
setEditedDataset(undefined); setEditedDataset(undefined);
}} }}
/> />
)} )}
{!!moveDataId && (
<MoveModal
moveDataId={moveDataId}
onClose={() => setMoveDataId('')}
onSuccess={() => {
refetch();
refetchFolderDetail();
setMoveDataId('');
}}
/>
)}
{!!editPerDataset && ( {!!editPerDataset && (
<ConfigPerModal <ConfigPerModal
avatar={editPerDataset.avatar} avatar={editPerDataset.avatar}
@@ -464,7 +522,7 @@ function List() {
id: editPerDataset._id, id: editPerDataset._id,
defaultPermission: e defaultPermission: e
}); });
refetch(); refetchDatasets();
} }
}} }}
managePer={{ managePer={{
@@ -493,6 +551,42 @@ function List() {
onClose={() => setEditPerDatasetIndex(undefined)} onClose={() => setEditPerDatasetIndex(undefined)}
/> />
)} )}
{!!editFolderData && (
<EditFolderModal
onClose={() => setEditFolderData(undefined)}
onCreate={async ({ name }) => {
try {
await postCreateDataset({
parentId: parentId || undefined,
name,
type: DatasetTypeEnum.folder,
avatar: FolderImgUrl,
intro: ''
});
refetchDatasets();
refetchPaths();
} catch (error) {
return Promise.reject(error);
}
}}
onEdit={async ({ name, intro, id }) => {
try {
await putDatasetById({
id,
name,
intro
});
refetchDatasets();
refetchPaths();
} catch (error) {
return Promise.reject(error);
}
}}
/>
)}
{isOpenCreateModal && (
<CreateModal onClose={onCloseCreateModal} parentId={parentId || undefined} />
)}
</> </>
); );
} }

View File

@@ -1,58 +1,109 @@
import { getDatasetPaths } from '@/web/core/dataset/api'; import { getDatasetPaths, putDatasetById } from '@/web/core/dataset/api';
import { useDatasetStore } from '@/web/core/dataset/store/dataset'; import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { getErrText } from '@fastgpt/global/common/error/utils'; import {
import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type'; GetResourceFolderListProps,
import { useToast } from '@fastgpt/web/hooks/useToast'; ParentIdType,
import { useQuery } from '@tanstack/react-query'; ParentTreePathItemType
import { useTranslation } from 'next-i18next'; } from '@fastgpt/global/common/parentFolder/type';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React, { useCallback, useState } from 'react';
import { createContext } from 'use-context-selector'; import { createContext } from 'use-context-selector';
import { useI18n } from '@/web/context/I18n';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api';
import dynamic from 'next/dynamic';
const MoveModal = dynamic(() => import('@/components/common/folder/MoveModal'));
export type DatasetContextType = { export type DatasetContextType = {
refetch: () => void; refetchDatasets: () => void;
isFetching: boolean; refetchPaths: () => void;
isFetchingDatasets: boolean;
setMoveDatasetId: (id: string) => void;
paths: ParentTreePathItemType[]; paths: ParentTreePathItemType[];
}; };
export const DatasetContext = createContext<DatasetContextType>({ export const DatasetContext = createContext<DatasetContextType>({
refetch: () => {}, refetchDatasets: () => {},
isFetching: false, isFetchingDatasets: false,
setMoveDatasetId: () => {},
refetchPaths: () => {},
paths: [] paths: []
}); });
function DatasetContextProvider({ children }: { children: React.ReactNode }) { function DatasetContextProvider({ children }: { children: React.ReactNode }) {
const router = useRouter(); const router = useRouter();
const { toast } = useToast(); const { commonT } = useI18n();
const { t } = useTranslation();
const { parentId } = router.query as { parentId: string }; const { parentId = null } = router.query as { parentId?: string | null };
const { loadMyDatasets } = useDatasetStore(); const { loadMyDatasets } = useDatasetStore();
const { data, refetch, isFetching } = useQuery( const getDatasetFolderList = useCallback(async ({ parentId }: GetResourceFolderListProps) => {
['loadDataset', parentId], const res = await getDatasetPaths(parentId);
() => { return res.map((item) => ({
return Promise.all([loadMyDatasets(parentId), getDatasetPaths(parentId)]); id: item.parentId,
}, name: item.parentName
}));
}, []);
const { data: paths = [], runAsync: refetchPaths } = useRequest2(
() => getDatasetPaths(parentId),
{ {
onError(err) { manual: false,
toast({ refreshDeps: [parentId]
status: 'error',
title: t(getErrText(err))
});
}
} }
); );
const paths = data?.[1] || []; const { runAsync: refetchDatasets, loading: isFetchingDatasets } = useRequest2(
() => loadMyDatasets(parentId ?? undefined),
{
manual: false,
refreshDeps: [parentId]
}
);
const [moveDatasetId, setMoveDatasetId] = useState<string>();
const { runAsync: onUpdateDataset } = useRequest2((data: DatasetUpdateBody) =>
putDatasetById(data).then(async (res) => {
await Promise.all([refetchDatasets(), refetchPaths()]);
return res;
})
);
const onMoveDataset = useCallback(
async (parentId: ParentIdType) => {
if (!moveDatasetId) return;
await onUpdateDataset({
id: moveDatasetId,
parentId
});
},
[moveDatasetId, onUpdateDataset]
);
const contextValue = { const contextValue = {
refetch, refetchDatasets,
isFetching, isFetchingDatasets,
paths setMoveDatasetId,
paths,
refetchPaths
}; };
return <DatasetContext.Provider value={contextValue}>{children}</DatasetContext.Provider>; return (
<DatasetContext.Provider value={contextValue}>
{children}
{!!moveDatasetId && (
<MoveModal
moveResourceId={moveDatasetId}
server={getDatasetFolderList}
title={commonT('Move')}
onClose={() => setMoveDatasetId(undefined)}
onConfirm={onMoveDataset}
/>
)}
</DatasetContext.Provider>
);
} }
export default DatasetContextProvider; export default DatasetContextProvider;

View File

@@ -1,55 +1,32 @@
import React from 'react'; import React from 'react';
import { Box, Flex, useDisclosure, Image, Button } from '@chakra-ui/react'; import { Box, Flex, Image } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import PageContainer from '@/components/PageContainer'; import PageContainer from '@/components/PageContainer';
import { AddIcon } from '@chakra-ui/icons';
import { postCreateDataset } from '@/web/core/dataset/api';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { serviceSideProps } from '@/web/common/utils/i18n'; import { serviceSideProps } from '@/web/common/utils/i18n';
import dynamic from 'next/dynamic'; import ParentPaths from '@/components/common/folder/Path';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { FolderImgUrl, FolderIcon } from '@fastgpt/global/common/file/image/constants';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import EditFolderModal, { useEditFolder } from '../component/EditFolderModal';
import { useUserStore } from '@/web/support/user/useUserStore';
import ParentPaths from '@/components/common/ParentPaths';
import { useDatasetStore } from '@/web/core/dataset/store/dataset'; import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import List from './component/List'; import List from './component/List';
import { DatasetContext } from './context'; import { DatasetContext } from './context';
import DatasetContextProvider from './context'; import DatasetContextProvider from './context';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
const CreateModal = dynamic(() => import('./component/CreateModal'), { ssr: false });
const Dataset = () => { const Dataset = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const { userInfo } = useUserStore();
const { myDatasets } = useDatasetStore(); const { myDatasets } = useDatasetStore();
const { parentId } = router.query as { parentId: string };
const { const { paths, isFetchingDatasets } = useContextSelector(DatasetContext, (v) => v);
isOpen: isOpenCreateModal,
onOpen: onOpenCreateModal,
onClose: onCloseCreateModal
} = useDisclosure();
const { editFolderData, setEditFolderData } = useEditFolder();
const { paths, refetch, isFetching } = useContextSelector(DatasetContext, (v) => v);
return ( return (
<PageContainer <PageContainer
isLoading={myDatasets.length === 0 && isFetching} isLoading={myDatasets.length === 0 && isFetchingDatasets}
insertProps={{ px: [5, '48px'] }} insertProps={{ px: [5, '48px'] }}
> >
<Flex pt={[4, '30px']} alignItems={'center'} justifyContent={'space-between'}> <Flex pt={[4, '30px']} alignItems={'center'} justifyContent={'space-between'}>
{/* url path */} {/* url path */}
<ParentPaths <ParentPaths
paths={paths.map((path) => ({ paths={paths}
parentId: path.parentId,
parentName: path.parentName
}))}
FirstPathDom={ FirstPathDom={
<Flex flex={1} alignItems={'center'}> <Flex flex={1} alignItems={'center'}>
<Image src={'/imgs/workflow/db.png'} alt={''} mr={2} h={'24px'} /> <Image src={'/imgs/workflow/db.png'} alt={''} mr={2} h={'24px'} />
@@ -66,68 +43,8 @@ const Dataset = () => {
}); });
}} }}
/> />
{/* create icon */}
{userInfo?.team?.permission.hasWritePer && (
<MyMenu
offset={[-30, 5]}
width={120}
Button={
<Button variant={'primaryOutline'} px={0}>
<Flex alignItems={'center'} px={'20px'}>
<AddIcon mr={2} />
<Box>{t('common.Create New')}</Box>
</Flex>
</Button>
}
menuList={[
{
children: [
{
label: (
<Flex>
<MyIcon name={FolderIcon} w={'20px'} mr={1} />
{t('Folder')}
</Flex>
),
onClick: () => setEditFolderData({})
},
{
label: (
<Flex>
<Image src={'/imgs/workflow/db.png'} alt={''} w={'20px'} mr={1} />
{t('core.dataset.Dataset')}
</Flex>
),
onClick: onOpenCreateModal
}
]
}
]}
/>
)}
</Flex> </Flex>
<List /> <List />
{isOpenCreateModal && <CreateModal onClose={onCloseCreateModal} parentId={parentId} />}
{!!editFolderData && (
<EditFolderModal
onClose={() => 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}
/>
)}
</PageContainer> </PageContainer>
); );
}; };

View File

@@ -1,5 +1,8 @@
import { GET, POST, PUT, DELETE } from '@/web/common/api/request'; import { GET, POST, PUT, DELETE } from '@/web/common/api/request';
import type { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type.d'; import type {
ParentIdType,
ParentTreePathItemType
} from '@fastgpt/global/common/parentFolder/type.d';
import type { import type {
DatasetItemType, DatasetItemType,
DatasetListItemType, DatasetListItemType,
@@ -56,7 +59,7 @@ export const getDatasets = (data: { parentId?: string; type?: DatasetTypeEnum })
*/ */
export const getAllDataset = () => GET<DatasetSimpleItemType[]>(`/core/dataset/allDataset`); export const getAllDataset = () => GET<DatasetSimpleItemType[]>(`/core/dataset/allDataset`);
export const getDatasetPaths = (parentId?: string) => export const getDatasetPaths = (parentId: ParentIdType) =>
GET<ParentTreePathItemType[]>('/core/dataset/paths', { parentId }); GET<ParentTreePathItemType[]>('/core/dataset/paths', { parentId });
export const getDatasetById = (id: string) => GET<DatasetItemType>(`/core/dataset/detail?id=${id}`); export const getDatasetById = (id: string) => GET<DatasetItemType>(`/core/dataset/detail?id=${id}`);