mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-24 22:03:54 +00:00
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Box, Flex, Button, ModalFooter, ModalBody, Input } from '@chakra-ui/react';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { useForm } from 'react-hook-form';
|
||||
@@ -14,29 +14,56 @@ import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { postCreateDataset } from '@/web/core/dataset/api';
|
||||
import type { CreateDatasetParams } from '@/global/core/dataset/api.d';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyRadio from '@/components/common/MyRadio';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||
import AIModelSelector from '@/components/Select/AIModelSelector';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
|
||||
const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: string }) => {
|
||||
export type CreateDatasetType =
|
||||
| DatasetTypeEnum.dataset
|
||||
| DatasetTypeEnum.externalFile
|
||||
| DatasetTypeEnum.websiteDataset;
|
||||
|
||||
const CreateModal = ({
|
||||
onClose,
|
||||
parentId,
|
||||
type
|
||||
}: {
|
||||
onClose: () => void;
|
||||
parentId?: string;
|
||||
type: CreateDatasetType;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { datasetT } = useI18n();
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const { feConfigs, vectorModelList, datasetModelList } = useSystemStore();
|
||||
const { vectorModelList, datasetModelList } = useSystemStore();
|
||||
const { isPc } = useSystem();
|
||||
|
||||
const databaseNameMap = useMemo(() => {
|
||||
return {
|
||||
[DatasetTypeEnum.dataset]: t('dataset:common_dataset'),
|
||||
[DatasetTypeEnum.externalFile]: t('dataset:external_file'),
|
||||
[DatasetTypeEnum.websiteDataset]: t('dataset:website_dataset')
|
||||
};
|
||||
}, [t]);
|
||||
|
||||
const iconMap = useMemo(() => {
|
||||
return {
|
||||
[DatasetTypeEnum.dataset]: 'core/dataset/commonDatasetColor',
|
||||
[DatasetTypeEnum.externalFile]: 'core/dataset/externalDatasetColor',
|
||||
[DatasetTypeEnum.websiteDataset]: 'core/dataset/websiteDatasetColor'
|
||||
};
|
||||
}, []);
|
||||
|
||||
const filterNotHiddenVectorModelList = vectorModelList.filter((item) => !item.hidden);
|
||||
|
||||
const { register, setValue, handleSubmit, watch } = useForm<CreateDatasetParams>({
|
||||
defaultValues: {
|
||||
parentId,
|
||||
type: DatasetTypeEnum.dataset,
|
||||
avatar: '/icon/logo.svg',
|
||||
type: type || DatasetTypeEnum.dataset,
|
||||
avatar: iconMap[type] || 'core/dataset/commonDatasetColor',
|
||||
name: '',
|
||||
intro: '',
|
||||
vectorModel: filterNotHiddenVectorModelList[0].model,
|
||||
@@ -44,7 +71,6 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
|
||||
}
|
||||
});
|
||||
const avatar = watch('avatar');
|
||||
const datasetType = watch('type');
|
||||
const vectorModel = watch('vectorModel');
|
||||
const agentModel = watch('agentModel');
|
||||
|
||||
@@ -88,63 +114,16 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
|
||||
}
|
||||
});
|
||||
|
||||
const onSelectDatasetType = useCallback(
|
||||
(e: DatasetTypeEnum) => {
|
||||
if (
|
||||
!feConfigs?.isPlus &&
|
||||
(e === DatasetTypeEnum.websiteDataset || e === DatasetTypeEnum.externalFile)
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('common:common.system.Commercial version function')
|
||||
});
|
||||
}
|
||||
setValue('type', e);
|
||||
},
|
||||
[feConfigs?.isPlus, setValue, t, toast]
|
||||
);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
iconSrc="/imgs/workflow/db.png"
|
||||
title={t('common:core.dataset.Create dataset')}
|
||||
iconSrc={iconMap[type]}
|
||||
title={t('common:core.dataset.Create dataset', { name: databaseNameMap[type] })}
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
isCentered={!isPc}
|
||||
w={'450px'}
|
||||
>
|
||||
<ModalBody py={2}>
|
||||
<>
|
||||
<Box mb={1} color={'myGray.900'}>
|
||||
{t('common:core.dataset.Dataset Type')}
|
||||
</Box>
|
||||
<MyRadio
|
||||
gridGap={2}
|
||||
gridTemplateColumns={'repeat(1,1fr)'}
|
||||
list={[
|
||||
{
|
||||
title: datasetT('common_dataset'),
|
||||
value: DatasetTypeEnum.dataset,
|
||||
icon: 'core/dataset/commonDataset',
|
||||
desc: datasetT('common_dataset_desc')
|
||||
},
|
||||
{
|
||||
title: datasetT('website_dataset'),
|
||||
value: DatasetTypeEnum.websiteDataset,
|
||||
icon: 'core/dataset/websiteDataset',
|
||||
desc: datasetT('website_dataset_desc')
|
||||
},
|
||||
{
|
||||
title: datasetT('external_file'),
|
||||
value: DatasetTypeEnum.externalFile,
|
||||
icon: 'core/dataset/externalDataset',
|
||||
desc: datasetT('external_file_dataset_desc')
|
||||
}
|
||||
]}
|
||||
value={datasetType}
|
||||
onChange={onSelectDatasetType}
|
||||
/>
|
||||
</>
|
||||
<Box mt={5}>
|
||||
<Box color={'myGray.900'}>{t('common:common.Set Name')}</Box>
|
||||
<Flex mt={1} alignItems={'center'}>
|
||||
|
@@ -49,7 +49,8 @@ function List() {
|
||||
setEditedDataset,
|
||||
onDelDataset,
|
||||
onUpdateDataset,
|
||||
myDatasets
|
||||
myDatasets,
|
||||
folderDetail
|
||||
} = useContextSelector(DatasetsContext, (v) => v);
|
||||
const [editPerDatasetIndex, setEditPerDatasetIndex] = useState<number>();
|
||||
const [loadingDatasetId, setLoadingDatasetId] = useState<string>();
|
||||
@@ -142,11 +143,14 @@ function List() {
|
||||
<>
|
||||
{formatDatasets.length > 0 && (
|
||||
<Grid
|
||||
flexGrow={1}
|
||||
py={5}
|
||||
gridTemplateColumns={['1fr', 'repeat(2,1fr)', 'repeat(3,1fr)', 'repeat(4,1fr)']}
|
||||
py={4}
|
||||
gridTemplateColumns={
|
||||
folderDetail
|
||||
? ['1fr', 'repeat(2,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']
|
||||
: ['1fr', 'repeat(2,1fr)', 'repeat(3,1fr)', 'repeat(3,1fr)', 'repeat(4,1fr)']
|
||||
}
|
||||
gridGap={5}
|
||||
userSelect={'none'}
|
||||
alignItems={'stretch'}
|
||||
>
|
||||
{formatDatasets.map((dataset, index) => (
|
||||
<MyTooltip
|
||||
@@ -165,14 +169,18 @@ function List() {
|
||||
isLoading={loadingDatasetId === dataset._id}
|
||||
display={'flex'}
|
||||
flexDirection={'column'}
|
||||
lineHeight={1.5}
|
||||
h="100%"
|
||||
py={3}
|
||||
px={5}
|
||||
cursor={'pointer'}
|
||||
borderWidth={1.5}
|
||||
border={'base'}
|
||||
boxShadow={'2'}
|
||||
bg={'white'}
|
||||
borderRadius={'md'}
|
||||
minH={'130px'}
|
||||
borderRadius={'lg'}
|
||||
position={'relative'}
|
||||
minH={'150px'}
|
||||
{...getBoxProps({
|
||||
dataId: dataset._id,
|
||||
isFolder: dataset.type === DatasetTypeEnum.folder
|
||||
|
@@ -37,6 +37,8 @@ export type DatasetContextType = {
|
||||
setEditedDataset: (data?: EditResourceInfoFormType) => void;
|
||||
onDelDataset: (id: string) => Promise<void>;
|
||||
onUpdateDataset: (data: DatasetUpdateBody) => Promise<void>;
|
||||
searchKey: string;
|
||||
setSearchKey: React.Dispatch<React.SetStateAction<string>>;
|
||||
};
|
||||
|
||||
export const DatasetsContext = createContext<DatasetContextType>({
|
||||
@@ -57,7 +59,11 @@ export const DatasetsContext = createContext<DatasetContextType>({
|
||||
onUpdateDataset: function (_data: DatasetUpdateBody): Promise<void> {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
myDatasets: []
|
||||
myDatasets: [],
|
||||
searchKey: '',
|
||||
setSearchKey: function (value: React.SetStateAction<string>): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}
|
||||
});
|
||||
|
||||
function DatasetContextProvider({ children }: { children: React.ReactNode }) {
|
||||
@@ -65,7 +71,7 @@ function DatasetContextProvider({ children }: { children: React.ReactNode }) {
|
||||
const { commonT } = useI18n();
|
||||
const { t } = useTranslation();
|
||||
const [moveDatasetId, setMoveDatasetId] = useState<string>();
|
||||
|
||||
const [searchKey, setSearchKey] = useState('');
|
||||
const { parentId = null } = router.query as { parentId?: string | null };
|
||||
|
||||
const {
|
||||
@@ -75,11 +81,12 @@ function DatasetContextProvider({ children }: { children: React.ReactNode }) {
|
||||
} = useRequest2(
|
||||
() =>
|
||||
getDatasets({
|
||||
searchKey,
|
||||
parentId
|
||||
}),
|
||||
{
|
||||
manual: false,
|
||||
refreshDeps: [parentId]
|
||||
refreshDeps: [parentId, searchKey]
|
||||
}
|
||||
);
|
||||
|
||||
@@ -145,7 +152,9 @@ function DatasetContextProvider({ children }: { children: React.ReactNode }) {
|
||||
onDelDataset,
|
||||
onUpdateDataset,
|
||||
myDatasets,
|
||||
loadMyDatasets
|
||||
loadMyDatasets,
|
||||
searchKey,
|
||||
setSearchKey
|
||||
};
|
||||
|
||||
return (
|
||||
|
@@ -1,5 +1,14 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Flex, Image, Button, useDisclosure } from '@chakra-ui/react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Image,
|
||||
Button,
|
||||
useDisclosure,
|
||||
InputGroup,
|
||||
InputLeftElement,
|
||||
Input
|
||||
} from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
@@ -28,6 +37,10 @@ import {
|
||||
getCollaboratorList
|
||||
} from '@/web/core/dataset/api/collaborator';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
import { CreateDatasetType } from './component/CreateModal';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
|
||||
const EditFolderModal = dynamic(
|
||||
() => import('@fastgpt/web/components/common/MyModal/EditFolderModal')
|
||||
@@ -52,32 +65,62 @@ const Dataset = () => {
|
||||
setEditedDataset,
|
||||
setMoveDatasetId,
|
||||
onDelDataset,
|
||||
onUpdateDataset
|
||||
onUpdateDataset,
|
||||
searchKey,
|
||||
setSearchKey
|
||||
} = useContextSelector(DatasetsContext, (v) => v);
|
||||
const { userInfo } = useUserStore();
|
||||
|
||||
const { toast } = useToast();
|
||||
const [editFolderData, setEditFolderData] = useState<EditFolderFormType>();
|
||||
const [createDatasetType, setCreateDatasetType] = useState<CreateDatasetType>();
|
||||
|
||||
const {
|
||||
isOpen: isOpenCreateModal,
|
||||
onOpen: onOpenCreateModal,
|
||||
onClose: onCloseCreateModal
|
||||
} = useDisclosure();
|
||||
const onSelectDatasetType = useCallback(
|
||||
(e: CreateDatasetType) => {
|
||||
if (
|
||||
!feConfigs?.isPlus &&
|
||||
(e === DatasetTypeEnum.websiteDataset || e === DatasetTypeEnum.externalFile)
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('common:common.system.Commercial version function')
|
||||
});
|
||||
}
|
||||
setCreateDatasetType(e);
|
||||
},
|
||||
[t, toast]
|
||||
);
|
||||
|
||||
const RenderSearchInput = useMemo(
|
||||
() => (
|
||||
<InputGroup maxW={['auto', '250px']} pr={4}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon name={'common/searchLight'} w={'1rem'} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
value={searchKey}
|
||||
onChange={(e) => setSearchKey(e.target.value)}
|
||||
placeholder={t('common:dataset.dataset_name')}
|
||||
maxLength={30}
|
||||
bg={'white'}
|
||||
/>
|
||||
</InputGroup>
|
||||
),
|
||||
[searchKey, setSearchKey, t]
|
||||
);
|
||||
return (
|
||||
<PageContainer
|
||||
<MyBox
|
||||
isLoading={myDatasets.length === 0 && isFetchingDatasets}
|
||||
insertProps={{ px: folderDetail ? [4, 6] : [5, '10'] }}
|
||||
flexDirection={'column'}
|
||||
h={'100%'}
|
||||
>
|
||||
<Flex pt={[4, 6]}>
|
||||
<Flex pt={[4, 6]} pl={3} pr={10}>
|
||||
<Flex flexGrow={1} flexDirection="column">
|
||||
<Flex alignItems={'flex-start'} justifyContent={'space-between'}>
|
||||
<ParentPaths
|
||||
paths={paths}
|
||||
FirstPathDom={
|
||||
<Flex flex={1} alignItems={'center'}>
|
||||
<Image src={'/imgs/workflow/db.png'} alt={''} mr={2} h={'24px'} />
|
||||
<Box className="textlg" letterSpacing={1} fontSize={'24px'} fontWeight={'bold'}>
|
||||
<Box pl={2} letterSpacing={1} fontSize={'1.25rem'} fontWeight={'bold'}>
|
||||
{t('common:core.dataset.My Dataset')}
|
||||
</Box>
|
||||
</Flex>
|
||||
@@ -90,10 +133,14 @@ const Dataset = () => {
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
{isPc && RenderSearchInput}
|
||||
|
||||
{userInfo?.team?.permission.hasWritePer && (
|
||||
<MyMenu
|
||||
offset={[-30, 5]}
|
||||
width={120}
|
||||
iconSize="2rem"
|
||||
Button={
|
||||
<Button variant={'primary'} px="0">
|
||||
<Flex alignItems={'center'} px={'20px'}>
|
||||
@@ -106,22 +153,31 @@ const Dataset = () => {
|
||||
{
|
||||
children: [
|
||||
{
|
||||
label: (
|
||||
<Flex>
|
||||
<MyIcon name={FolderIcon} w={'20px'} mr={1} />
|
||||
{t('common:Folder')}
|
||||
</Flex>
|
||||
),
|
||||
onClick: () => setEditFolderData({})
|
||||
icon: 'core/dataset/commonDatasetColor',
|
||||
label: t('dataset:common_dataset'),
|
||||
description: t('dataset:common_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.dataset)
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<Flex>
|
||||
<Image src={'/imgs/workflow/db.png'} alt={''} w={'20px'} mr={1} />
|
||||
{t('common:core.dataset.Dataset')}
|
||||
</Flex>
|
||||
),
|
||||
onClick: onOpenCreateModal
|
||||
icon: 'core/dataset/websiteDatasetColor',
|
||||
label: t('dataset:website_dataset'),
|
||||
description: t('dataset:website_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.websiteDataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/externalDatasetColor',
|
||||
label: t('dataset:external_file'),
|
||||
description: t('dataset:external_file_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.externalFile)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: FolderIcon,
|
||||
label: t('common:Folder'),
|
||||
onClick: () => setEditFolderData({})
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -129,6 +185,9 @@ const Dataset = () => {
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
{!isPc && <Box mt={2}>{RenderSearchInput}</Box>}
|
||||
|
||||
<Box flexGrow={1}>
|
||||
<List />
|
||||
</Box>
|
||||
@@ -231,13 +290,16 @@ const Dataset = () => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isOpenCreateModal && (
|
||||
<CreateModal onClose={onCloseCreateModal} parentId={parentId || undefined} />
|
||||
{createDatasetType && (
|
||||
<CreateModal
|
||||
type={createDatasetType}
|
||||
onClose={() => setCreateDatasetType(undefined)}
|
||||
parentId={parentId || undefined}
|
||||
/>
|
||||
)}
|
||||
</PageContainer>
|
||||
</MyBox>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getServerSideProps(content: any) {
|
||||
return {
|
||||
props: {
|
||||
|
Reference in New Issue
Block a user