Style-dataset-2.5 (#2580)

* style: dataset detail page 2.5

* fix merge error

* fix: flash bug

* fix: build error

* revert: 滚动变回分页
This commit is contained in:
papapatrick
2024-09-02 10:00:55 +08:00
committed by GitHub
parent 060492dbf7
commit fdab383b26
14 changed files with 473 additions and 311 deletions

View File

@@ -60,7 +60,7 @@ const ParentPaths = (props: {
{item.parentName}
</Box>
{i !== concatPaths.length - 1 && (
<Box mx={1.5} color={'myGray.500'}>
<Box mx={1} color={'myGray.500'}>
/
</Box>
)}

View File

@@ -150,7 +150,7 @@ const InputGuideConfig = ({
alignItems={'center'}
cursor={'pointer'}
>
<MyIcon name={'book'} ml={4} mr={1} />
<MyIcon name={'book'} w={'17px'} ml={4} mr={1} color={'myGray.600'} />
{commonT('common.Documents')}
</Flex>
<Box flex={'1 0 0'} />

View File

@@ -275,9 +275,6 @@ const QuoteItem = ({
onSuccess={() => {
console.log('更新引用成功');
}}
onDelete={() => {
console.log('删除引用成功');
}}
dataId={editInputData.dataId}
collectionId={editInputData.collectionId}
/>

View File

@@ -1,4 +1,4 @@
import React, { useState, useRef, useMemo } from 'react';
import React, { useState, useRef, useMemo, useCallback } from 'react';
import {
Box,
Card,
@@ -69,8 +69,6 @@ const DataCard = () => {
content: t('common:dataset.Confirm to delete the data'),
type: 'delete'
});
const { isOpen, onOpen, onClose } = useDisclosure();
const readSource = getCollectionSourceAndOpen(collectionId);
const {
data: datasetDataList,
@@ -136,10 +134,10 @@ const DataCard = () => {
const isLoading = isRequesting || loading;
return (
<MyBox isLoading={isLoading} position={'relative'} py={[1, 5]} h={'100%'}>
<MyBox isLoading={isLoading} position={'relative'} py={[1, 0]} h={'100%'}>
<Flex ref={BoxRef} flexDirection={'column'} h={'100%'}>
{/* Header */}
<Flex alignItems={'center'} px={5}>
<Flex alignItems={'center'} px={6}>
<Flex className="textEllipsis" flex={'1 0 0'} mr={[3, 5]} alignItems={'center'}>
<Box>
<Box alignItems={'center'} gap={2} display={isPc ? 'flex' : ''}>
@@ -174,10 +172,10 @@ const DataCard = () => {
</Box>
)}
</Flex>
<Box justifyContent={'center'} px={5} pos={'relative'} w={'100%'}>
<Box justifyContent={'center'} px={6} pos={'relative'} w={'100%'}>
<MyDivider my={'17px'} w={'100%'} />
</Box>
<Flex alignItems={'center'} px={5} pb={4}>
<Flex alignItems={'center'} px={6} pb={4}>
<Flex align={'center'} color={'myGray.500'}>
<MyIcon name="common/list" mr={2} w={'18px'} />
<Box as={'span'} fontSize={['sm', '14px']} fontWeight={'500'}>
@@ -227,7 +225,7 @@ const DataCard = () => {
'& .forbid-switch': { display: 'flex' },
bg: index % 2 === 1 ? 'myGray.200' : 'blue.100'
}}
onClickCapture={(e) => {
onClick={(e) => {
e.stopPropagation();
if (!collection) return;
setEditDataId(item._id);
@@ -316,7 +314,7 @@ const DataCard = () => {
display={'flex'}
p={1}
boxShadow={'1'}
icon={<MyIcon name={'common/trash'} w={'14px'} />}
icon={<MyIcon name={'common/trash'} w={'14px'} color={'myGray.600'} />}
variant={'whiteDanger'}
size={'xsSquare'}
aria-label={'delete'}
@@ -355,7 +353,6 @@ const DataCard = () => {
dataId={editDataId}
onClose={() => setEditDataId(undefined)}
onSuccess={() => getData(pageNum)}
onDelete={() => getData(pageNum)}
/>
)}
<ConfirmModal />

View File

@@ -1,6 +1,14 @@
import React, { useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Box, Flex, Button, Textarea, useTheme, Grid, HStack } from '@chakra-ui/react';
import { UseFormRegister, useFieldArray, useForm } from 'react-hook-form';
import {
Control,
FieldArrayWithId,
UseFieldArrayAppend,
UseFieldArrayRemove,
UseFormRegister,
useFieldArray,
useForm
} from 'react-hook-form';
import {
postInsertData2Dataset,
putDatasetDataById,
@@ -16,7 +24,7 @@ import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'next-i18next';
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils';
import { getDefaultIndex, getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
import SideTabs from '@/components/SideTabs';
import DeleteIcon from '@fastgpt/web/components/common/Icon/delete';
@@ -27,6 +35,9 @@ import MyBox from '@fastgpt/web/components/common/MyBox';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import styles from './styles.module.scss';
export type InputDataType = {
q: string;
@@ -38,9 +49,7 @@ export type InputDataType = {
enum TabEnum {
content = 'content',
index = 'index',
delete = 'delete',
doc = 'doc'
index = 'index'
}
const InputDataModal = ({
@@ -48,22 +57,20 @@ const InputDataModal = ({
dataId,
defaultValue,
onClose,
onSuccess,
onDelete
onSuccess
}: {
collectionId: string;
dataId?: string;
defaultValue?: { q: string; a?: string };
onClose: () => void;
onSuccess: (data: InputDataType & { dataId: string }) => void;
onDelete?: () => void;
}) => {
const { t } = useTranslation();
const theme = useTheme();
const { toast } = useToast();
const [currentTab, setCurrentTab] = useState(TabEnum.content);
const { vectorModelList } = useSystemStore();
const { isPc } = useSystem();
const { register, handleSubmit, reset, control } = useForm<InputDataType>();
const {
fields: indexes,
@@ -76,19 +83,35 @@ const InputDataModal = ({
const tabList = [
{
label: t('common:dataset.data.edit.Content'),
value: TabEnum.content,
icon: 'common/overviewLight'
label: (
<Flex align={'center'}>
<Box>{t('common:dataset.data.edit.divide_content')}</Box>
</Flex>
),
value: TabEnum.content
},
{
label: t('common:dataset.data.edit.Index', { amount: indexes.length }),
value: TabEnum.index,
icon: 'kbTest'
},
...(dataId
? [{ label: t('common:dataset.data.edit.Delete'), value: TabEnum.delete, icon: 'delete' }]
: []),
{ label: t('common:dataset.data.edit.Course'), value: TabEnum.doc, icon: 'common/courseLight' }
label: (
<Flex align={'center'}>
<Box>{t('common:dataset.data.edit.Index', { amount: indexes.length })}</Box>
<MyTooltip label={t('common:core.app.tool_label.view_doc')}>
<MyIcon
name={'book'}
w={'1rem'}
mr={'0.38rem'}
color={'myGray.500'}
ml={1}
onClick={() => window.open(getDocPath('/docs/course/dataset_engine'), '_blank')}
_hover={{
color: 'primary.600',
cursor: 'pointer'
}}
/>
</MyTooltip>
</Flex>
),
value: TabEnum.index
}
];
const { ConfirmModal, openConfirm } = useConfirm({
@@ -181,7 +204,7 @@ const InputDataModal = ({
a: '',
indexes: []
});
console.log('执行onSuccess');
onSuccess(e);
},
errorToast: t('common:common.error.unKnow')
@@ -215,176 +238,101 @@ const InputDataModal = ({
}
}
);
// delete
const { mutate: onDeleteData, isLoading: isDeleting } = useRequest({
mutationFn: () => {
if (!onDelete || !dataId) return Promise.resolve(null);
return delOneDatasetDataById(dataId);
},
onSuccess() {
if (!onDelete) return;
onDelete();
onClose();
},
successToast: t('common:common.Delete Success'),
errorToast: t('common:common.error.unKnow')
});
const isLoading = isFetchingData || isDeleting;
const isLoading = isFetchingData;
const icon = useMemo(
() => getSourceNameIcon({ sourceName: collection.sourceName, sourceId: collection.sourceId }),
[collection]
);
return (
<MyModal isOpen={true} isCentered w={'90vw'} maxW={'1440px'} h={'90vh'}>
<MyBox isLoading={isLoading} display={'flex'} h={'100%'}>
<Box p={5} bg={'myGray.50'} borderLeftRadius={'md'} borderRight={theme.borders.base}>
<RawSourceBox
w={'210px'}
className="textEllipsis3"
whiteSpace={'pre-wrap'}
collectionId={collection._id}
sourceName={collection.sourceName}
sourceId={collection.sourceId}
mb={6}
fontSize={'sm'}
/>
<SideTabs<TabEnum>
list={tabList}
value={currentTab}
onChange={async (e) => {
if (e === TabEnum.delete) {
return openConfirm(onDeleteData)();
}
if (e === TabEnum.doc) {
return window.open(getDocPath('/docs/course/dataset_engine'), '_blank');
}
setCurrentTab(e);
}}
/>
</Box>
<Flex flexDirection={'column'} pb={8} flex={1} h={'100%'}>
<Box fontSize={'md'} px={5} py={3} fontWeight={'medium'}>
{currentTab === TabEnum.content && (
<>
{dataId
? t('common:dataset.data.Update Data')
: t('common:dataset.data.Input Data')}
</>
)}
{currentTab === TabEnum.index && <> {t('common:dataset.data.Index Edit')}</>}
<MyModal
isOpen={true}
isCentered
w={['20rem', '64rem']}
onClose={() => onClose()}
closeOnOverlayClick={false}
maxW={'1440px'}
h={'46.25rem'}
title={
<Flex ml={-3}>
<MyIcon name={icon as any} w={['16px', '20px']} mr={2} />
<Box
className={'textEllipsis'}
wordBreak={'break-all'}
fontSize={'md'}
maxW={['200px', '80vw']}
fontWeight={'500'}
color={'myGray.900'}
>
{collection.sourceName || t('common:common.UnKnow Source')}
</Box>
<Box flex={1} px={9} overflow={'auto'}>
{currentTab === TabEnum.content && <InputTab maxToken={maxToken} register={register} />}
{currentTab === TabEnum.index && (
<Grid mt={3} gridTemplateColumns={['1fr', '1fr 1fr']} gridGap={4}>
{indexes?.map((index, i) => (
<Box
key={index.dataId || i}
p={4}
borderRadius={'md'}
border={
index.defaultIndex
? '1.5px solid var(--light-fastgpt-primary-opacity-01, rgba(51, 112, 255, 0.10))'
: '1.5px solid var(--Gray-Modern-200, #E8EBF0)'
}
bg={index.defaultIndex ? 'primary.50' : 'myGray.25'}
_hover={{
'& .delete': {
display: index.defaultIndex ? 'none' : 'block'
}
}}
>
<Flex mb={2}>
<Box
flex={1}
fontWeight={'medium'}
color={index.defaultIndex ? 'primary.700' : 'myGray.900'}
>
{index.defaultIndex
? t('common:dataset.data.Default Index')
: t('dataset.data.Custom Index Number', { number: i })}
</Box>
<DeleteIcon
onClick={() => {
if (indexes.length <= 1) {
appendIndexes(getDefaultIndex({ dataId: `${Date.now()}` }));
}
removeIndexes(i);
}}
/>
</Flex>
{index.defaultIndex ? (
<Box fontSize={'sm'} fontWeight={'medium'} color={'myGray.600'}>
{t('common:core.dataset.data.Default Index Tip')}
</Box>
) : (
<Textarea
maxLength={maxToken}
rows={10}
borderColor={'transparent'}
px={0}
pt={0}
_focus={{
px: 3,
py: 2,
borderColor: 'primary.500',
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
bg: 'white'
}}
placeholder={t('common:dataset.data.Index Placeholder')}
{...register(`indexes.${i}.text`, {
required: true
})}
/>
)}
</Box>
))}
<Flex
alignItems={'center'}
justifyContent={'center'}
borderRadius={'md'}
color={'myGray.600'}
fontWeight={'medium'}
border={'1.5px solid var(--Gray-Modern-200, #E8EBF0)'}
bg={'myGray.25'}
cursor={'pointer'}
_hover={{
bg: 'primary.50',
color: 'primary.600',
border:
'1.5px solid var(--light-fastgpt-primary-opacity-01, rgba(51, 112, 255, 0.10))'
}}
minH={'100px'}
onClick={() =>
appendIndexes({
defaultIndex: false,
text: '',
dataId: `${Date.now()}`
})
}
>
<MyIcon name={'common/addLight'} w={'18px'} mr={1.5} />
<Box>{t('common:dataset.data.Add Index')}</Box>
</Flex>
</Grid>
)}
</Box>
{/* footer */}
<Flex justifyContent={'flex-end'} px={9} mt={6}>
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common:common.Close')}
</Button>
<MyTooltip
label={collection.permission.hasWritePer ? '' : t('common:dataset.data.Can not edit')}
>
<Button
isDisabled={!collection.permission.hasWritePer}
isLoading={isImporting || isUpdating}
// @ts-ignore
onClick={handleSubmit(dataId ? onUpdateData : sureImportData)}
>
{dataId ? t('common:common.Confirm Update') : t('common:common.Confirm Import')}
</Button>
</MyTooltip>
</Flex>
}
>
<MyBox
display={'flex'}
flexDir={'column'}
isLoading={isLoading}
h={'100%'}
py={[6, '1.5rem']}
px={[5, '3.25rem']}
>
<Flex justify={'space-between'} gap={4} w={'100%'}>
<Flex justify={'space-between'} pb={4}>
<LightRowTabs<TabEnum>
list={tabList}
p={0}
value={currentTab}
onChange={(e: TabEnum) => setCurrentTab(e)}
/>
</Flex>
{currentTab === TabEnum.index && (
<Button
variant={'whiteBase'}
boxShadow={'1'}
p={0}
onClick={() =>
appendIndexes({
defaultIndex: false,
text: '',
dataId: `${Date.now()}`
})
}
>
<Flex px={'0.62rem'} py={2}>
<MyIcon name={'common/addLight'} w={'1rem'} mr={'0.38rem'} />
{t('common:add_new')}
</Flex>
</Button>
)}
</Flex>
<Box w={'100%'} flexGrow={1} overflow={'scroll'}>
{currentTab === TabEnum.content && <InputTab maxToken={maxToken} register={register} />}
{currentTab === TabEnum.index && (
<DataIndex
register={register}
maxToken={maxToken}
appendIndexes={appendIndexes}
removeIndexes={removeIndexes}
indexes={indexes}
/>
)}
</Box>
<Flex justifyContent={'flex-end'} pt={8} pb={[8, 0]} h={[24, 16]}>
<MyTooltip
label={collection.permission.hasWritePer ? '' : t('common:dataset.data.Can not edit')}
>
<Button
isDisabled={!collection.permission.hasWritePer}
isLoading={isImporting || isUpdating}
// @ts-ignore
onClick={handleSubmit(dataId ? onUpdateData : sureImportData)}
>
{dataId ? t('common:common.Confirm Update') : t('common:common.Confirm Import')}
</Button>
</MyTooltip>
</Flex>
</MyBox>
<ConfirmModal />
@@ -404,44 +352,205 @@ const InputTab = ({
const { t } = useTranslation();
return (
<HStack h={'100%'} spacing={6}>
<Flex flexDirection={'column'} w={'50%'} h={'100%'}>
<Flex pt={3} pb={2} fontWeight={'medium'} fontSize={'md'} alignItems={'center'}>
<Box color={'red.600'}>*</Box>
<Box color={'myGray.900'}>{t('common:core.dataset.data.Main Content')}</Box>
<QuestionTip label={t('common:core.dataset.data.Data Content Tip')} ml={1} />
<>
<Flex h={'100%'} gap={6} flexDir={['column', 'row']} w={'100%'} pr={2}>
<Flex flexDir={'column'} flex={1}>
<Flex mb={2} fontWeight={'medium'} fontSize={'sm'} alignItems={'center'} h={8}>
<Box color={'red.600'}>*</Box>
<Box color={'myGray.900'}>{t('common:core.dataset.data.Main Content')}</Box>
<QuestionTip label={t('common:core.dataset.data.Data Content Tip')} ml={1} />
</Flex>
<Box
borderRadius={'md'}
border={'1.5px solid var(--Gray-Modern-200, #E8EBF0)'}
bg={'myGray.25'}
flex={1}
>
<Textarea
resize={'none'}
placeholder={t('core.dataset.data.Data Content Placeholder', { maxToken })}
className={styles.scrollbar}
maxLength={maxToken}
h={'100%'}
tabIndex={1}
_focus={{
borderColor: 'primary.500',
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
bg: 'white'
}}
borderColor={'transparent'}
bg={'myGray.25'}
{...register(`q`, {
required: true
})}
/>
</Box>
</Flex>
<Box flex={'1 0 0'}>
<Textarea
placeholder={t('core.dataset.data.Data Content Placeholder', { maxToken })}
maxLength={maxToken}
tabIndex={1}
bg={'myGray.50'}
h={'full'}
{...register(`q`, {
required: true
})}
/>
</Box>
</Flex>
<Flex flexDirection={'column'} w={'50%'} h={'100%'}>
<Flex pt={3} pb={2} fontWeight={'medium'} fontSize={'md'} alignItems={'center'}>
<Box color={'myGray.900'}>{t('common:core.dataset.data.Auxiliary Data')}</Box>
<QuestionTip label={t('common:core.dataset.data.Auxiliary Data Tip')} ml={1} />
<Flex flex={1} flexDir={'column'}>
<Flex mb={2} fontWeight={'medium'} fontSize={'sm'} alignItems={'center'} h={8}>
<Box color={'myGray.900'}>{t('common:core.dataset.data.Auxiliary Data')}</Box>
<QuestionTip label={t('common:core.dataset.data.Auxiliary Data Tip')} ml={1} />
</Flex>
<Box
borderRadius={'md'}
border={'1.5px solid '}
borderColor={'myGray.200'}
bg={'myGray.25'}
flex={1}
>
<Textarea
resize={'none'}
placeholder={t('core.dataset.data.Auxiliary Data Placeholder', {
maxToken: maxToken * 1.5
})}
className={styles.scrollbar}
borderColor={'transparent'}
h={'100%'}
tabIndex={1}
bg={'myGray.25'}
maxLength={maxToken * 1.5}
{...register('a')}
/>
</Box>
</Flex>
<Box flex={'1 0 0'}>
<Textarea
placeholder={t('core.dataset.data.Auxiliary Data Placeholder', {
maxToken: maxToken * 1.5
})}
h={'100%'}
tabIndex={1}
bg={'myGray.50'}
maxLength={maxToken * 1.5}
{...register('a')}
/>
</Box>
</Flex>
</HStack>
</>
);
};
const DataIndex = ({
maxToken,
register,
indexes,
appendIndexes,
removeIndexes
}: {
maxToken: number;
register: UseFormRegister<InputDataType>;
indexes: FieldArrayWithId<InputDataType, 'indexes', 'id'>[];
appendIndexes: UseFieldArrayAppend<InputDataType, 'indexes'>;
removeIndexes: UseFieldArrayRemove;
}) => {
const { t } = useTranslation();
return (
<>
<Flex mt={3} gap={3} flexDir={'column'} pr={2}>
<Box
p={4}
borderRadius={'md'}
border={'1.5px solid var(--light-fastgpt-primary-opacity-01, rgba(51, 112, 255, 0.10))'}
bg={'primary.50'}
>
<Flex mb={2}>
<Box flex={1} fontWeight={'medium'} fontSize={'sm'} color={'primary.700'}>
{t('common:dataset.data.Default Index')}
</Box>
</Flex>
<Box fontSize={'sm'} fontWeight={'medium'} color={'myGray.600'}>
{t('common:core.dataset.data.Default Index Tip')}
</Box>
</Box>
{indexes?.map((index, i) => {
return (
!index.defaultIndex && (
<Box
key={index.dataId || i}
p={4}
borderRadius={'md'}
border={'1.5px solid var(--Gray-Modern-200, #E8EBF0)'}
bg={'myGray.25'}
_hover={{
'& .delete': {
display: 'block'
}
}}
>
<Flex mb={2}>
<Box flex={1} fontWeight={'medium'} fontSize={'sm'} color={'myGray.900'}>
{t('dataset.data.Custom Index Number', { number: i })}
</Box>
<DeleteIcon
onClick={() => {
if (indexes.length <= 1) {
appendIndexes(getDefaultIndex({ dataId: `${Date.now()}` }));
}
removeIndexes(i);
}}
/>
</Flex>
<DataIndexTextArea index={i} maxToken={maxToken} register={register} />
</Box>
)
);
})}
</Flex>
</>
);
};
const DataIndexTextArea = ({
index,
maxToken,
register
}: {
index: number;
maxToken: number;
register: UseFormRegister<InputDataType>;
}) => {
const { t } = useTranslation();
const TextareaDom = useRef<HTMLTextAreaElement | null>(null);
const {
ref: TextareaRef,
required,
name,
onChange: onTextChange,
onBlur
} = register(`indexes.${index}.text`, { required: true });
const textareaMinH = '40px';
useEffect(() => {
if (TextareaDom.current) {
TextareaDom.current.style.height = textareaMinH;
TextareaDom.current.style.height = `${TextareaDom.current.scrollHeight + 5}px`;
}
}, []);
const autoHeight = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
if (e.target) {
e.target.style.height = textareaMinH;
e.target.style.height = `${e.target.scrollHeight + 5}px`;
}
}, []);
return (
<Textarea
maxLength={maxToken}
borderColor={'transparent'}
className={styles.scrollbar}
minH={textareaMinH}
px={0}
pt={0}
isRequired={required}
whiteSpace={'pre-wrap'}
resize={'none'}
_focus={{
px: 3,
py: 1,
borderColor: 'primary.500',
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
bg: 'white'
}}
placeholder={t('common:dataset.data.Index Placeholder')}
ref={(e) => {
if (e) TextareaDom.current = e;
TextareaRef(e);
}}
required
name={name}
onChange={(e) => {
autoHeight(e);
onTextChange(e);
}}
onFocus={autoHeight}
onBlur={onBlur}
/>
);
};

View File

@@ -10,6 +10,7 @@ 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';
import MyIcon from '@fastgpt/web/components/common/Icon';
const MetaDataCard = ({ datasetId }: { datasetId: string }) => {
const { t } = useTranslation();
@@ -94,26 +95,33 @@ const MetaDataCard = ({ datasetId }: { datasetId: string }) => {
return (
<MyBox isLoading={isLoading} w={'100%'} h={'100%'} p={6}>
<Box fontSize={'lg'} pb={4}>
<Box fontSize={'md'} 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}
<Flex mb={4} wordBreak={'break-all'} fontSize={'sm'}>
<Box color={'myGray.500'} flex={'0 0 70px'}>
{t('common:core.dataset.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 70px'}>
{item.label}
</Box>
<Box>{item.value}</Box>
</Flex>
))}
<Box>{collection?._id}</Box>
</Flex>
{metadataList.map(
(item, i) =>
item.label &&
item.value && (
<Flex key={i} alignItems={'center'} mb={4} wordBreak={'break-all'} fontSize={'sm'}>
<Box color={'myGray.500'} flex={'0 0 70px'}>
{item.label}
</Box>
<Box>{item.value}</Box>
</Flex>
)
)}
{collection?.sourceId && (
<Button variant={'whitePrimary'} onClick={readSource}>
{t('common:core.dataset.collection.metadata.read source')}
<Flex py={2} px={3}>
<MyIcon name="visible" w={'1rem'} mr={'0.38rem'} />
<Box>{t('common:core.dataset.collection.metadata.read source')}</Box>
</Flex>
</Button>
)}
</MyBox>

View File

@@ -9,6 +9,7 @@ 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';
import ParentPaths from '@/components/common/ParentPaths';
export enum TabEnum {
dataCard = 'dataCard',
@@ -25,7 +26,7 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => {
const router = useRouter();
const query = router.query;
const { isPc } = useSystem();
const { datasetDetail, vectorTrainingMap, agentTrainingMap, rebuildingCount } =
const { datasetDetail, vectorTrainingMap, agentTrainingMap, rebuildingCount, paths } =
useContextSelector(DatasetPageContext, (v) => v);
const tabList = [
@@ -55,56 +56,67 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => {
<>
{isPc ? (
<Flex
py={2}
pb={2}
pt={3}
px={4}
justify={'space-between'}
borderBottom={theme.borders.base}
borderBottom={currentTab === TabEnum.dataCard ? 'none' : 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>
{currentTab === TabEnum.dataCard ? (
<>
<Flex
alignItems={'center'}
cursor={'pointer'}
py={'0.38rem'}
px={2}
ml={0}
borderRadius={'md'}
_hover={{ bg: 'myGray.05' }}
fontSize={'sm'}
fontWeight={500}
onClick={() => {
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'}>
{datasetDetail.name}
</Box>
</Flex>
</>
) : (
<Flex py={'0.38rem'} px={2} h={10} ml={0.5}>
<ParentPaths
paths={paths}
onClick={(e) => {
router.push(`/dataset/list?parentId=${e}`);
}}
/>
</Flex>
)}
<Box position={'absolute'} left={'50%'} transform={'translateX(-50%)'}>
<LightRowTabs<TabEnum>
px={4}

View File

@@ -0,0 +1,11 @@
.scrollbar {
&::-webkit-scrollbar-thumb {
background: var(--chakra-colors-myGray-150) !important;
transition: background 1s;
margin-left: 5px;
}
&::-webkit-scrollbar-thumb:hover {
background: var(--chakra-colors-myGray-250) !important;
}
}

View File

@@ -6,6 +6,7 @@ import {
getAllTags,
getDatasetById,
getDatasetCollectionTags,
getDatasetPaths,
getDatasetTrainingQueue,
getTrainingQueueLen,
postCreateDatasetCollectionTag,
@@ -15,6 +16,7 @@ import { defaultDatasetDetail } from '../constants';
import { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api';
import { DatasetItemType, DatasetTagType } from '@fastgpt/global/core/dataset/type';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
type DatasetPageContextType = {
@@ -32,7 +34,8 @@ type DatasetPageContextType = {
isCreateCollectionTagLoading: boolean;
searchTagKey: string;
setSearchTagKey: Dispatch<SetStateAction<string>>;
paths: ParentTreePathItemType[];
refetchPaths: () => void;
vectorTrainingMap: {
colorSchema: string;
tip: string;
@@ -84,7 +87,9 @@ export const DatasetPageContext = createContext<DatasetPageContextType>({
searchTagKey: '',
setSearchTagKey: function (value: SetStateAction<string>): void {
throw new Error('Function not implemented.');
}
},
paths: [],
refetchPaths: () => {}
});
export const DatasetPageContextProvider = ({
@@ -99,12 +104,9 @@ export const DatasetPageContextProvider = ({
// dataset detail
const [datasetDetail, setDatasetDetail] = useState(defaultDatasetDetail);
const loadDatasetDetail = async (id: string) => {
const data = await getDatasetById(id);
setDatasetDetail(data);
return data;
};
const updateDataset = async (data: DatasetUpdateBody) => {
@@ -224,12 +226,28 @@ export const DatasetPageContextProvider = ({
refetchInterval: 10000
});
const { data: paths = [], runAsync: refetchPaths } = useRequest2(
() =>
getDatasetPaths(datasetDetail.parentId).then((res) => {
res.push({
parentId: '',
parentName: datasetDetail.name
});
return res;
}),
{
manual: false,
refreshDeps: [datasetDetail.parentId]
}
);
const contextValue: DatasetPageContextType = {
datasetId,
datasetDetail,
loadDatasetDetail,
updateDataset,
paths,
refetchPaths,
vectorTrainingMap,
agentTrainingMap,
rebuildingCount,