* feat: add customize toolkit (#3205) * chaoyang * fix-auth * add toolkit * add order * plugin usage * fix * delete console: * Fix: Fix fullscreen preview top positioning and improve Markdown rendering logic (#3247) * 完成任务:修复全屏预览顶部固定问题,优化 Markdown 渲染逻辑 * 有问题修改 * 问题再修改 * 修正问题 * fix: plugin standalone display issue (#3254) * 4.8.15 test (#3246) * o1 config * perf: system plugin code * 调整系统插件代码。增加html 渲染安全配置。 (#3258) * perf: base64 picker * perf: list app or dataset * perf: plugin config code * 小窗适配等问题 (#3257) * 小窗适配等问题 * git问题 * 小窗剩余问题 * feat: system plugin auth and lock version (#3265) * feat: system plugin auth and lock version * update comment * 4.8.15 test (#3267) * tmp log * perf: login direct * perf: iframe html code * remove log * fix: plugin standalone display (#3277) * refactor: 页面拆分&i18n拆分 (#3281) * refactor: account组件拆成独立页面 * script: 新增i18n json文件创建脚本 * refactor: 页面i18n拆分 * i18n: add en&hant * 4.8.15 test (#3285) * tmp log * remove log * fix: watch avatar refresh * perf: i18n code * fix(plugin): use intro instead of userguide (#3290) * Universal SSO (#3292) * tmp log * remove log * feat: common oauth * readme * perf: sso provider * remove sso code * perf: refresh plugins * feat: add api dataset (#3272) * add api-dataset * fix api-dataset * fix api dataset * fix ts * perf: create collection code (#3301) * tmp log * remove log * perf: i18n change * update version doc * feat: question guide from chatId * perf: create collection code * fix: request api * fix: request api * fix: tts auth and response type (#3303) * perf: md splitter * fix: tts auth and response type * fix: api file dataset (#3307) * perf: api dataset init (#3310) * perf: collection schema * perf: api dataset init * refactor: 团队管理独立页面 (#3302) * ui: 团队管理独立页面 * 代码优化 * fix * perf: sync collection and ui check (#3314) * perf: sync collection * remove script * perf: update api server * perf: api dataset parent * perf: team ui * perf: team 18n * update team ui * perf: ui check * perf: i18n * fix: debug variables & cronjob & system plugin callback load (#3315) * fix: debug variables & cronjob & system plugin callback load * fix type * fix * fix * fix: plugin dataset quote;perf: system variables init (#3316) * fix: plugin dataset quote * perf: system variables init * perf: node templates ui;fix: dataset import ui (#3318) * fix: dataset import ui * perf: node templates ui * perf: ui refresh * feat:套餐改名和套餐跳转配置 (#3309) * fixing:except Sidebar * 去除了多余的代码 * 修正了套餐说明的代码 * 修正了误删除的show_git代码 * 修正了名字部分等代码 * 修正了问题,遗留了其他和ui讨论不一致的部分 * 4.8.15 test (#3319) * remove log * pref: bill ui * pref: bill ui * perf: log * html渲染文档 (#3270) * html渲染文档 * 文档有点小问题 * feat: doc (#3322) * 集合重训练 (#3282) * rebaser * 一点补充 * 小问题 * 其他问题修正,删除集合保留文件的参数还没找到... * reTraining * delete uesless * 删除了一行错误代码 * 集合重训练部分 * fixing * 删除console代码 * feat: navbar item config (#3326) * perf: custom navbar code;perf: retraining code;feat: api dataset and dataset api doc (#3329) * feat: api dataset and dataset api doc * perf: retraining code * perf: custom navbar code * fix: ts (#3330) * fix: ts * fix: ts * retraining ui * perf: api collection filter * perf: retrining button --------- Co-authored-by: heheer <heheer@sealos.io> Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com> Co-authored-by: papapatrick <109422393+Patrickill@users.noreply.github.com>
452 lines
15 KiB
TypeScript
452 lines
15 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
Box,
|
|
Flex,
|
|
MenuButton,
|
|
Button,
|
|
Link,
|
|
useTheme,
|
|
useDisclosure,
|
|
HStack
|
|
} from '@chakra-ui/react';
|
|
import {
|
|
getDatasetCollectionPathById,
|
|
postDatasetCollection,
|
|
putDatasetCollectionById
|
|
} from '@/web/core/dataset/api';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { useTranslation } from 'next-i18next';
|
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
|
import MyInput from '@/components/MyInput';
|
|
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
|
import { useRouter } from 'next/router';
|
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
|
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
|
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
|
import {
|
|
DatasetCollectionTypeEnum,
|
|
TrainingModeEnum,
|
|
DatasetTypeEnum,
|
|
DatasetTypeMap,
|
|
DatasetStatusEnum
|
|
} from '@fastgpt/global/core/dataset/constants';
|
|
import EditFolderModal, { useEditFolder } from '../../../component/EditFolderModal';
|
|
import { TabEnum } from '../../index';
|
|
import ParentPath from '@/components/common/ParentPaths';
|
|
import dynamic from 'next/dynamic';
|
|
|
|
import { ImportDataSourceEnum } from '@fastgpt/global/core/dataset/constants';
|
|
import { useContextSelector } from 'use-context-selector';
|
|
import { CollectionPageContext } from './Context';
|
|
import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext';
|
|
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
|
import HeaderTagPopOver from './HeaderTagPopOver';
|
|
|
|
const FileSourceSelector = dynamic(() => import('../Import/components/FileSourceSelector'));
|
|
|
|
const Header = ({}: {}) => {
|
|
const { t } = useTranslation();
|
|
const theme = useTheme();
|
|
|
|
const { setLoading, feConfigs } = useSystemStore();
|
|
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
|
|
|
|
const router = useRouter();
|
|
const { parentId = '' } = router.query as { parentId: string };
|
|
const { isPc } = useSystem();
|
|
|
|
const { searchText, setSearchText, total, getData, pageNum, onOpenWebsiteModal } =
|
|
useContextSelector(CollectionPageContext, (v) => v);
|
|
|
|
const { data: paths = [] } = useQuery(['getDatasetCollectionPathById', parentId], () =>
|
|
getDatasetCollectionPathById(parentId)
|
|
);
|
|
|
|
const { editFolderData, setEditFolderData } = useEditFolder();
|
|
const { onOpenModal: onOpenCreateVirtualFileModal, EditModal: EditCreateVirtualFileModal } =
|
|
useEditTitle({
|
|
title: t('common:dataset.Create manual collection'),
|
|
tip: t('common:dataset.Manual collection Tip'),
|
|
canEmpty: false
|
|
});
|
|
const {
|
|
isOpen: isOpenFileSourceSelector,
|
|
onOpen: onOpenFileSourceSelector,
|
|
onClose: onCloseFileSourceSelector
|
|
} = useDisclosure();
|
|
const { mutate: onCreateCollection } = useRequest({
|
|
mutationFn: async ({
|
|
name,
|
|
type,
|
|
callback,
|
|
...props
|
|
}: {
|
|
name: string;
|
|
type: DatasetCollectionTypeEnum;
|
|
callback?: (id: string) => void;
|
|
trainingType?: TrainingModeEnum;
|
|
rawLink?: string;
|
|
chunkSize?: number;
|
|
}) => {
|
|
setLoading(true);
|
|
const id = await postDatasetCollection({
|
|
parentId,
|
|
datasetId: datasetDetail._id,
|
|
name,
|
|
type,
|
|
...props
|
|
});
|
|
callback?.(id);
|
|
return id;
|
|
},
|
|
onSuccess() {
|
|
getData(pageNum);
|
|
},
|
|
onSettled() {
|
|
setLoading(false);
|
|
},
|
|
|
|
successToast: t('common:common.Create Success'),
|
|
errorToast: t('common:common.Create Failed')
|
|
});
|
|
const isWebSite = datasetDetail?.type === DatasetTypeEnum.websiteDataset;
|
|
|
|
return (
|
|
<Box display={['block', 'flex']} alignItems={'center'} gap={2}>
|
|
<HStack flex={1}>
|
|
<Box flex={1} fontWeight={'500'} color={'myGray.900'} whiteSpace={'nowrap'}>
|
|
<ParentPath
|
|
paths={paths.map((path, i) => ({
|
|
parentId: path.parentId,
|
|
parentName: i === paths.length - 1 ? `${path.parentName}` : path.parentName
|
|
}))}
|
|
FirstPathDom={
|
|
<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})
|
|
</Flex>
|
|
{datasetDetail?.websiteConfig?.url && (
|
|
<Flex fontSize={'mini'}>
|
|
{t('common:core.dataset.website.Base Url')}:
|
|
<Link
|
|
href={datasetDetail.websiteConfig.url}
|
|
target="_blank"
|
|
mr={2}
|
|
color={'blue.700'}
|
|
>
|
|
{datasetDetail.websiteConfig.url}
|
|
</Link>
|
|
</Flex>
|
|
)}
|
|
</Flex>
|
|
}
|
|
onClick={(e) => {
|
|
router.replace({
|
|
query: {
|
|
...router.query,
|
|
parentId: e
|
|
}
|
|
});
|
|
}}
|
|
/>
|
|
</Box>
|
|
|
|
{/* search input */}
|
|
{isPc && (
|
|
<MyInput
|
|
maxW={'250px'}
|
|
flex={1}
|
|
size={'sm'}
|
|
h={'36px'}
|
|
placeholder={t('common:common.Search') || ''}
|
|
value={searchText}
|
|
leftIcon={
|
|
<MyIcon
|
|
name="common/searchLight"
|
|
position={'absolute'}
|
|
w={'16px'}
|
|
color={'myGray.500'}
|
|
/>
|
|
}
|
|
onChange={(e) => {
|
|
setSearchText(e.target.value);
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* Tag */}
|
|
{datasetDetail.permission.hasWritePer && feConfigs?.isPlus && <HeaderTagPopOver />}
|
|
</HStack>
|
|
|
|
{/* diff collection button */}
|
|
{datasetDetail.permission.hasWritePer && (
|
|
<Box textAlign={'end'} mt={[3, 0]}>
|
|
{datasetDetail?.type === DatasetTypeEnum.dataset && (
|
|
<MyMenu
|
|
offset={[0, 5]}
|
|
Button={
|
|
<MenuButton
|
|
_hover={{
|
|
color: 'primary.500'
|
|
}}
|
|
fontSize={['sm', 'md']}
|
|
>
|
|
<Flex
|
|
px={3.5}
|
|
py={2}
|
|
borderRadius={'sm'}
|
|
cursor={'pointer'}
|
|
bg={'primary.500'}
|
|
overflow={'hidden'}
|
|
color={'white'}
|
|
>
|
|
<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>
|
|
}
|
|
menuList={[
|
|
{
|
|
children: [
|
|
{
|
|
label: (
|
|
<Flex>
|
|
<MyIcon name={'common/folderFill'} w={'20px'} mr={2} />
|
|
{t('common:Folder')}
|
|
</Flex>
|
|
),
|
|
onClick: () => setEditFolderData({})
|
|
},
|
|
{
|
|
label: (
|
|
<Flex>
|
|
<MyIcon name={'core/dataset/manualCollection'} mr={2} w={'20px'} />
|
|
{t('common:core.dataset.Manual collection')}
|
|
</Flex>
|
|
),
|
|
onClick: () => {
|
|
onOpenCreateVirtualFileModal({
|
|
defaultVal: '',
|
|
onSuccess: (name) => {
|
|
onCreateCollection({ name, type: DatasetCollectionTypeEnum.virtual });
|
|
}
|
|
});
|
|
}
|
|
},
|
|
{
|
|
label: (
|
|
<Flex>
|
|
<MyIcon name={'core/dataset/fileCollection'} mr={2} w={'20px'} />
|
|
{t('common:core.dataset.Text collection')}
|
|
</Flex>
|
|
),
|
|
onClick: onOpenFileSourceSelector
|
|
},
|
|
{
|
|
label: (
|
|
<Flex>
|
|
<MyIcon name={'core/dataset/tableCollection'} mr={2} w={'20px'} />
|
|
{t('common:core.dataset.Table collection')}
|
|
</Flex>
|
|
),
|
|
onClick: () =>
|
|
router.replace({
|
|
query: {
|
|
...router.query,
|
|
currentTab: TabEnum.import,
|
|
source: ImportDataSourceEnum.csvTable
|
|
}
|
|
})
|
|
}
|
|
]
|
|
}
|
|
]}
|
|
/>
|
|
)}
|
|
{datasetDetail?.type === DatasetTypeEnum.websiteDataset && (
|
|
<>
|
|
{datasetDetail?.websiteConfig?.url ? (
|
|
<Flex alignItems={'center'}>
|
|
{datasetDetail.status === DatasetStatusEnum.active && (
|
|
<Button onClick={onOpenWebsiteModal}>{t('common:common.Config')}</Button>
|
|
)}
|
|
{datasetDetail.status === DatasetStatusEnum.syncing && (
|
|
<Flex
|
|
ml={3}
|
|
alignItems={'center'}
|
|
px={3}
|
|
py={1}
|
|
borderRadius="md"
|
|
border={theme.borders.base}
|
|
>
|
|
<Box
|
|
animation={'zoomStopIcon 0.5s infinite alternate'}
|
|
bg={'myGray.700'}
|
|
w="8px"
|
|
h="8px"
|
|
borderRadius={'50%'}
|
|
mt={'1px'}
|
|
></Box>
|
|
<Box ml={2} color={'myGray.600'}>
|
|
{t('common:core.dataset.status.syncing')}
|
|
</Box>
|
|
</Flex>
|
|
)}
|
|
</Flex>
|
|
) : (
|
|
<Button onClick={onOpenWebsiteModal}>
|
|
{t('common:core.dataset.Set Website Config')}
|
|
</Button>
|
|
)}
|
|
</>
|
|
)}
|
|
{datasetDetail?.type === DatasetTypeEnum.externalFile && (
|
|
<MyMenu
|
|
offset={[0, 5]}
|
|
Button={
|
|
<MenuButton
|
|
_hover={{
|
|
color: 'primary.500'
|
|
}}
|
|
fontSize={['sm', 'md']}
|
|
>
|
|
<Flex
|
|
px={3.5}
|
|
py={2}
|
|
borderRadius={'sm'}
|
|
cursor={'pointer'}
|
|
bg={'primary.500'}
|
|
overflow={'hidden'}
|
|
color={'white'}
|
|
>
|
|
<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>
|
|
}
|
|
menuList={[
|
|
{
|
|
children: [
|
|
{
|
|
label: (
|
|
<Flex>
|
|
<MyIcon name={'common/folderFill'} w={'20px'} mr={2} />
|
|
{t('common:Folder')}
|
|
</Flex>
|
|
),
|
|
onClick: () => setEditFolderData({})
|
|
},
|
|
{
|
|
label: (
|
|
<Flex>
|
|
<MyIcon name={'core/dataset/fileCollection'} mr={2} w={'20px'} />
|
|
{t('common:core.dataset.Text collection')}
|
|
</Flex>
|
|
),
|
|
onClick: () =>
|
|
router.replace({
|
|
query: {
|
|
...router.query,
|
|
currentTab: TabEnum.import,
|
|
source: ImportDataSourceEnum.externalFile
|
|
}
|
|
})
|
|
}
|
|
]
|
|
}
|
|
]}
|
|
/>
|
|
)}
|
|
{/* apiDataset */}
|
|
{datasetDetail?.type === DatasetTypeEnum.apiDataset && (
|
|
<Flex
|
|
px={3.5}
|
|
py={2}
|
|
borderRadius={'sm'}
|
|
cursor={'pointer'}
|
|
bg={'primary.500'}
|
|
overflow={'hidden'}
|
|
color={'white'}
|
|
onClick={() =>
|
|
router.replace({
|
|
query: {
|
|
...router.query,
|
|
currentTab: TabEnum.import,
|
|
source: ImportDataSourceEnum.apiDataset
|
|
}
|
|
})
|
|
}
|
|
>
|
|
<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('dataset:add_file')}
|
|
</Box>
|
|
</Flex>
|
|
)}
|
|
</Box>
|
|
)}
|
|
|
|
{/* modal */}
|
|
{!!editFolderData && (
|
|
<EditFolderModal
|
|
onClose={() => setEditFolderData(undefined)}
|
|
editCallback={async (name) => {
|
|
try {
|
|
if (editFolderData.id) {
|
|
await putDatasetCollectionById({
|
|
id: editFolderData.id,
|
|
name
|
|
});
|
|
getData(pageNum);
|
|
} else {
|
|
onCreateCollection({
|
|
name,
|
|
type: DatasetCollectionTypeEnum.folder
|
|
});
|
|
}
|
|
} catch (error) {
|
|
return Promise.reject(error);
|
|
}
|
|
}}
|
|
isEdit={!!editFolderData.id}
|
|
name={editFolderData.name}
|
|
/>
|
|
)}
|
|
<EditCreateVirtualFileModal iconSrc={'modal/manualDataset'} closeBtnText={''} />
|
|
{isOpenFileSourceSelector && <FileSourceSelector onClose={onCloseFileSourceSelector} />}
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default Header;
|