style: dataset detail page style refactor (#2501)

* style: dataset detail page style refactor

* remove px

* remove py px px

* change shadow

* style: 2期联调结束

* 优化部分代码
This commit is contained in:
papapatrick
2024-08-28 10:17:49 +08:00
committed by GitHub
parent c9bb39d802
commit bebf565c06
33 changed files with 860 additions and 632 deletions

View File

@@ -85,7 +85,7 @@ const EditResourceModal = ({
w={'2rem'}
h={'2rem'}
cursor={'pointer'}
borderRadius={'md'}
borderRadius={'sm'}
onClick={onOpenSelectFile}
/>
</MyTooltip>

View File

@@ -15,9 +15,10 @@ const DatasetTypeTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & Fle
bg={'myGray.100'}
borderWidth={'1px'}
borderColor={'myGray.200'}
px={4}
py={'6px'}
borderRadius={'md'}
px={3}
py={1.5}
h={'1.75rem'}
borderRadius={'sm'}
fontSize={'xs'}
alignItems={'center'}
{...props}

View File

@@ -1,4 +1,4 @@
import { Box, BoxProps } from '@chakra-ui/react';
import { Box, BoxProps, ButtonProps } from '@chakra-ui/react';
import MySelect from '@fastgpt/web/components/common/MySelect';
import React from 'react';
import type { PermissionValueType } from '@fastgpt/global/support/permission/type';
@@ -20,6 +20,7 @@ type Props = Omit<BoxProps, 'onChange'> & {
writePer?: PermissionValueType;
onChange: (v: PermissionValueType) => Promise<any> | any;
isInheritPermission?: boolean;
isDisabled?: boolean;
hasParent?: boolean;
};
@@ -31,6 +32,7 @@ const DefaultPermissionList = ({
onChange,
isInheritPermission = false,
hasParent,
isDisabled = false,
...styles
}: Props) => {
const { ConfirmModal, openConfirm } = useConfirm({});
@@ -63,6 +65,8 @@ const DefaultPermissionList = ({
return onRequestChange(per);
}
}}
isDisabled={isDisabled}
fontSize={styles?.fontSize}
/>
</Box>
<ConfirmModal />

View File

@@ -1,4 +1,4 @@
import { Box, Button, Flex } from '@chakra-ui/react';
import { Box, Button, Flex, FormLabel } from '@chakra-ui/react';
import React from 'react';
import CollaboratorContextProvider, {
MemberManagerInputPropsType
@@ -9,29 +9,38 @@ import { useTranslation } from 'next-i18next';
function MemberManager({ managePer }: { managePer: MemberManagerInputPropsType }) {
const { t } = useTranslation();
return (
<Box mt={4}>
<Box>
<CollaboratorContextProvider {...managePer}>
{({ MemberListCard, onOpenManageModal, onOpenAddMember }) => {
return (
<>
<Flex alignItems="center" flexDirection="row" justifyContent="space-between" w="full">
<Flex flexDirection="row" gap="2">
<Button
size="sm"
variant="whitePrimary"
leftIcon={<MyIcon w="4" name="common/settingLight" />}
onClick={onOpenManageModal}
>
{t('common:permission.Manage')}
</Button>
<Button
size="sm"
variant="whitePrimary"
leftIcon={<MyIcon w="4" name="support/permission/collaborator" />}
onClick={onOpenAddMember}
>
{t('common:common.Add')}
</Button>
<Box>
<FormLabel fontSize={'mini'}>{t('common:permission.Collaborator')}</FormLabel>
</Box>
<Flex gap={0.5}>
<Box p={1}>
<MyIcon
onClick={onOpenManageModal}
name="common/setting"
w={'1rem'}
h={'1rem'}
color={'myGray.600'}
cursor={'pointer'}
_hover={{ color: 'primary.500' }}
/>
</Box>
<Box p={1}>
<MyIcon
cursor={'pointer'}
onClick={onOpenAddMember}
name="common/addUser"
_hover={{ color: 'primary.500' }}
w={'1rem'}
h={'1rem'}
color={'myGray.600'}
/>
</Box>
</Flex>
</Flex>
<MemberListCard mt={2} p={1.5} bg="myGray.100" borderRadius="md" />

View File

@@ -39,6 +39,7 @@ const FileSourceSelector = dynamic(() => import('../Import/components/FileSource
const Header = ({}: {}) => {
const { t } = useTranslation();
const theme = useTheme();
const { setLoading, feConfigs } = useSystemStore();
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
@@ -110,35 +111,43 @@ const Header = ({}: {}) => {
successToast: t('common:common.Create Success'),
errorToast: t('common:common.Create Failed')
});
const isWebSite = datasetDetail?.type === DatasetTypeEnum.websiteDataset;
return (
<Flex px={[2, 6]} alignItems={'flex-start'} h={'35px'}>
<Box flex={1}>
<Box flex={1} fontWeight={'500'} color={'myGray.900'} h={'100%'}>
<ParentPath
paths={paths.map((path, i) => ({
parentId: path.parentId,
parentName: i === paths.length - 1 ? `${path.parentName}` : path.parentName
}))}
FirstPathDom={
<>
<Box fontWeight={'bold'} fontSize={['sm', 'md']}>
<Flex
flexDir={'column'}
justify={'center'}
h={'100%'}
fontSize={isWebSite ? 'sm' : 'md'}
fontWeight={'500'}
color={'myGray.600'}
>
<Flex align={'center'}>
{!isWebSite && <MyIcon name="common/list" mr={2} w={'20px'} color={'black'} />}
{t(DatasetTypeMap[datasetDetail?.type]?.collectionLabel as any)}({total})
</Box>
</Flex>
{datasetDetail?.websiteConfig?.url && (
<Flex fontSize={'sm'}>
<Flex fontSize={'mini'}>
{t('common:core.dataset.website.Base Url')}:
<Link
href={datasetDetail.websiteConfig.url}
target="_blank"
mr={2}
textDecoration={'underline'}
color={'primary.600'}
color={'blue.700'}
>
{datasetDetail.websiteConfig.url}
</Link>
</Flex>
)}
</>
</Flex>
}
onClick={(e) => {
router.replace({
@@ -202,18 +211,26 @@ const Header = ({}: {}) => {
fontSize={['sm', 'md']}
>
<Flex
alignItems={'center'}
px={5}
px={3.5}
py={2}
borderRadius={'md'}
borderRadius={'sm'}
cursor={'pointer'}
bg={'primary.500'}
overflow={'hidden'}
color={'white'}
h={['28px', '35px']}
>
<MyIcon name={'common/importLight'} mr={2} w={'14px'} />
<Box>{t('common:dataset.collections.Create And Import')}</Box>
<Flex h={'20px'} alignItems={'center'}>
<MyIcon
name={'common/folderImport'}
mr={2}
w={'18px'}
h={'18px'}
color={'white'}
/>
</Flex>
<Box h={'20px'} fontSize={'sm'} fontWeight={'500'}>
{t('common:dataset.collections.Create And Import')}
</Box>
</Flex>
</MenuButton>
}
@@ -323,18 +340,26 @@ const Header = ({}: {}) => {
fontSize={['sm', 'md']}
>
<Flex
alignItems={'center'}
px={5}
px={3.5}
py={2}
borderRadius={'md'}
borderRadius={'sm'}
cursor={'pointer'}
bg={'primary.500'}
overflow={'hidden'}
color={'white'}
h={['28px', '35px']}
>
<MyIcon name={'common/importLight'} mr={2} w={'14px'} />
<Box>{t('common:dataset.collections.Create And Import')}</Box>
<Flex h={'20px'} alignItems={'center'}>
<MyIcon
name={'common/folderImport'}
mr={2}
w={'18px'}
h={'18px'}
color={'white'}
/>
</Flex>
<Box h={'20px'} fontSize={'sm'} fontWeight={'500'}>
{t('common:dataset.collections.Create And Import')}
</Box>
</Flex>
</MenuButton>
}

View File

@@ -121,7 +121,7 @@ const HeaderTagPopOver = () => {
<Input
pl={2}
h={8}
borderRadius={'4px'}
borderRadius={'xs'}
value={searchTag}
placeholder={t('dataset:tag.searchOrAddTag')}
onChange={(e) => setSearchTag(e.target.value)}

View File

@@ -246,7 +246,7 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
flex={'1'}
_hover={{ bg: 'myGray.100' }}
alignItems={'center'}
borderRadius={'4px'}
borderRadius={'xs'}
>
<Flex
flex={'1 0 0'}
@@ -263,7 +263,7 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
bg={'#DBF3FF'}
color={'#0884DD'}
fontSize={'xs'}
borderRadius={'6px'}
borderRadius={'sm'}
>
{item.tag}
</Box>
@@ -299,7 +299,7 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
_hover={{ bg: '#1118240D' }}
mr={2}
p={1}
borderRadius={'6px'}
borderRadius={'sm'}
onClick={() => {
setCurrentAddTag({ ...item, collections });
}}
@@ -313,7 +313,7 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
_hover={{ bg: '#1118240D' }}
mr={2}
p={1}
borderRadius={'6px'}
borderRadius={'sm'}
cursor={'pointer'}
onClick={(e) => {
setCurrentEditTag(item);
@@ -332,7 +332,7 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
display="none"
_hover={{ bg: '#1118240D' }}
p={1}
borderRadius={'6px'}
borderRadius={'sm'}
cursor={'pointer'}
>
<MyIcon name="delete" w={4} />
@@ -441,7 +441,7 @@ const AddTagToCollections = ({
bg={'#DBF3FF'}
color={'#0884DD'}
fontSize={'sm'}
borderRadius={'6px'}
borderRadius={'sm'}
>
{currentAddTag.tag}
</Box>
@@ -496,7 +496,7 @@ const AddTagToCollections = ({
: {})
}}
alignItems={'center'}
borderRadius={'4px'}
borderRadius={'xs'}
key={collection.id}
cursor={'pointer'}
onClick={() => {
@@ -525,7 +525,7 @@ const AddTagToCollections = ({
isChecked={selectedCollections.includes(collection.id)}
/>
<MyIcon name={collection.icon as any} w={'20px'} mr={2} />
<Box fontSize={'14px'} borderRadius={'6px'} color={'myGray.900'}>
<Box fontSize={'sm'} borderRadius={'sm'} color={'myGray.900'}>
{collection.name}
</Box>
</Flex>

View File

@@ -161,7 +161,7 @@ const TagsPopOver = ({
fontWeight={'500'}
bg={'#F0FBFF'}
color={'#0884DD'}
borderRadius={'4px'}
borderRadius={'xs'}
>
{item.tag}
</Box>
@@ -197,7 +197,7 @@ const TagsPopOver = ({
onBlur={() => setIsFocusInput(false)}
pl={2}
h={7}
borderRadius={'4px'}
borderRadius={'xs'}
value={searchTag}
placeholder={t('dataset:tag.searchOrAddTag')}
onChange={(e) => setSearchTag(e.target.value)}
@@ -217,7 +217,7 @@ const TagsPopOver = ({
// setCheckedTags([...checkedTags, item]);
}}
>
<MyIcon name={'common/addLight'} w={'14px'} />
<MyIcon name={'common/addLight'} w={'sm'} />
<Box ml={1} py={1}>
{t('dataset:tag.add') + ` "${searchTag}"`}
</Box>
@@ -277,7 +277,7 @@ const TagsPopOver = ({
fontSize={'11px'}
bg={'#F0FBFF'}
color={'#0884DD'}
borderRadius={'4px'}
borderRadius={'xs'}
>
{tag.tag}
</Box>

View File

@@ -186,12 +186,12 @@ const CollectionCard = () => {
return (
<MyBox isLoading={isLoading} h={'100%'} py={[2, 4]}>
<Flex ref={BoxRef} flexDirection={'column'} py={[1, 3]} h={'100%'}>
<Flex ref={BoxRef} flexDirection={'column'} py={[1, 0]} h={'100%'}>
{/* header */}
<Header />
{/* collection table */}
<TableContainer px={[2, 6]} mt={[0, 3]} flex={'1 0 0'} overflowY={'auto'} fontSize={'sm'}>
<TableContainer px={[2, 6]} mt={[0, 3]} overflowY={'auto'} fontSize={'sm'}>
<Table variant={'simple'} draggable={false}>
<Thead draggable={false}>
<Tr>

View File

@@ -7,12 +7,6 @@ import {
Grid,
Button,
useTheme,
Drawer,
DrawerBody,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
DrawerContent,
useDisclosure,
HStack
} from '@chakra-ui/react';
@@ -52,6 +46,8 @@ import MyBox from '@fastgpt/web/components/common/MyBox';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import TagsPopOver from './CollectionCard/TagsPopOver';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyDivider from '@fastgpt/web/components/common/MyDivider';
import index from '../../../index';
const DataCard = () => {
const BoxRef = useRef<HTMLDivElement>(null);
@@ -67,7 +63,6 @@ const DataCard = () => {
const { feConfigs } = useSystemStore();
const { t } = useTranslation();
const { datasetT } = useI18n();
const [searchText, setSearchText] = useState('');
const { toast } = useToast();
const { openConfirm, ConfirmModal } = useConfirm({
@@ -132,66 +127,6 @@ const DataCard = () => {
const canWrite = useMemo(() => datasetDetail.permission.hasWritePer, [datasetDetail]);
const metadataList = useMemo(() => {
if (!collection) return [];
const webSelector =
collection?.datasetId?.websiteConfig?.selector || collection?.metadata?.webPageSelector;
return [
{
label: t('common:core.dataset.collection.metadata.source'),
value: t(DatasetCollectionTypeMap[collection.type]?.name as any)
},
{
label: t('common:core.dataset.collection.metadata.source name'),
value: collection.file?.filename || collection?.rawLink || collection?.name
},
{
label: t('common:core.dataset.collection.metadata.source size'),
value: collection.file ? formatFileSize(collection.file.length) : '-'
},
{
label: t('common:core.dataset.collection.metadata.Createtime'),
value: formatTime2YMDHM(collection.createTime)
},
{
label: t('common:core.dataset.collection.metadata.Updatetime'),
value: formatTime2YMDHM(collection.updateTime)
},
{
label: t('common:core.dataset.collection.metadata.Raw text length'),
value: collection.rawTextLength ?? '-'
},
{
label: t('common:core.dataset.collection.metadata.Training Type'),
value: t(TrainingTypeMap[collection.trainingType]?.label as any)
},
{
label: t('common:core.dataset.collection.metadata.Chunk Size'),
value: collection.chunkSize || '-'
},
...(webSelector
? [
{
label: t('common:core.dataset.collection.metadata.Web page selector'),
value: webSelector
}
]
: []),
{
...(collection.tags
? [
{
label: datasetT('collection_tags'),
value: collection.tags?.join(', ') || '-'
}
]
: [])
}
];
}, [collection, datasetT, t]);
const { run: onUpdate, loading } = useRequest2(putDatasetDataById, {
onSuccess() {
getData(pageNum);
@@ -205,23 +140,6 @@ const DataCard = () => {
<Flex ref={BoxRef} flexDirection={'column'} h={'100%'}>
{/* Header */}
<Flex alignItems={'center'} px={5}>
<IconButton
mr={3}
icon={<MyIcon name={'common/backFill'} w={['14px', '18px']} color={'primary.500'} />}
variant={'whitePrimary'}
size={'smSquare'}
borderRadius={'50%'}
aria-label={''}
onClick={() =>
router.replace({
query: {
datasetId: router.query.datasetId,
parentId: router.query.parentId,
currentTab: TabEnum.collectionCard
}
})
}
/>
<Flex className="textEllipsis" flex={'1 0 0'} mr={[3, 5]} alignItems={'center'}>
<Box>
<Box alignItems={'center'} gap={2} display={isPc ? 'flex' : ''}>
@@ -234,12 +152,6 @@ const DataCard = () => {
textDecoration={'none'}
/>
)}
<Box fontSize={'sm'} color={'myGray.500'}>
{t('common:core.dataset.collection.id')}:{' '}
<Box as={'span'} userSelect={'all'}>
{collection?._id}
</Box>
</Box>
</Box>
{feConfigs?.isPlus && !!collection?.tags?.length && (
<TagsPopOver currentCollection={collection} />
@@ -250,7 +162,6 @@ const DataCard = () => {
<Box>
<Button
ml={2}
mr={isPc ? 2 : 0}
variant={'whitePrimary'}
size={['sm', 'md']}
onClick={() => {
@@ -262,24 +173,17 @@ const DataCard = () => {
</Button>
</Box>
)}
{isPc && (
<MyTooltip label={t('common:core.dataset.collection.metadata.Read Metadata')}>
<IconButton
variant={'whiteBase'}
size={['sm', 'md']}
icon={<MyIcon name={'menu'} w={'18px'} />}
aria-label={''}
onClick={onOpen}
/>
</MyTooltip>
)}
</Flex>
<Flex my={3} alignItems={'center'} px={5}>
<Box>
<Box as={'span'} fontSize={['sm', 'md']}>
<Box justifyContent={'center'} px={5} pos={'relative'} w={'100%'}>
<MyDivider my={'17px'} w={'100%'} />
</Box>
<Flex alignItems={'center'} px={5} pb={4}>
<Flex align={'center'} color={'myGray.500'}>
<MyIcon name="common/list" mr={2} w={'18px'} />
<Box as={'span'} fontSize={['sm', '14px']} fontWeight={'500'}>
{t('core.dataset.data.Total Amount', { total })}
</Box>
</Box>
</Flex>
<Box flex={1} mr={1} />
<MyInput
leftIcon={
@@ -287,9 +191,12 @@ const DataCard = () => {
name="common/searchLight"
position={'absolute'}
w={'14px'}
color={'myGray.500'}
color={'myGray.600'}
/>
}
bg={'myGray.25'}
borderColor={'myGray.200'}
color={'myGray.500'}
w={['200px', '300px']}
placeholder={t('common:core.dataset.data.Search data placeholder')}
value={searchText}
@@ -300,45 +207,59 @@ const DataCard = () => {
</Flex>
{/* data */}
<Box flex={'1 0 0'} overflow={'auto'} px={5}>
<Grid
gridTemplateColumns={['1fr', 'repeat(2,1fr)', 'repeat(3,1fr)', 'repeat(4,1fr)']}
gridGap={4}
>
{datasetDataList.map((item) => (
<Flex flexDir={'column'} gap={2}>
{datasetDataList.map((item, index) => (
<Card
key={item._id}
cursor={'pointer'}
p={3}
userSelect={'none'}
boxShadow={'none'}
bg={'myWhite.500'}
bg={index % 2 === 1 ? 'myGray.50' : 'blue.50'}
border={theme.borders.sm}
position={'relative'}
overflow={'hidden'}
_hover={{
borderColor: 'myGray.200',
borderColor: 'blue.600',
boxShadow: 'lg',
bg: 'white',
'& .footer': { h: 'auto', p: 3 },
'& .forbid-switch': { display: 'flex' }
'& .header': { visibility: 'visible' },
'& .footer': { visibility: 'visible' },
'& .forbid-switch': { display: 'flex' },
bg: index % 2 === 1 ? 'myGray.200' : 'blue.100'
}}
onClick={() => {
if (!collection) return;
setEditDataId(item._id);
}}
>
<Flex zIndex={1} alignItems={'center'}>
<MyTag type="borderFill"># {item.chunkIndex ?? '-'}</MyTag>
<Box
className={'textEllipsis'}
flex={'1 0 0'}
w="0"
fontSize={'mini'}
textAlign={'right'}
<Flex
position={'absolute'}
zIndex={1}
alignItems={'center'}
visibility={'hidden'}
className="header"
>
<MyTag
px={2}
type="borderFill"
borderRadius={'sm'}
border={'1px'}
color={'myGray.200'}
bg={'white'}
fontWeight={'500'}
>
ID:{item._id}
</Box>
<Box color={'blue.600'}>#{item.chunkIndex ?? '-'} </Box>
<Box
ml={1.5}
className={'textEllipsis'}
fontSize={'mini'}
textAlign={'right'}
color={'myGray.500'}
>
ID:{item._id}
</Box>
</MyTag>
{/* {item.forbid ? (
<MyTag colorSchema="gray" bg={'transparent'} px={1} showDot>
{datasetT('Disabled')}
@@ -390,54 +311,69 @@ const DataCard = () => {
<Flex
className="footer"
position={'absolute'}
top={0}
bottom={0}
left={0}
right={0}
h={'0'}
bottom={2}
right={2}
overflow={'hidden'}
bg={'linear-gradient(to top, white,white 20%, rgba(255,255,255,0) 60%)'}
alignItems={'flex-end'}
visibility={'hidden'}
fontSize={'mini'}
>
<HStack p={0} flex={1}>
<Flex alignItems={'center'}>
<MyIcon name="common/text/t" w={'0.8rem'} mr={1} color={'myGray.500'} />
<Box>{item.q.length + (item.a?.length || 0)}</Box>
</Flex>
<Box flex={1}></Box>
{/* <Box className={'textEllipsis'} flex={'1 0 0'} w="0">
ID:{item._id}
</Box> */}
{canWrite && (
<IconButton
display={'flex'}
icon={<DeleteIcon />}
variant={'whiteDanger'}
size={'xsSquare'}
aria-label={'delete'}
onClick={(e) => {
e.stopPropagation();
openConfirm(async () => {
try {
await delOneDatasetDataById(item._id);
getData(pageNum);
} catch (error) {
toast({
title: getErrText(error),
status: 'error'
});
}
})();
}}
/>
)}
</HStack>
<Flex
alignItems={'center'}
bg={'white'}
color={'myGray.600'}
borderRadius={'sm'}
border={'1px'}
borderColor={'myGray.200'}
h={'24px'}
px={2}
fontSize={'mini'}
boxShadow={'1'}
py={1}
mr={2}
>
<MyIcon
bg={'white'}
color={'myGray.600'}
borderRadius={'sm'}
border={'1px'}
borderColor={'myGray.200'}
name="common/text/t"
w={'14px'}
mr={1}
/>
{item.q.length + (item.a?.length || 0)}
</Flex>
{canWrite && (
<IconButton
display={'flex'}
p={1}
boxShadow={'1'}
icon={<MyIcon name={'common/trash'} w={'14px'} color={'myGray.600'} />}
variant={'whiteDanger'}
size={'xsSquare'}
aria-label={'delete'}
onClick={(e) => {
e.stopPropagation();
openConfirm(async () => {
try {
await delOneDatasetDataById(item._id);
getData(pageNum);
} catch (error) {
toast({
title: getErrText(error),
status: 'error'
});
}
})();
}}
/>
)}
</Flex>
</Box>
</Card>
))}
</Grid>
</Flex>
{total > pageSize && (
<Flex mt={2} justifyContent={'center'}>
<Pagination />
@@ -447,38 +383,6 @@ const DataCard = () => {
</Box>
</Flex>
{/* metadata drawer */}
<Drawer isOpen={isOpen} placement="right" size={'md'} onClose={onClose}>
<DrawerOverlay />
<DrawerContent>
<DrawerHeader fontSize={'lg'}>
{t('common:core.dataset.collection.metadata.metadata')}
</DrawerHeader>
<DrawerBody>
{metadataList.map((item, i) => (
<Flex key={i} alignItems={'center'} mb={5} wordBreak={'break-all'} fontSize={'sm'}>
<Box color={'myGray.500'} flex={'0 0 100px'}>
{item.label}
</Box>
<Box>{item.value}</Box>
</Flex>
))}
{collection?.sourceId && (
<Button variant={'whitePrimary'} onClick={readSource}>
{t('common:core.dataset.collection.metadata.read source')}
</Button>
)}
</DrawerBody>
<DrawerFooter>
<Button variant={'whitePrimary'} onClick={onClose}>
{t('common:common.Close')}
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
{editDataId !== undefined && collection && (
<InputDataModal
collectionId={collection._id}

View File

@@ -6,7 +6,7 @@ import { ImportDataSourceEnum, TrainingModeEnum } from '@fastgpt/global/core/dat
import { useMyStep } from '@fastgpt/web/hooks/useStep';
import { Box, Button, Flex, IconButton } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { TabEnum } from '../Slider';
import { TabEnum } from '../NavBar';
import { ImportProcessWayEnum } from '@/web/core/dataset/constants';
import { UseFormReturn, useForm } from 'react-hook-form';
import { ImportSourceItemType } from '@/web/core/dataset/type';

View File

@@ -272,7 +272,7 @@ function DataProcess({ showPreviewChunks = true }: { showPreviewChunks: boolean
<Box mt={5} pl={[0, '100px']} gap={3}>
{feConfigs?.show_pay && (
<MyTooltip label={priceTip}>
<MyTag colorSchema={'gray'} py={'6px'} borderRadius={'md'} px={3} whiteSpace={'wrap'}>
<MyTag colorSchema={'gray'} py={1.5} borderRadius={'md'} px={3} whiteSpace={'wrap'}>
{priceTip}
</MyTag>
</MyTooltip>

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, Button, IconButton, Input, Textarea, HStack } from '@chakra-ui/react';
import { DeleteIcon } from '@chakra-ui/icons';
@@ -16,15 +16,15 @@ import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
import AIModelSelector from '@/components/Select/AIModelSelector';
import { postRebuildEmbedding } from '@/web/core/dataset/api';
import { useI18n } from '@/web/context/I18n';
import type { VectorModelItemType } from '@fastgpt/global/core/ai/model.d';
import { useContextSelector } from 'use-context-selector';
import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext';
import MyDivider from '@fastgpt/web/components/common/MyDivider/index';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import DefaultPermissionList from '@/components/support/permission/DefaultPerList';
import MyIcon from '@fastgpt/web/components/common/Icon';
import {
DatasetDefaultPermissionVal,
DatasetPermissionList
@@ -35,18 +35,23 @@ import {
postUpdateDatasetCollaborators,
deleteDatasetCollaborators
} from '@/web/core/dataset/api/collaborator';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
import dynamic from 'next/dynamic';
import { EditResourceInfoFormType } from '@/components/common/Modal/EditResourceModal';
const EditResourceModal = dynamic(() => import('@/components/common/Modal/EditResourceModal'));
const Info = ({ datasetId }: { datasetId: string }) => {
const router = useRouter();
const [openBaseConfig, setOpenBaseConfig] = useState(true);
const [openPermissionConfig, setOpenPermissionConfig] = useState(true);
const { t } = useTranslation();
const { datasetT, commonT } = useI18n();
const { datasetDetail, loadDatasetDetail, updateDataset, rebuildingCount, trainingCount } =
useContextSelector(DatasetPageContext, (v) => v);
const [editedDataset, setEditedDataset] = useState<EditResourceInfoFormType>();
const refetchDatasetTraining = useContextSelector(
DatasetPageContext,
(v) => v.refetchDatasetTraining
);
const { setValue, register, handleSubmit, watch } = useForm<DatasetItemType>({
defaultValues: datasetDetail
});
@@ -57,16 +62,13 @@ const Info = ({ datasetId }: { datasetId: string }) => {
const defaultPermission = watch('defaultPermission');
const { datasetModelList, vectorModelList } = useSystemStore();
const router = useRouter();
const { openConfirm: onOpenConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
content: t('common:core.dataset.Delete Confirm'),
type: 'delete'
});
const { openConfirm: onOpenConfirmRebuild, ConfirmModal: ConfirmRebuildModal } = useConfirm({
title: t('common:common.confirm.Common Tip'),
content: datasetT('confirm_to_rebuild_embedding_tip'),
content: t('dataset:confirm_to_rebuild_embedding_tip'),
type: 'delete'
});
@@ -87,13 +89,10 @@ const Info = ({ datasetId }: { datasetId: string }) => {
errorToast: t('common:common.Delete Failed')
});
const { mutate: onclickSave, isLoading: isSaving } = useRequest({
const { mutate: onSave, isLoading: isSaving } = useRequest({
mutationFn: (data: DatasetItemType) => {
return updateDataset({
id: datasetId,
name: data.name,
avatar: data.avatar,
intro: data.intro,
agentModel: data.agentModel,
externalReadUrl: data.externalReadUrl,
defaultPermission: data.defaultPermission
@@ -133,156 +132,191 @@ const Info = ({ datasetId }: { datasetId: string }) => {
refetchDatasetTraining();
loadDatasetDetail(datasetId);
},
successToast: datasetT('rebuild_embedding_start_tip'),
successToast: t('dataset:rebuild_embedding_start_tip'),
errorToast: t('common:common.Update Failed')
});
const btnLoading = isSelecting || isDeleting || isSaving || isRebuilding;
const totalLoading = isSelecting || isDeleting || isSaving || isRebuilding;
return (
<Box py={5} px={[5, 10]}>
<Flex mt={5} w={'100%'} alignItems={'center'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{t('common:core.dataset.Dataset ID')}
</FormLabel>
<Box flex={1}>{datasetDetail._id}</Box>
</Flex>
<Flex mt={8} w={'100%'} alignItems={'center'} flexWrap={'wrap'}>
<HStack flex={['0 0 90px', '0 0 160px']} w={0} spacing={1}>
<FormLabel>{t('common:core.ai.model.Vector Model')}</FormLabel>
<QuestionTip label={t('common:core.dataset.embedding model tip')} />
</HStack>
<Box flex={[1, '0 0 320px']}>
<AIModelSelector
w={'100%'}
value={vectorModel.model}
disableTip={
rebuildingCount > 0 || trainingCount > 0
? datasetT('the_knowledge_base_has_indexes_that_are_being_trained_or_being_rebuilt')
: undefined
<Box w={'100%'} h={'100%'} p={6}>
<Box>
<Flex mb={2} alignItems={'center'}>
<Avatar src={datasetDetail.avatar} w={'20px'} h={'20px'} borderRadius={'xs'} />
<Box ml={1.5}>
<Box fontWeight={'bold'} color={'myGray.900'}>
{datasetDetail.name}
</Box>
</Box>
<MyIcon
pl={1.5}
name={'edit'}
_hover={{ color: 'primary.600' }}
w={'0.875rem'}
cursor={'pointer'}
onClick={() =>
setEditedDataset({
id: datasetDetail._id,
name: datasetDetail.name,
avatar: datasetDetail.avatar,
intro: datasetDetail.intro
})
}
list={vectorModelList.map((item) => ({
label: item.name,
value: item.model
}))}
onchange={(e) => {
const vectorModel = vectorModelList.find((item) => item.model === e);
if (!vectorModel) return;
onOpenConfirmRebuild(() => {
setValue('vectorModel', vectorModel);
onRebuilding(vectorModel);
})();
}}
/>
</Box>
</Flex>
<Flex mt={8} w={'100%'} alignItems={'center'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{t('common:core.Max Token')}
</FormLabel>
<Box flex={[1, '0 0 320px']}>{vectorModel.maxToken}</Box>
</Flex>
<Flex mt={6} alignItems={'center'} flexWrap={'wrap'}>
<HStack flex={['0 0 90px', '0 0 160px']} w={0} spacing={1}>
<FormLabel>{t('common:core.ai.model.Dataset Agent Model')}</FormLabel>
<QuestionTip label={t('dataset:file_model_function_tip')} />
</HStack>
<Box flex={[1, '0 0 320px']}>
<AIModelSelector
w={'100%'}
value={agentModel.model}
list={datasetModelList.map((item) => ({
label: item.name,
value: item.model
}))}
onchange={(e) => {
const agentModel = datasetModelList.find((item) => item.model === e);
if (!agentModel) return;
setValue('agentModel', agentModel);
}}
/>
</Box>
</Flex>
<MyDivider my={6} h={'2px'} maxW={'500px'} />
{datasetDetail.type === DatasetTypeEnum.externalFile && (
<>
<Flex w={'100%'} alignItems={'center'}>
<FormLabel
display={'flex'}
flex={['0 0 90px', '0 0 160px']}
w={0}
gap={1}
alignItems={'center'}
>
<Box>{datasetT('external_read_url')}</Box>
<QuestionTip label={datasetT('external_read_url_tip')} />
</FormLabel>
<Input
flex={[1, '0 0 320px']}
placeholder="https://test.com/read?fileId={{fileId}}"
{...register('externalReadUrl')}
/>
</Flex>
{DatasetTypeMap[datasetDetail.type] && (
<Flex alignItems={'center'} justifyContent={'space-between'}>
<DatasetTypeTag type={datasetDetail.type} />
</Flex>
<MyDivider my={6} h={'2px'} maxW={'500px'} />
</>
)}
<Flex mt={5} w={'100%'} alignItems={'center'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{t('common:core.dataset.Avatar')}
</FormLabel>
<Box flex={[1, '0 0 320px']}>
<MyTooltip label={t('common:common.avatar.Select Avatar')}>
<Avatar
m={'auto'}
src={avatar}
w={['32px', '40px']}
h={['32px', '40px']}
cursor={'pointer'}
borderRadius={'md'}
onClick={onOpenSelectFile}
/>
</MyTooltip>
)}
<Box
flex={1}
className={'textEllipsis3'}
pt={3}
wordBreak={'break-all'}
fontSize={'xs'}
color={'myGray.500'}
>
{datasetDetail.intro || t('common:core.dataset.Intro Placeholder')}
</Box>
</Flex>
<Flex mt={8} w={'100%'} alignItems={'center'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{t('common:core.dataset.Name')}
</FormLabel>
<Input flex={[1, '0 0 320px']} maxLength={30} {...register('name')} />
</Flex>
<Flex mt={8} alignItems={'center'} w={'100%'}>
<FormLabel flex={['0 0 90px', '0 0 160px']}>{t('common:common.Intro')}</FormLabel>
<Textarea
flex={[1, '0 0 320px']}
{...register('intro')}
placeholder={t('common:common.Intro')}
/>
</Flex>
</Box>
<MyDivider my={4} h={'2px'} maxW={'500px'} />
<Box overflow={'hidden'} h={openBaseConfig ? 'auto' : '24px'}>
<Flex justify={'space-between'} alignItems={'center'} fontSize={'mini'} h={'24px'}>
<Box fontWeight={'500'} color={'myGray.900'}>
{t('common:common.base_config')}
</Box>
<MyIcon
w={'16px'}
_hover={{ color: 'primary.500', cursor: 'pointer' }}
color={'myGray.500'}
name={openBaseConfig ? 'core/chat/chevronUp' : 'core/chat/chevronDown'}
onClick={() => setOpenBaseConfig(!openBaseConfig)}
/>
</Flex>
<Flex mt={3} w={'100%'} flexDir={'column'}>
<FormLabel fontSize={'mini'}>{t('common:core.dataset.Dataset ID')}</FormLabel>
<Box fontSize={'mini'}>{datasetDetail._id}</Box>
</Flex>
<Box mt={5} w={'100%'}>
<FormLabel fontSize={'mini'}>{t('common:core.ai.model.Vector Model')}</FormLabel>
<Box pt={2} flex={[1, '0 0 320px']}>
<AIModelSelector
w={'100%'}
value={vectorModel.model}
fontSize={'mini'}
disableTip={
rebuildingCount > 0 || trainingCount > 0
? t(
'dataset:the_knowledge_base_has_indexes_that_are_being_trained_or_being_rebuilt'
)
: undefined
}
list={vectorModelList.map((item) => ({
label: item.name,
value: item.model
}))}
onchange={(e) => {
const vectorModel = vectorModelList.find((item) => item.model === e);
if (!vectorModel) return;
onOpenConfirmRebuild(() => {
setValue('vectorModel', vectorModel);
onRebuilding(vectorModel);
})();
}}
/>
</Box>
</Box>
<Flex mt={2} w={'100%'} alignItems={'center'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} fontSize={'mini'} w={0}>
{t('common:core.Max Token')}
</FormLabel>
<Box flex={[1, '0 0 320px']} fontSize={'mini'}>
{vectorModel.maxToken}
</Box>
</Flex>
<Box pt={5}>
<FormLabel fontSize={'mini'}>{t('common:core.ai.model.Dataset Agent Model')}</FormLabel>
<Box pt={2}>
<AIModelSelector
w={'100%'}
value={agentModel.model}
list={datasetModelList.map((item) => ({
label: item.name,
value: item.model
}))}
fontSize={'mini'}
onchange={(e) => {
const agentModel = datasetModelList.find((item) => item.model === e);
if (!agentModel) return;
setValue('agentModel', agentModel);
handleSubmit((data) => onSave({ ...data, agentModel: agentModel }))();
}}
isDisabled={totalLoading}
/>
</Box>
</Box>
{/* <MyDivider my={4} h={'2px'} maxW={'500px'} /> */}
{datasetDetail.type === DatasetTypeEnum.externalFile && (
<>
<Box w={'100%'} alignItems={'center'} pt={4}>
<FormLabel display={'flex'} pb={2} fontSize={'mini'}>
<Box>{t('dataset:external_read_url')}</Box>
<QuestionTip label={t('dataset:external_read_url_tip')} />
</FormLabel>
<Input
fontSize={'mini'}
flex={[1, '0 0 320px']}
placeholder="https://test.com/read?fileId={{fileId}}"
{...register('externalReadUrl')}
onBlur={handleSubmit((data) => onSave(data))}
/>
</Box>
</>
)}
</Box>
{datasetDetail.permission.hasManagePer && (
<>
<MyDivider my={6} h={'2px'} maxW={'500px'} />
<MyDivider my={4} h={'2px'} maxW={'500px'} />
<Box overflow={'hidden'} h={openPermissionConfig ? 'auto' : '24px'}>
<Flex justify={'space-between'} alignItems={'center'} fontSize={'mini'} h={'24px'}>
<Box fontWeight={'500'} color={'myGray.900'}>
{t('common:permission.Permission config')}
</Box>
<MyIcon
w={'16px'}
_hover={{ color: 'primary.500', cursor: 'pointer' }}
color={'myGray.500'}
name={openPermissionConfig ? 'core/chat/chevronUp' : 'core/chat/chevronDown'}
onClick={() => setOpenPermissionConfig(!openPermissionConfig)}
/>
</Flex>
<Flex mt={5} alignItems={'center'} w={'100%'} flexWrap={'wrap'} maxW="500px">
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{commonT('permission.Default permission')}
</FormLabel>
<DefaultPermissionList
w="320px"
per={defaultPermission}
defaultPer={DatasetDefaultPermissionVal}
onChange={(v) => setValue('defaultPermission', v)}
/>
</Flex>
<Box mt={3}>
<FormLabel fontSize={'mini'} pb={3}>
{t('common:permission.Default permission')}
</FormLabel>
<DefaultPermissionList
fontSize={'mini'}
per={defaultPermission}
defaultPer={DatasetDefaultPermissionVal}
isDisabled={totalLoading}
onChange={(v) => {
setValue('defaultPermission', v);
handleSubmit((data) => onSave({ ...data, defaultPermission: v }))();
}}
/>
</Box>
<Flex mt={5} alignItems={'center'} w={'100%'} flexWrap={'wrap'} maxW="500px">
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}>
{commonT('permission.Collaborator')}
</FormLabel>
<Box flex={1}>
<Box mt={4}>
<MemberManager
managePer={{
permission: datasetDetail.permission,
@@ -301,35 +335,31 @@ const Info = ({ datasetId }: { datasetId: string }) => {
}}
/>
</Box>
</Flex>
</Box>
</>
)}
<Flex mt={5} w={'100%'} alignItems={'flex-end'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}></Box>
<Button
isLoading={btnLoading}
mr={4}
w={'100px'}
onClick={handleSubmit((data) => onclickSave(data))}
>
{t('common:common.Save')}
</Button>
{datasetDetail.permission.isOwner && (
<IconButton
isLoading={btnLoading}
icon={<DeleteIcon />}
aria-label={''}
variant={'whiteDanger'}
size={'smSquare'}
onClick={onOpenConfirmDel(onclickDelete)}
/>
)}
</Flex>
<File onSelect={onSelectFile} />
<ConfirmDelModal />
<ConfirmRebuildModal countDown={10} />
{editedDataset && (
<EditResourceModal
{...editedDataset}
title={t('common:dataset.Edit Info')}
onClose={() => {
setEditedDataset(undefined);
}}
onEdit={async (data) => {
await updateDataset({
id: editedDataset.id,
name: data.name,
intro: data.intro,
avatar: data.avatar
});
setEditedDataset(undefined);
}}
/>
)}
</Box>
);
};

View File

@@ -0,0 +1,123 @@
import React, { useMemo, useState } from 'react';
import { Box, Flex, Button, IconButton, Input, Textarea, HStack } from '@chakra-ui/react';
import { DeleteIcon } from '@chakra-ui/icons';
import { useTranslation } from 'next-i18next';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { getDatasetCollectionById } from '@/web/core/dataset/api';
import { useRouter } from 'next/router';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { formatFileSize } from '@fastgpt/global/common/file/tools';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import { DatasetCollectionTypeMap, TrainingTypeMap } from '@fastgpt/global/core/dataset/constants';
import { getCollectionSourceAndOpen } from '@/web/core/dataset/hooks/readCollectionSource';
const MetaDataCard = ({ datasetId }: { datasetId: string }) => {
const { t } = useTranslation();
const router = useRouter();
const { collectionId = '' } = router.query as {
collectionId: string;
datasetId: string;
};
const readSource = getCollectionSourceAndOpen(collectionId);
const { data: collection, loading: isLoading } = useRequest2(
() => getDatasetCollectionById(collectionId),
{
onError: () => {
router.replace({
query: {
datasetId
}
});
},
manual: false
}
);
const metadataList = useMemo(() => {
if (!collection) return [];
const webSelector =
collection?.datasetId?.websiteConfig?.selector || collection?.metadata?.webPageSelector;
return [
{
label: t('common:core.dataset.collection.metadata.source'),
value: t(DatasetCollectionTypeMap[collection.type]?.name as any)
},
{
label: t('common:core.dataset.collection.metadata.source name'),
value: collection.file?.filename || collection?.rawLink || collection?.name
},
{
label: t('common:core.dataset.collection.metadata.source size'),
value: collection.file ? formatFileSize(collection.file.length) : '-'
},
{
label: t('common:core.dataset.collection.metadata.Createtime'),
value: formatTime2YMDHM(collection.createTime)
},
{
label: t('common:core.dataset.collection.metadata.Updatetime'),
value: formatTime2YMDHM(collection.updateTime)
},
{
label: t('common:core.dataset.collection.metadata.Raw text length'),
value: collection.rawTextLength ?? '-'
},
{
label: t('common:core.dataset.collection.metadata.Training Type'),
value: t(TrainingTypeMap[collection.trainingType]?.label as any)
},
{
label: t('common:core.dataset.collection.metadata.Chunk Size'),
value: collection.chunkSize || '-'
},
...(webSelector
? [
{
label: t('common:core.dataset.collection.metadata.Web page selector'),
value: webSelector
}
]
: []),
{
...(collection.tags
? [
{
label: t('dataset:collection_tags'),
value: collection.tags?.join(', ') || '-'
}
]
: [])
}
];
}, [collection, t]);
return (
<MyBox isLoading={isLoading} w={'100%'} h={'100%'} p={6}>
<Box fontSize={'lg'} pb={4}>
{t('common:core.dataset.collection.metadata.metadata')}
</Box>
<Box fontSize={'sm'} color={'myGray.500'} mb={5}>
{t('common:core.dataset.collection.id')}:{' '}
<Box as={'span'} userSelect={'all'}>
{collection?._id}
</Box>
</Box>
{metadataList.map((item, i) => (
<Flex key={i} alignItems={'center'} mb={5} wordBreak={'break-all'} fontSize={'sm'}>
<Box color={'myGray.500'} flex={'0 0 100px'}>
{item.label}
</Box>
<Box>{item.value}</Box>
</Flex>
))}
{collection?.sourceId && (
<Button variant={'whitePrimary'} onClick={readSource}>
{t('common:core.dataset.collection.metadata.read source')}
</Button>
)}
</MyBox>
);
};
export default React.memo(MetaDataCard);

View File

@@ -0,0 +1,212 @@
import React, { useCallback } from 'react';
import { useTranslation } from 'next-i18next';
import { Box, Flex, IconButton, useTheme, Progress } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRouter } from 'next/router';
import { useContextSelector } from 'use-context-selector';
import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import { useI18n } from '@/web/context/I18n';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import MyPopover from '@fastgpt/web/components/common/MyPopover';
export enum TabEnum {
dataCard = 'dataCard',
collectionCard = 'collectionCard',
test = 'test',
info = 'info',
import = 'import'
}
const NavBar = ({ currentTab }: { currentTab: TabEnum }) => {
const theme = useTheme();
const { t } = useTranslation();
const { datasetT } = useI18n();
const router = useRouter();
const query = router.query;
const { isPc } = useSystem();
const { datasetDetail, vectorTrainingMap, agentTrainingMap, rebuildingCount } =
useContextSelector(DatasetPageContext, (v) => v);
const tabList = [
{
label: t('common:core.dataset.Collection'),
value: TabEnum.collectionCard
},
{ label: t('common:core.dataset.test.Search Test'), value: TabEnum.test },
...(datasetDetail.permission.hasManagePer && !isPc
? [{ label: t('common:common.Config'), value: TabEnum.info }]
: [])
];
const setCurrentTab = useCallback(
(tab: TabEnum) => {
router.replace({
query: {
datasetId: query.datasetId,
currentTab: tab
}
});
},
[query, router]
);
return (
<>
{isPc ? (
<Flex
py={2}
px={4}
justify={'space-between'}
borderBottom={theme.borders.base}
borderColor={'myGray.200'}
position={'relative'}
>
<Flex
alignItems={'center'}
cursor={'pointer'}
py={'0.38rem'}
px={2}
h={10}
borderRadius={'md'}
_hover={{ bg: 'myGray.05' }}
fontSize={'sm'}
fontWeight={500}
onClick={() => {
if (currentTab !== TabEnum.dataCard) router.replace('/dataset/list');
else
router.replace({
query: {
datasetId: router.query.datasetId,
parentId: router.query.parentId,
currentTab: TabEnum.collectionCard
}
});
}}
>
<IconButton
p={2}
mr={2}
w={'1.5rem'}
h={'24px'}
border={'1px solid'}
borderColor={'myGray.200'}
boxShadow={'1'}
icon={<MyIcon name={'common/arrowLeft'} w={'16px'} color={'myGray.500'} />}
bg={'white'}
size={'smSquare'}
borderRadius={'50%'}
aria-label={''}
_hover={'none'}
/>
<Box fontWeight={500} color={'myGray.600'} fontSize={'sm'}>
{currentTab !== TabEnum.dataCard
? t('common:core.dataset.All Dataset')
: datasetDetail.name}
</Box>
</Flex>
<Box position={'absolute'} left={'50%'} transform={'translateX(-50%)'}>
<LightRowTabs<TabEnum>
px={4}
py={1}
visibility={currentTab === TabEnum.dataCard ? 'hidden' : 'visible'}
flex={1}
mx={'auto'}
w={'100%'}
list={tabList}
value={currentTab}
activatedColor="blue.700"
onChange={setCurrentTab}
inlineStyles={{
fontSize: '1rem',
lineHeight: '1.5rem',
fontWeight: 500,
border: 'none',
_hover: {
bg: 'myGray.05',
color: 'blue.700'
},
borderRadius: '6px'
}}
/>
</Box>
{/* 训练情况hover弹窗 */}
<MyPopover
placement="bottom-end"
visibility={currentTab === TabEnum.collectionCard ? 'visible' : 'hidden'}
trigger="hover"
Trigger={
<Flex
visibility={currentTab === TabEnum.collectionCard ? 'visible' : 'hidden'}
alignItems={'center'}
justifyContent={'center'}
p={2}
borderRadius={'md'}
_hover={{
bg: 'myGray.05'
}}
>
<MyIcon name={'common/monitor'} w={'18px'} h={'18px'} color={'myGray.500'} />
<Box color={'myGray.600'} ml={1.5} fontWeight={500}>
{t('common:core.dataset.training.tag')}
</Box>
</Flex>
}
>
{({ onClose }) => (
<Box p={6}>
{rebuildingCount > 0 && (
<Box mb={3}>
<Box fontSize={'sm'}>
{datasetT('rebuilding_index_count', { count: rebuildingCount })}
</Box>
</Box>
)}
<Box mb={3}>
<Box fontSize={'sm'} pb={1}>
{t('common:core.dataset.training.Agent queue')}({agentTrainingMap.tip})
</Box>
<Progress
value={100}
size={'xs'}
colorScheme={agentTrainingMap.colorSchema}
borderRadius={'md'}
isAnimated
hasStripe
/>
</Box>
<Box>
<Box fontSize={'sm'} pb={1}>
{t('common:core.dataset.training.Vector queue')}({vectorTrainingMap.tip})
</Box>
<Progress
value={100}
size={'xs'}
colorScheme={vectorTrainingMap.colorSchema}
borderRadius={'md'}
isAnimated
hasStripe
/>
</Box>
</Box>
)}
</MyPopover>
</Flex>
) : (
<Box mb={3}>
<LightRowTabs<TabEnum>
m={'auto'}
w={'full'}
size={'sm'}
list={tabList}
value={currentTab}
onChange={setCurrentTab}
/>
</Box>
)}
</>
);
};
export default NavBar;

View File

@@ -1,165 +0,0 @@
import React, { useCallback } from 'react';
import { useTranslation } from 'next-i18next';
import { Box, Flex, IconButton, useTheme, Progress } from '@chakra-ui/react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import Avatar from '@fastgpt/web/components/common/Avatar';
import { DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
import MyIcon from '@fastgpt/web/components/common/Icon';
import SideTabs from '@/components/SideTabs';
import { useRouter } from 'next/router';
import { useContextSelector } from 'use-context-selector';
import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import { useI18n } from '@/web/context/I18n';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
export enum TabEnum {
dataCard = 'dataCard',
collectionCard = 'collectionCard',
test = 'test',
info = 'info',
import = 'import'
}
const Slider = ({ currentTab }: { currentTab: TabEnum }) => {
const theme = useTheme();
const { t } = useTranslation();
const { datasetT } = useI18n();
const router = useRouter();
const query = router.query;
const { isPc } = useSystem();
const { datasetDetail, vectorTrainingMap, agentTrainingMap, rebuildingCount } =
useContextSelector(DatasetPageContext, (v) => v);
const tabList = [
{
label: t('common:core.dataset.Collection'),
value: TabEnum.collectionCard,
icon: 'common/overviewLight'
},
{ label: t('common:core.dataset.test.Search Test'), value: TabEnum.test, icon: 'kbTest' },
...(datasetDetail.permission.hasManagePer
? [{ label: t('common:common.Config'), value: TabEnum.info, icon: 'common/settingLight' }]
: [])
];
const setCurrentTab = useCallback(
(tab: TabEnum) => {
router.replace({
query: {
datasetId: query.datasetId,
currentTab: tab
}
});
},
[query, router]
);
return (
<>
{isPc ? (
<Flex
flexDirection={'column'}
py={4}
h={'100%'}
flex={'0 0 200px'}
borderRight={theme.borders.base}
>
<Box px={4} borderBottom={'1px'} borderColor={'myGray.200'} pb={4} mb={4}>
<Flex mb={4} alignItems={'center'}>
<Avatar src={datasetDetail.avatar} w={'34px'} borderRadius={'md'} />
<Box ml={2}>
<Box fontWeight={'bold'}>{datasetDetail.name}</Box>
</Box>
</Flex>
{DatasetTypeMap[datasetDetail.type] && (
<Flex alignItems={'center'} pl={2} justifyContent={'space-between'}>
<DatasetTypeTag type={datasetDetail.type} />
</Flex>
)}
</Box>
<SideTabs<TabEnum>
px={4}
flex={1}
mx={'auto'}
w={'100%'}
list={tabList}
value={currentTab}
onChange={setCurrentTab}
/>
<Box px={4}>
{rebuildingCount > 0 && (
<Box mb={3}>
<Box fontSize={'sm'}>
{datasetT('rebuilding_index_count', { count: rebuildingCount })}
</Box>
</Box>
)}
<Box mb={3}>
<Box fontSize={'sm'}>
{t('common:core.dataset.training.Agent queue')}({agentTrainingMap.tip})
</Box>
<Progress
value={100}
size={'xs'}
colorScheme={agentTrainingMap.colorSchema}
borderRadius={'10px'}
isAnimated
hasStripe
/>
</Box>
<Box mb={3}>
<Box fontSize={'sm'}>
{t('common:core.dataset.training.Vector queue')}({vectorTrainingMap.tip})
</Box>
<Progress
value={100}
size={'xs'}
colorScheme={vectorTrainingMap.colorSchema}
borderRadius={'10px'}
isAnimated
hasStripe
/>
</Box>
</Box>
<Flex
alignItems={'center'}
cursor={'pointer'}
py={2}
px={3}
borderRadius={'md'}
_hover={{ bg: 'myGray.100' }}
fontSize={'sm'}
onClick={() => router.replace('/dataset/list')}
>
<IconButton
mr={3}
icon={<MyIcon name={'common/backFill'} w={'1rem'} color={'primary.500'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
size={'smSquare'}
borderRadius={'50%'}
aria-label={''}
/>
{t('common:core.dataset.All Dataset')}
</Flex>
</Flex>
) : (
<Box mb={3}>
<LightRowTabs<TabEnum>
m={'auto'}
w={'full'}
size={isPc ? 'md' : 'sm'}
list={tabList}
value={currentTab}
onChange={setCurrentTab}
/>
</Box>
)}
</>
);
};
export default Slider;

View File

@@ -141,7 +141,6 @@ const Test = ({ datasetId }: { datasetId: string }) => {
flex={1}
maxW={'500px'}
py={4}
borderRight={['none', theme.borders.base]}
>
<Box
border={'2px solid'}
@@ -280,7 +279,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
</Button>
</Flex>
</Box>
<Box mt={5} flex={'1 0 0'} px={4} overflow={'overlay'} display={['none', 'block']}>
<Box mt={5} px={4} overflow={'overlay'} display={['none', 'block']}>
<TestHistories
datasetId={datasetId}
datasetTestItem={datasetTestItem}

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { useRouter } from 'next/router';
import { Box } from '@chakra-ui/react';
import { Box, Flex } from '@chakra-ui/react';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { getErrText } from '@fastgpt/global/common/error/utils';
@@ -8,8 +8,8 @@ import dynamic from 'next/dynamic';
import PageContainer from '@/components/PageContainer';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next';
import Slider from './components/Slider';
import MetaDataCard from './components/MetaDataCard';
import NavBar from './components/NavBar';
import MyBox from '@fastgpt/web/components/common/MyBox';
import {
DatasetPageContext,
@@ -19,6 +19,7 @@ import CollectionPageContextProvider from './components/CollectionCard/Context';
import { useContextSelector } from 'use-context-selector';
import NextHead from '@/components/common/NextHead';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
const CollectionCard = dynamic(() => import('./components/CollectionCard/index'));
const DataCard = dynamic(() => import('./components/DataCard'));
@@ -39,6 +40,7 @@ const Detail = ({ datasetId, currentTab }: Props) => {
const { t } = useTranslation();
const { toast } = useToast();
const router = useRouter();
const { isPc } = useSystem();
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
const loadDatasetDetail = useContextSelector(DatasetPageContext, (v) => v.loadDatasetDetail);
const loadAllDatasetTags = useContextSelector(DatasetPageContext, (v) => v.loadAllDatasetTags);
@@ -60,25 +62,71 @@ const Detail = ({ datasetId, currentTab }: Props) => {
return (
<>
<NextHead title={datasetDetail?.name} icon={datasetDetail?.avatar} />
<PageContainer insertProps={{ bg: 'white' }}>
<MyBox display={'flex'} flexDirection={['column', 'row']} h={'100%'} pt={[4, 0]}>
<Slider currentTab={currentTab} />
{!!datasetDetail._id && (
<Box flex={'1 0 0'} pb={0} overflow={'auto'}>
{isPc ? (
<Flex h={'100%'} w={'100%'}>
<Flex
flexGrow={1}
flex={81}
bg={'white'}
w={'100%'}
flexDir={'column'}
my={3}
mr={2}
boxShadow={'2'}
borderRadius={'md'}
>
{currentTab !== TabEnum.import && <NavBar currentTab={currentTab} />}
<Box flex={'1 0 0'} w={'100%'} overflow={'auto'}>
{currentTab === TabEnum.collectionCard && (
<CollectionPageContextProvider>
<CollectionCard />
</CollectionPageContextProvider>
)}
{currentTab === TabEnum.dataCard && <DataCard />}
{currentTab === TabEnum.test && <Test datasetId={datasetId} />}
{currentTab === TabEnum.info && <Info datasetId={datasetId} />}
{currentTab === TabEnum.dataCard && <DataCard />}
{currentTab === TabEnum.import && <Import />}
</Box>
</Flex>
{currentTab !== TabEnum.import && (
<Flex
bg={'white'}
borderRadius={'md'}
overflowY={'scroll'}
boxShadow={'2'}
my={3}
mr={3}
flex={19}
>
{currentTab === TabEnum.dataCard ? (
<MetaDataCard datasetId={datasetId} />
) : (
<Info datasetId={datasetId} />
)}
</Flex>
)}
</MyBox>
</PageContainer>
</Flex>
) : (
<PageContainer insertProps={{ bg: 'white' }}>
<MyBox display={'flex'} flexDirection={['column', 'row']} h={'100%'} pt={[4, 0]}>
<NavBar currentTab={currentTab} />
{!!datasetDetail._id && (
<Box flex={'1 0 0'} pb={0} overflow={'auto'}>
{currentTab === TabEnum.collectionCard && (
<CollectionPageContextProvider>
<CollectionCard />
</CollectionPageContextProvider>
)}
{currentTab === TabEnum.dataCard && <DataCard />}
{currentTab === TabEnum.test && <Test datasetId={datasetId} />}
{currentTab === TabEnum.info && <Info datasetId={datasetId} />}
{currentTab === TabEnum.import && <Import />}
</Box>
)}
</MyBox>
</PageContainer>
)}
</>
);
};

View File

@@ -118,7 +118,7 @@ const CreateModal = ({
<MyModal
title={
<Flex alignItems={'center'} ml={-3}>
<Avatar w={'20px'} h={'20px'} borderRadius={'4px'} src={iconMap[type]} pr={'10px'} />
<Avatar w={'20px'} h={'20px'} borderRadius={'xs'} src={iconMap[type]} pr={'10px'} />
{t('common:core.dataset.Create dataset', { name: databaseNameMap[type] })}
</Flex>
}
@@ -127,9 +127,9 @@ const CreateModal = ({
isCentered={!isPc}
w={'490px'}
>
<ModalBody py={'24px'} px={'36px'}>
<ModalBody py={6} px={9}>
<Box>
<Box color={'myGray.900'} fontWeight={500} fontSize={'14px'}>
<Box color={'myGray.900'} fontWeight={500} fontSize={'sm'}>
{t('common:common.Set Name')}
</Box>
<Flex mt={'12px'} alignItems={'center'}>
@@ -226,7 +226,7 @@ const CreateModal = ({
)}
</ModalBody>
<ModalFooter px={'36px'}>
<ModalFooter px={9}>
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common:common.Close')}
</Button>

View File

@@ -229,7 +229,7 @@ function List() {
>
<HStack>
<Avatar src={dataset.avatar} borderRadius={6} w={'28px'} />
<Box flex={'1 0 0'} className="textEllipsis3">
<Box flex={'1 0 0'} className="textEllipsis3" color={'myGray.900'}>
{dataset.name}
</Box>
@@ -264,7 +264,7 @@ function List() {
h={'24px'}
alignItems={'center'}
justifyContent={'space-between'}
fontSize={'12px'}
fontSize={'sm'}
fontWeight={500}
color={'myGray.500'}
>

View File

@@ -28,7 +28,7 @@ const SideTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps)
return (
<Flex
bg={'myGray.100'}
py={'3px'}
py={0.75}
pl={'8px'}
pr={'12px'}
borderRadius={'md'}

View File

@@ -155,7 +155,7 @@ const Dataset = () => {
placement="bottom-end"
Button={
<Button variant={'primary'} px="0">
<Flex alignItems={'center'} px={'20px'}>
<Flex alignItems={'center'} px={5}>
<AddIcon mr={2} />
<Box>{t('common:common.Create New')}</Box>
</Flex>