mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-16 08:01:18 +00:00
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:
@@ -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",
|
||||||
|
3
packages/global/core/dataset/api.d.ts
vendored
3
packages/global/core/dataset/api.d.ts
vendored
@@ -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;
|
||||||
|
@@ -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",
|
||||||
|
@@ -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
21047
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -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 />
|
||||||
|
@@ -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} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -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}`);
|
||||||
|
Reference in New Issue
Block a user