This commit is contained in:
Archer
2023-11-09 09:46:57 +08:00
committed by GitHub
parent 661ee79943
commit 8bb5588305
402 changed files with 9899 additions and 5967 deletions

View File

@@ -50,6 +50,8 @@ import { useDrag } from '@/web/common/hooks/useDrag';
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
import { useToast } from '@/web/common/hooks/useToast';
import MyTooltip from '@/components/MyTooltip';
import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
const FileImportModal = dynamic(() => import('./Import/ImportModal'), {});
@@ -62,6 +64,7 @@ const CollectionCard = () => {
const { t } = useTranslation();
const { Loading } = useLoading();
const { isPc } = useSystemStore();
const { userInfo } = useUserStore();
const [searchText, setSearchText] = useState('');
const { setLoading } = useSystemStore();
@@ -271,67 +274,69 @@ const CollectionCard = () => {
/>
</Flex>
)}
<MyMenu
offset={[-40, 10]}
width={120}
Button={
<MenuButton
_hover={{
color: 'myBlue.600'
}}
fontSize={['sm', 'md']}
>
<Flex
alignItems={'center'}
px={5}
py={2}
borderRadius={'md'}
cursor={'pointer'}
bg={'myBlue.600'}
overflow={'hidden'}
color={'white'}
h={['28px', '35px']}
{userInfo?.team?.role !== TeamMemberRoleEnum.visitor && (
<MyMenu
offset={[-40, 10]}
width={120}
Button={
<MenuButton
_hover={{
color: 'myBlue.600'
}}
fontSize={['sm', 'md']}
>
<MyIcon name={'importLight'} mr={2} w={'14px'} />
<Box>{t('dataset.collections.Create And Import')}</Box>
</Flex>
</MenuButton>
}
menuList={[
{
child: (
<Flex>
<Image src={FolderAvatarSrc} alt={''} w={'20px'} mr={2} />
{t('Folder')}
<Flex
alignItems={'center'}
px={5}
py={2}
borderRadius={'md'}
cursor={'pointer'}
bg={'myBlue.600'}
overflow={'hidden'}
color={'white'}
h={['28px', '35px']}
>
<MyIcon name={'importLight'} mr={2} w={'14px'} />
<Box>{t('dataset.collections.Create And Import')}</Box>
</Flex>
),
onClick: () => setEditFolderData({})
},
{
child: (
<Flex>
<Image src={'/imgs/files/collection.svg'} alt={''} w={'20px'} mr={2} />
{t('dataset.Create Virtual File')}
</Flex>
),
onClick: () => {
onOpenCreateVirtualFileModal({
defaultVal: '',
onSuccess: (name) => onCreateVirtualFile({ name })
});
}
},
{
child: (
<Flex>
<Image src={'/imgs/files/file.svg'} alt={''} w={'20px'} mr={2} />
{t('dataset.File Input')}
</Flex>
),
onClick: onOpenFileImportModal
</MenuButton>
}
]}
/>
menuList={[
{
child: (
<Flex>
<Image src={FolderAvatarSrc} alt={''} w={'20px'} mr={2} />
{t('Folder')}
</Flex>
),
onClick: () => setEditFolderData({})
},
{
child: (
<Flex>
<Image src={'/imgs/files/collection.svg'} alt={''} w={'20px'} mr={2} />
{t('dataset.Create Virtual File')}
</Flex>
),
onClick: () => {
onOpenCreateVirtualFileModal({
defaultVal: '',
onSuccess: (name) => onCreateVirtualFile({ name })
});
}
},
{
child: (
<Flex>
<Image src={'/imgs/files/file.svg'} alt={''} w={'20px'} mr={2} />
{t('dataset.File Input')}
</Flex>
),
onClick: onOpenFileImportModal
}
]}
/>
)}
</Flex>
<TableContainer mt={[0, 3]} position={'relative'} flex={'1 0 0'} overflowY={'auto'}>
@@ -436,85 +441,87 @@ const CollectionCard = () => {
</Flex>
</Td>
<Td onClick={(e) => e.stopPropagation()}>
<MyMenu
width={100}
Button={
<MenuButton
w={'22px'}
h={'22px'}
borderRadius={'md'}
_hover={{
color: 'myBlue.600',
'& .icon': {
bg: 'myGray.100'
}
}}
>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
{collection.canWrite && userInfo?.team?.role !== TeamMemberRoleEnum.visitor && (
<MyMenu
width={100}
Button={
<MenuButton
w={'22px'}
h={'22px'}
borderRadius={'md'}
cursor={'pointer'}
/>
</MenuButton>
}
menuList={[
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'moveLight'} w={'14px'} mr={2} />
{t('Move')}
</Flex>
),
onClick: () => setMoveCollectionData({ collectionId: collection._id })
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
</Flex>
),
onClick: () =>
onOpenEditTitleModal({
defaultVal: collection.name,
onSuccess: (newName) => {
onUpdateCollectionName({
collectionId: collection._id,
name: newName
});
_hover={{
color: 'myBlue.600',
'& .icon': {
bg: 'myGray.100'
}
})
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon
mr={1}
name={'delete'}
w={'14px'}
_hover={{ color: 'red.600' }}
/>
<Box>{t('common.Delete')}</Box>
</Flex>
),
onClick: () =>
openConfirm(
() => {
onDelCollection(collection._id);
},
undefined,
collection.type === DatasetCollectionTypeEnum.folder
? t('dataset.collections.Confirm to delete the folder')
: t('dataset.Confirm to delete the file')
)()
}}
>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
borderRadius={'md'}
cursor={'pointer'}
/>
</MenuButton>
}
]}
/>
menuList={[
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'moveLight'} w={'14px'} mr={2} />
{t('Move')}
</Flex>
),
onClick: () => setMoveCollectionData({ collectionId: collection._id })
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
</Flex>
),
onClick: () =>
onOpenEditTitleModal({
defaultVal: collection.name,
onSuccess: (newName) => {
onUpdateCollectionName({
collectionId: collection._id,
name: newName
});
}
})
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon
mr={1}
name={'delete'}
w={'14px'}
_hover={{ color: 'red.600' }}
/>
<Box>{t('common.Delete')}</Box>
</Flex>
),
onClick: () =>
openConfirm(
() => {
onDelCollection(collection._id);
},
undefined,
collection.type === DatasetCollectionTypeEnum.folder
? t('dataset.collections.Confirm to delete the folder')
: t('dataset.Confirm to delete the file')
)()
}
]}
/>
)}
</Td>
</Tr>
))}

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useState, useRef, useMemo } from 'react';
import { Box, Card, IconButton, Flex, Grid, Image, Button } from '@chakra-ui/react';
import { Box, Card, IconButton, Flex, Grid, Button } from '@chakra-ui/react';
import { usePagination } from '@/web/common/hooks/usePagination';
import {
getDatasetDataList,
@@ -17,21 +17,22 @@ import { useRouter } from 'next/router';
import MyIcon from '@/components/Icon';
import MyInput from '@/components/MyInput';
import { useLoading } from '@/web/common/hooks/useLoading';
import { getCollectionIcon } from '@fastgpt/global/core/dataset/utils';
import InputDataModal, { RawSourceText, type InputDataType } from '../components/InputDataModal';
import type { DatasetDataListItemType } from '@/global/core/dataset/response.d';
import { TabEnum } from '..';
import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
const DataCard = () => {
const BoxRef = useRef<HTMLDivElement>(null);
const lastSearch = useRef('');
const router = useRouter();
const { userInfo } = useUserStore();
const { collectionId = '' } = router.query as { collectionId: string };
const { Loading, setIsLoading } = useLoading({ defaultLoading: true });
const { t } = useTranslation();
const [searchText, setSearchText] = useState('');
const { toast } = useToast();
const [isDeleting, setIsDeleting] = useState(false);
const { openConfirm, ConfirmModal } = useConfirm({
content: t('dataset.Confirm to delete the data')
});
@@ -74,6 +75,11 @@ const DataCard = () => {
getDatasetCollectionById(collectionId)
);
const canWrite = useMemo(
() => userInfo?.team?.role !== TeamMemberRoleEnum.visitor && !!collection?.canWrite,
[collection?.canWrite, userInfo?.team?.role]
);
return (
<Box ref={BoxRef} position={'relative'} px={5} py={[1, 5]} h={'100%'} overflow={'overlay'}>
<Flex alignItems={'center'}>
@@ -112,24 +118,25 @@ const DataCard = () => {
</Box>
</Box>
</Flex>
<Box>
<Button
ml={2}
variant={'base'}
size={['sm', 'md']}
onClick={() => {
if (!collection) return;
setEditInputData({
datasetId: collection.datasetId,
collectionId: collection._id,
sourceId: collection.metadata?.fileId || collection.metadata?.rawLink,
sourceName: collection.name
});
}}
>
{t('dataset.Insert Data')}
</Button>
</Box>
{canWrite && (
<Box>
<Button
ml={2}
variant={'base'}
size={['sm', 'md']}
onClick={() => {
if (!collection) return;
setEditInputData({
collectionId: collection._id,
sourceId: collection.metadata?.fileId || collection.metadata?.rawLink,
sourceName: collection.name
});
}}
>
{t('dataset.Insert Data')}
</Button>
</Box>
)}
</Flex>
<Flex my={3} alignItems={'center'}>
<Box>
@@ -180,7 +187,6 @@ const DataCard = () => {
if (!collection) return;
setEditInputData({
id: item.id,
datasetId: collection.datasetId,
collectionId: collection._id,
q: item.q,
a: item.a,
@@ -206,34 +212,35 @@ const DataCard = () => {
<Box className={'textEllipsis'} flex={1} color={'myGray.500'}>
ID:{item.id}
</Box>
<IconButton
className="delete"
display={['flex', 'none']}
icon={<DeleteIcon />}
variant={'base'}
colorScheme={'gray'}
aria-label={'delete'}
size={'xs'}
borderRadius={'md'}
_hover={{ color: 'red.600' }}
isLoading={isDeleting}
onClick={(e) => {
e.stopPropagation();
openConfirm(async () => {
try {
setIsDeleting(true);
await delOneDatasetDataById(item.id);
getData(pageNum);
} catch (error) {
toast({
title: getErrText(error),
status: 'error'
});
}
setIsDeleting(false);
})();
}}
/>
{canWrite && (
<IconButton
className="delete"
display={['flex', 'none']}
icon={<DeleteIcon />}
variant={'base'}
colorScheme={'gray'}
aria-label={'delete'}
size={'xs'}
borderRadius={'md'}
_hover={{ color: 'red.600' }}
onClick={(e) => {
e.stopPropagation();
openConfirm(async () => {
try {
setIsLoading(true);
await delOneDatasetDataById(item.id);
getData(pageNum);
} catch (error) {
toast({
title: getErrText(error),
status: 'error'
});
}
setIsLoading(false);
})();
}}
/>
)}
</Flex>
</Card>
))}
@@ -248,17 +255,18 @@ const DataCard = () => {
<Flex flexDirection={'column'} alignItems={'center'} pt={'10vh'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
</Box>
</Flex>
)}
{editInputData !== undefined && collection && (
<InputDataModal
datasetId={collection.datasetId}
datasetId={collection?.datasetId}
defaultValues={editInputData}
onClose={() => setEditInputData(undefined)}
onSuccess={() => getData(pageNum)}
canWrite={canWrite}
/>
)}
<ConfirmModal />

View File

@@ -10,7 +10,7 @@ import {
NumberDecrementStepper
} from '@chakra-ui/react';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { formatPrice } from '@fastgpt/global/common/bill/tools';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';

View File

@@ -5,13 +5,13 @@ import { useToast } from '@/web/common/hooks/useToast';
import { splitText2Chunks } from '@/global/common/string/tools';
import { simpleText } from '@fastgpt/global/common/string/tools';
import {
uploadFiles,
fileDownload,
readCsvContent,
readTxtContent,
readPdfContent,
readDocContent
} from '@/web/common/file/utils';
import { uploadFiles } from '@/web/common/file/controller';
import { Box, Flex, useDisclosure, type BoxProps } from '@chakra-ui/react';
import React, { DragEvent, useCallback, useState } from 'react';
import { useTranslation } from 'next-i18next';
@@ -108,13 +108,18 @@ const FileSelect = ({
if (!icon) continue;
// upload file
const filesId = await uploadFiles([file], { datasetId: datasetDetail._id }, (percent) => {
if (percent < 100) {
setSelectingText(
t('file.Uploading', { name: file.name.slice(0, 30), percent }) || ''
);
} else {
setSelectingText(t('file.Parse', { name: file.name.slice(0, 30) }) || '');
const filesId = await uploadFiles({
files: [file],
bucketName: 'dataset',
metadata: { datasetId: datasetDetail._id },
percentListen: (percent) => {
if (percent < 100) {
setSelectingText(
t('file.Uploading', { name: file.name.slice(0, 30), percent }) || ''
);
} else {
setSelectingText(t('file.Parse', { name: file.name.slice(0, 30) }) || '');
}
}
});
const fileId = filesId[0];
@@ -243,7 +248,11 @@ const FileSelect = ({
type: txtBlob.type,
lastModified: new Date().getTime()
});
const fileIds = await uploadFiles([txtFile], { datasetId: datasetDetail._id });
const fileIds = await uploadFiles({
files: [txtFile],
bucketName: 'dataset',
metadata: { datasetId: datasetDetail._id }
});
const splitRes = splitText2Chunks({
text: content,

View File

@@ -45,7 +45,7 @@ const ImportData = ({
mode: TrainingModeEnum.index
},
[ImportTypeEnum.qa]: {
defaultChunkLen: qaModel?.maxToken * 0.5 || 8000,
defaultChunkLen: qaModel?.maxContext * 0.5 || 8000,
unitPrice: qaModel?.price || 3,
mode: TrainingModeEnum.qa
},

View File

@@ -11,7 +11,7 @@ import React, {
import FileSelect, { FileItemType, Props as FileSelectProps } from './FileSelect';
import { useRequest } from '@/web/common/hooks/useRequest';
import { postDatasetCollection } from '@/web/core/dataset/api';
import { formatPrice } from '@fastgpt/global/common/bill/tools';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import { splitText2Chunks } from '@/global/common/string/tools';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
@@ -21,7 +21,7 @@ import { CloseIcon } from '@chakra-ui/icons';
import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
import MyIcon from '@/components/Icon';
import { chunksUpload } from '@/web/core/dataset/utils';
import { postCreateTrainingBill } from '@/web/common/bill/api';
import { postCreateTrainingBill } from '@/web/support/wallet/bill/api';
import { useTranslation } from 'react-i18next';
import { ImportTypeEnum } from './ImportModal';
@@ -129,19 +129,19 @@ const Provider = ({
let totalInsertion = 0;
for await (const file of files) {
const chunks = file.chunks;
// create training bill
const billId = await postCreateTrainingBill({
name: t('dataset.collections.Create Training Data', { filename: file.filename })
});
// create a file collection and training bill
const [collectionId, billId] = await Promise.all([
postDatasetCollection({
datasetId,
parentId,
name: file.filename,
type: file.type,
metadata: file.metadata
}),
postCreateTrainingBill({
name: t('dataset.collections.Create Training Data', { filename: file.filename })
})
]);
const collectionId = await postDatasetCollection({
datasetId,
parentId,
name: file.filename,
type: file.type,
metadata: file.metadata
});
// upload data
const { insertLen } = await chunksUpload({
collectionId,

View File

@@ -1,7 +1,7 @@
import React, { useState, useMemo } from 'react';
import { Box, Flex, Button, Input } from '@chakra-ui/react';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { formatPrice } from '@fastgpt/global/common/bill/tools';
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon, InfoOutlineIcon } from '@chakra-ui/icons';
import { Prompt_AgentQA } from '@/global/core/prompt/agent';

View File

@@ -15,11 +15,13 @@ import { useToast } from '@/web/common/hooks/useToast';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { UseFormReturn } from 'react-hook-form';
import { compressImg } from '@/web/common/file/utils';
import { compressImgAndUpload } from '@/web/common/file/controller';
import type { DatasetItemType } from '@/types/core/dataset';
import Avatar from '@/components/Avatar';
import Tag from '@/components/Tag';
import MyTooltip from '@/components/MyTooltip';
import { useTranslation } from 'react-i18next';
import PermissionRadio from '@/components/support/permission/Radio';
export interface ComponentRef {
initInput: (tags: string) => void;
@@ -29,6 +31,7 @@ const Info = (
{ datasetId, form }: { datasetId: string; form: UseFormReturn<DatasetItemType, any> },
ref: ForwardedRef<ComponentRef>
) => {
const { t } = useTranslation();
const { getValues, formState, setValue, register, handleSubmit } = form;
const InputRef = useRef<HTMLInputElement>(null);
@@ -115,7 +118,7 @@ const Info = (
const file = e[0];
if (!file) return;
try {
const src = await compressImg({
const src = await compressImgAndUpload({
file,
maxW: 100,
maxH: 100
@@ -220,6 +223,23 @@ const Info = (
))}
</Flex>
</Flex>
{datasetDetail.isOwner && (
<Flex mt={5} alignItems={'center'} w={'100%'} flexWrap={'wrap'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
{t('user.Permission')}
</Box>
<Box>
<PermissionRadio
value={getValues('permission')}
onChange={(e) => {
setValue('permission', e);
setRefresh(!refresh);
}}
/>
</Box>
</Flex>
)}
<Flex mt={5} w={'100%'} alignItems={'flex-end'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}></Box>
<Button
@@ -230,18 +250,20 @@ const Info = (
>
</Button>
<IconButton
isLoading={btnLoading}
icon={<DeleteIcon />}
aria-label={''}
variant={'outline'}
size={'sm'}
_hover={{
color: 'red.600',
borderColor: 'red.600'
}}
onClick={openConfirm(onclickDelKb)}
/>
{datasetDetail.isOwner && (
<IconButton
isLoading={btnLoading}
icon={<DeleteIcon />}
aria-label={''}
variant={'outline'}
size={'sm'}
_hover={{
color: 'red.600',
borderColor: 'red.600'
}}
onClick={openConfirm(onclickDelKb)}
/>
)}
</Flex>
<File onSelect={onSelectFile} />
<ConfirmModal />

View File

@@ -15,7 +15,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { getFileAndOpen } from '@/web/common/file/utils';
import { getFileAndOpen } from '@/web/core/dataset/utils';
import { strIsLink } from '@fastgpt/global/common/string/tools';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import type { SetOneDatasetDataProps } from '@/global/core/api/datasetReq';
@@ -39,17 +39,18 @@ const InputDataModal = ({
onDelete,
datasetId,
defaultValues = {
datasetId: '',
collectionId: '',
sourceId: '',
sourceName: ''
}
},
canWrite
}: {
onClose: () => void;
onSuccess: (data: SetOneDatasetDataProps) => void;
onDelete?: () => void;
datasetId: string;
defaultValues: InputDataType;
canWrite: boolean;
}) => {
const { t } = useTranslation();
const { toast } = useToast();
@@ -223,7 +224,7 @@ const InputDataModal = ({
/>
<Box flex={1}>
{defaultValues.id && onDelete && (
{defaultValues.id && onDelete && canWrite && (
<IconButton
variant={'outline'}
icon={<MyIcon name={'delete'} w={'16px'} h={'16px'} />}
@@ -259,13 +260,16 @@ const InputDataModal = ({
<Button variant={'base'} mr={3} isLoading={loading} onClick={onClose}>
{t('common.Close')}
</Button>
<Button
isLoading={loading}
// @ts-ignore
onClick={handleSubmit(defaultValues.id ? onUpdateData : sureImportData)}
>
{defaultValues.id ? '确认变更' : '确认导入'}
</Button>
<MyTooltip label={canWrite ? '' : t('dataset.data.Can not edit')}>
<Button
isDisabled={!canWrite}
isLoading={loading}
// @ts-ignore
onClick={handleSubmit(defaultValues.id ? onUpdateData : sureImportData)}
>
{defaultValues.id ? '确认变更' : '确认导入'}
</Button>
</MyTooltip>
</Box>
</Flex>
</Flex>
@@ -325,7 +329,7 @@ export function RawSourceText({
>
<Image src={icon} alt="" w={'14px'} mr={2} />
<Box maxW={['200px', '300px']} className={'textEllipsis'}>
{sourceName || t('common.Unknow Source')}
{sourceName || t('common.UnKnow Source')}
</Box>
</Box>
</MyTooltip>

View File

@@ -206,7 +206,6 @@ const Test = ({ datasetId }: { datasetId: string }) => {
setEditInputData({
id: data.id,
datasetId: data.datasetId,
collectionId: data.collectionId,
q: data.q,
a: data.a,
@@ -256,7 +255,8 @@ const Test = ({ datasetId }: { datasetId: string }) => {
{!!editInputData && (
<InputDataModal
datasetId={editInputData.datasetId}
datasetId={datasetDetail._id}
canWrite={datasetDetail.canWrite}
defaultValues={editInputData}
onClose={() => setEditInputData(undefined)}
onSuccess={(data) => {

View File

@@ -17,13 +17,14 @@ import Avatar from '@/components/Avatar';
import Info from './components/Info';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'react-i18next';
import { getTrainingQueueLen, delDatasetEmptyFiles } from '@/web/core/dataset/api';
import { getTrainingQueueLen } from '@/web/core/dataset/api';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { feConfigs } from '@/web/common/system/staticData';
import Script from 'next/script';
import CollectionCard from './components/CollectionCard';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { useUserStore } from '@/web/support/user/useUserStore';
const DataCard = dynamic(() => import('./components/DataCard'), {
ssr: false
@@ -47,12 +48,15 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
const router = useRouter();
const { isPc } = useSystemStore();
const { datasetDetail, loadDatasetDetail } = useDatasetStore();
const { userInfo } = useUserStore();
const tabList = useRef([
const tabList = [
{ label: '数据集', id: TabEnum.collectionCard, icon: 'overviewLight' },
{ label: '搜索测试', id: TabEnum.test, icon: 'kbTest' },
{ label: '配置', id: TabEnum.info, icon: 'settingLight' }
]);
...(userInfo?.team.canWrite && datasetDetail.isOwner
? [{ label: '配置', id: TabEnum.info, icon: 'settingLight' }]
: [])
];
const setCurrentTab = useCallback(
(tab: `${TabEnum}`) => {
@@ -88,14 +92,6 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
refetchInterval: 10000
});
useEffect(() => {
return () => {
try {
delDatasetEmptyFiles(datasetId);
} catch (error) {}
};
}, [datasetId]);
return (
<>
<Script src="/js/pdf.js" strategy="lazyOnload"></Script>
@@ -120,7 +116,7 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
mx={'auto'}
mt={2}
w={'100%'}
list={tabList.current}
list={tabList}
activeId={currentTab}
onChange={(e: any) => {
setCurrentTab(e);
@@ -169,7 +165,7 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
m={'auto'}
w={'260px'}
size={isPc ? 'md' : 'sm'}
list={tabList.current.map((item) => ({
list={tabList.map((item) => ({
id: item.id,
label: item.label
}))}

View File

@@ -2,7 +2,7 @@ import React, { useCallback, useState, useRef } from 'react';
import { Box, Flex, Button, ModalHeader, ModalFooter, ModalBody, Input } from '@chakra-ui/react';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImg } from '@/web/common/file/utils';
import { compressImgAndUpload } from '@/web/common/file/controller';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { useRouter } from 'next/router';
@@ -27,7 +27,7 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
defaultValues: {
avatar: '/icon/logo.svg',
name: '',
tags: [],
tags: '',
vectorModel: vectorModelList[0].model,
type: 'dataset',
parentId
@@ -45,7 +45,7 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
const file = e[0];
if (!file) return;
try {
const src = await compressImg({
const src = await compressImgAndUpload({
file,
maxW: 100,
maxH: 100
@@ -135,13 +135,14 @@ const CreateModal = ({ onClose, parentId }: { onClose: () => void; parentId?: st
placeholder={'标签,使用空格分割。'}
maxLength={30}
onChange={(e) => {
setValue('tags', e.target.value.split(' '));
setValue('tags', e.target.value);
setRefresh(!refresh);
}}
/>
</Flex>
<Flex mt={2} flexWrap={'wrap'}>
{getValues('tags')
.split(' ')
.filter((item) => item)
.map((item, i) => (
<Tag mr={2} mb={2} key={i} whiteSpace={'nowrap'}>

View File

@@ -36,6 +36,10 @@ import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import { feConfigs } from '@/web/common/system/staticData';
import EditFolderModal, { useEditFolder } from '../component/EditFolderModal';
import { useDrag } from '@/web/common/hooks/useDrag';
import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import PermissionIconText from '@/components/support/permission/IconText';
import { PermissionTypeEnum } from '@fastgpt/global/support/permission/constant';
const CreateModal = dynamic(() => import('./component/CreateModal'), { ssr: false });
const MoveModal = dynamic(() => import('./component/MoveModal'), { ssr: false });
@@ -46,6 +50,7 @@ const Kb = () => {
const router = useRouter();
const { parentId } = router.query as { parentId: string };
const { setLoading } = useSystemStore();
const { userInfo } = useUserStore();
const DeleteTipsMap = useRef({
[DatasetTypeEnum.folder]: t('dataset.deleteFolderTips'),
@@ -162,50 +167,51 @@ const Kb = () => {
</Box>
</Flex>
)}
<MyMenu
offset={[-30, 10]}
width={120}
Button={
<MenuButton
_hover={{
color: 'myBlue.600'
}}
>
<Flex
alignItems={'center'}
border={theme.borders.base}
px={5}
py={2}
borderRadius={'md'}
cursor={'pointer'}
{userInfo?.team?.canWrite && (
<MyMenu
offset={[-30, 10]}
width={120}
Button={
<MenuButton
_hover={{
color: 'myBlue.600'
}}
>
<AddIcon mr={2} />
<Box>{t('Create New')}</Box>
</Flex>
</MenuButton>
}
menuList={[
{
child: (
<Flex>
<Image src={FolderAvatarSrc} alt={''} w={'20px'} mr={1} />
{t('Folder')}
<Flex
alignItems={'center'}
border={theme.borders.base}
px={5}
py={2}
borderRadius={'md'}
cursor={'pointer'}
>
<AddIcon mr={2} />
<Box>{t('Create New')}</Box>
</Flex>
),
onClick: () => setEditFolderData({})
},
{
child: (
<Flex>
<Image src={'/imgs/module/db.png'} alt={''} w={'20px'} mr={1} />
{t('Dataset')}
</Flex>
),
onClick: onOpenCreateModal
</MenuButton>
}
]}
/>
menuList={[
{
child: (
<Flex>
<Image src={FolderAvatarSrc} alt={''} w={'20px'} mr={1} />
{t('Folder')}
</Flex>
),
onClick: () => setEditFolderData({})
},
{
child: (
<Flex>
<Image src={'/imgs/module/db.png'} alt={''} w={'20px'} mr={1} />
{t('Dataset')}
</Flex>
),
onClick: onOpenCreateModal
}
]}
/>
)}
</Flex>
<Grid
p={5}
@@ -279,91 +285,126 @@ const Kb = () => {
}
}}
>
<MyMenu
offset={[-30, 10]}
width={120}
Button={
<MenuButton
position={'absolute'}
top={3}
right={3}
w={'22px'}
h={'22px'}
borderRadius={'md'}
_hover={{
color: 'myBlue.600',
'& .icon': {
bg: 'myGray.100'
}
}}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
{userInfo?.team.canWrite && dataset.isOwner && (
<MyMenu
offset={[-30, 10]}
width={120}
Button={
<MenuButton
position={'absolute'}
top={3}
right={3}
w={'22px'}
h={'22px'}
borderRadius={'md'}
cursor={'pointer'}
/>
</MenuButton>
}
menuList={[
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
</Flex>
),
onClick: () =>
onOpenTitleModal({
defaultVal: dataset.name,
onSuccess: (val) => {
if (val === dataset.name || !val) return;
updateDataset({ id: dataset._id, name: val });
_hover={{
color: 'myBlue.600',
'& .icon': {
bg: 'myGray.100'
}
})
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'moveLight'} w={'14px'} mr={2} />
{t('Move')}
</Flex>
),
onClick: () => setMoveDataId(dataset._id)
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'export'} w={'14px'} mr={2} />
{t('Export')}
</Flex>
),
onClick: () => onclickExport(dataset._id)
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'delete'} w={'14px'} mr={2} />
{t('common.Delete')}
</Flex>
),
onClick: () => {
openConfirm(
() => onclickDelDataset(dataset._id),
undefined,
DeleteTipsMap.current[dataset.type]
)();
}
}}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
borderRadius={'md'}
cursor={'pointer'}
/>
</MenuButton>
}
]}
/>
menuList={[
...(dataset.permission === PermissionTypeEnum.private
? [
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'support/permission/publicLight'} w={'14px'} mr={2} />
{t('permission.Set Public')}
</Flex>
),
onClick: () => {
updateDataset({
id: dataset._id,
permission: PermissionTypeEnum.public
});
}
}
]
: [
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'support/permission/privateLight'} w={'14px'} mr={2} />
{t('permission.Set Private')}
</Flex>
),
onClick: () => {
updateDataset({
id: dataset._id,
permission: PermissionTypeEnum.private
});
}
}
]),
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
</Flex>
),
onClick: () =>
onOpenTitleModal({
defaultVal: dataset.name,
onSuccess: (val) => {
if (val === dataset.name || !val) return;
updateDataset({ id: dataset._id, name: val });
}
})
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'moveLight'} w={'14px'} mr={2} />
{t('Move')}
</Flex>
),
onClick: () => setMoveDataId(dataset._id)
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'export'} w={'14px'} mr={2} />
{t('Export')}
</Flex>
),
onClick: () => onclickExport(dataset._id)
},
{
child: (
<Flex alignItems={'center'}>
<MyIcon name={'delete'} w={'14px'} mr={2} />
{t('common.Delete')}
</Flex>
),
onClick: () => {
openConfirm(
() => onclickDelDataset(dataset._id),
undefined,
DeleteTipsMap.current[dataset.type]
)();
}
}
]}
/>
)}
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={dataset.avatar} borderRadius={'lg'} w={'28px'} />
<Box mx={3} className="textEllipsis3">
@@ -372,14 +413,20 @@ const Kb = () => {
</Flex>
<Box flex={'1 0 0'} overflow={'hidden'} pt={2}>
<Flex>
{dataset.tags.map((tag, i) => (
<Tag key={i} mr={2} mb={2}>
{tag}
</Tag>
))}
{dataset.tags
.split(' ')
.filter((item) => item)
.map((tag, i) => (
<Tag key={i} mr={2} mb={2}>
{tag}
</Tag>
))}
</Flex>
</Box>
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
<Flex alignItems={'center'} fontSize={'sm'}>
<Box flex={1}>
<PermissionIconText permission={dataset.permission} color={'myGray.600'} />
</Box>
{dataset.type === DatasetTypeEnum.folder ? (
<Box color={'myGray.500'}>{t('Folder')}</Box>
) : (
@@ -419,7 +466,7 @@ const Kb = () => {
name,
type: DatasetTypeEnum.folder,
avatar: FolderAvatarSrc,
tags: []
tags: ''
});
}
refetch();