style: database refactor (#2460)

* fix: dataset folder modal

* style: dataset style refactor

* sideTag i18n pef
This commit is contained in:
papapatrick
2024-08-21 18:15:05 +08:00
committed by GitHub
parent 649de7f028
commit 113c57bcbe
16 changed files with 412 additions and 223 deletions

View File

@@ -17,8 +17,7 @@ import { useTranslation } from 'next-i18next';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
import AIModelSelector from '@/components/Select/AIModelSelector';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
export type CreateDatasetType =
@@ -116,17 +115,23 @@ const CreateModal = ({
return (
<MyModal
iconSrc={iconMap[type]}
title={t('common:core.dataset.Create dataset', { name: databaseNameMap[type] })}
title={
<Flex alignItems={'center'} ml={-3}>
<Avatar w={'20px'} h={'20px'} borderRadius={'4px'} src={iconMap[type]} pr={'10px'} />
{t('common:core.dataset.Create dataset', { name: databaseNameMap[type] })}
</Flex>
}
isOpen
onClose={onClose}
isCentered={!isPc}
w={'450px'}
w={'490px'}
>
<ModalBody py={2}>
<Box mt={5}>
<Box color={'myGray.900'}>{t('common:common.Set Name')}</Box>
<Flex mt={1} alignItems={'center'}>
<ModalBody py={'24px'} px={'36px'}>
<Box>
<Box color={'myGray.900'} fontWeight={500} fontSize={'14px'}>
{t('common:common.Set Name')}
</Box>
<Flex mt={'12px'} alignItems={'center'}>
<MyTooltip label={t('common:common.avatar.Select Avatar')}>
<Avatar
flexShrink={0}
@@ -152,14 +157,28 @@ const CreateModal = ({
</Flex>
</Box>
{filterNotHiddenVectorModelList.length > 1 && (
<Flex mt={6} alignItems={'center'}>
<Flex alignItems={'center'} flex={'0 0 100px'} fontSize={'sm'}>
<Flex
mt={6}
alignItems={['flex-start', 'center']}
justify={'space-between'}
flexDir={['column', 'row']}
>
<Flex
alignItems={'center'}
flex={['', '0 0 100px']}
fontSize={'sm'}
color={'myGray.900'}
fontWeight={500}
pb={['12px', '0']}
>
{t('common:core.ai.model.Vector Model')}
<QuestionTip label={t('common:core.dataset.embedding model tip')} />
<MyTooltip label={t('common:core.dataset.embedding model tip')}>
<MyIcon w={'16px'} h={'16px'} color={'myGray.500'} ml={'4px'} name="common/help" />
</MyTooltip>
</Flex>
<Box flex={1}>
<Box w={['100%', '300px']}>
<AIModelSelector
w={'100%'}
w={['100%', '300px']}
value={vectorModel}
list={filterNotHiddenVectorModelList.map((item) => ({
label: item.name,
@@ -173,13 +192,24 @@ const CreateModal = ({
</Flex>
)}
{datasetModelList.length > 1 && (
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 100px'} fontSize={'sm'}>
<Flex
mt={6}
alignItems={['flex-start', 'center']}
justify={'space-between'}
flexDir={['column', 'row']}
>
<Box
flex={['', '0 0 100px']}
fontSize={'sm'}
color={'myGray.900'}
fontWeight={500}
pb={['12px', '0']}
>
{t('common:core.ai.model.Dataset Agent Model')}
</Box>
<Box flex={1}>
<Box w={['100%', '300px']}>
<AIModelSelector
w={'100%'}
w={['100%', '300px']}
value={agentModel}
list={datasetModelList.map((item) => ({
label: item.name,
@@ -194,7 +224,7 @@ const CreateModal = ({
)}
</ModalBody>
<ModalFooter>
<ModalFooter pt={'0px'} pb={'24px'}>
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common:common.Close')}
</Button>

View File

@@ -1,16 +1,15 @@
import React, { useMemo, useRef, useState } from 'react';
import { resumeInheritPer } from '@/web/core/dataset/api';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { Box, Flex, Grid } from '@chakra-ui/react';
import { Box, Flex, Grid, HStack } from '@chakra-ui/react';
import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRouter } from 'next/router';
import PermissionIconText from '@/components/support/permission/IconText';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
import Avatar from '@fastgpt/web/components/common/Avatar';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { DatasetItemType } from '@fastgpt/global/core/dataset/type';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useToast } from '@fastgpt/web/hooks/useToast';
@@ -35,12 +34,18 @@ import { useFolderDrag } from '@/components/common/folder/useFolderDrag';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { useI18n } from '@/web/context/I18n';
import { useTranslation } from 'next-i18next';
import { useUserStore } from '@/web/support/user/useUserStore';
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import SideTag from './SideTag';
function List() {
const { setLoading } = useSystemStore();
const { toast } = useToast();
const { isPc } = useSystem();
const { t } = useTranslation();
const { commonT } = useI18n();
const { loadAndGetTeamMembers } = useUserStore();
const {
loadMyDatasets,
setMoveDatasetId,
@@ -71,6 +76,10 @@ function List() {
}
});
const { data: members = [], loading: isLoadMembers } = useRequest2(loadAndGetTeamMembers, {
manual: false
});
const editPerDataset = useMemo(
() => (editPerDatasetIndex !== undefined ? myDatasets[editPerDatasetIndex] : undefined),
[editPerDatasetIndex, myDatasets]
@@ -152,197 +161,238 @@ function List() {
gridGap={5}
alignItems={'stretch'}
>
{formatDatasets.map((dataset, index) => (
<MyTooltip
key={dataset._id}
label={
<Flex flexDirection={'column'} alignItems={'center'}>
<Box fontSize={'xs'} color={'myGray.500'}>
{dataset.type === DatasetTypeEnum.folder
? t('common.folder.Open folder')
: t('common.folder.open_dataset')}
</Box>
</Flex>
}
>
<MyBox
isLoading={loadingDatasetId === dataset._id}
display={'flex'}
flexDirection={'column'}
lineHeight={1.5}
h="100%"
py={3}
px={5}
cursor={'pointer'}
borderWidth={1.5}
border={'base'}
boxShadow={'2'}
bg={'white'}
borderRadius={'lg'}
position={'relative'}
minH={'150px'}
{...getBoxProps({
dataId: dataset._id,
isFolder: dataset.type === DatasetTypeEnum.folder
})}
_hover={{
borderColor: 'primary.300',
boxShadow: '1.5',
'& .delete': {
display: 'block'
},
'& .more': {
display: 'flex'
{!isLoadMembers &&
formatDatasets.map((dataset, index) => {
const owner = members.find((v) => v.tmbId === dataset.tmbId);
return (
<MyTooltip
key={dataset._id}
label={
<Flex flexDirection={'column'} alignItems={'center'}>
<Box fontSize={'xs'} color={'myGray.500'}>
{dataset.type === DatasetTypeEnum.folder
? t('common.folder.Open folder')
: t('common.folder.open_dataset')}
</Box>
</Flex>
}
}}
onClick={() => {
if (dataset.type === DatasetTypeEnum.folder) {
router.push({
pathname: '/dataset/list',
query: {
parentId: dataset._id
}
});
} else {
router.push({
pathname: '/dataset/detail',
query: {
datasetId: dataset._id
}
});
}
}}
>
{dataset.permission.hasWritePer && (
<Box
className="more"
display={['', 'none']}
position={'absolute'}
top={3.5}
right={4}
borderRadius={'md'}
>
<MyBox
isLoading={loadingDatasetId === dataset._id}
display={'flex'}
flexDirection={'column'}
lineHeight={1.5}
h="100%"
pt={5}
pb={3}
px={5}
cursor={'pointer'}
borderWidth={1.5}
border={'base'}
boxShadow={'2'}
bg={'white'}
borderRadius={'lg'}
position={'relative'}
minH={'150px'}
{...getBoxProps({
dataId: dataset._id,
isFolder: dataset.type === DatasetTypeEnum.folder
})}
_hover={{
color: 'primary.500',
'& .icon': {
bg: 'myGray.100'
borderColor: 'primary.300',
boxShadow: '1.5',
'& .delete': {
display: 'block'
},
'& .more': {
display: 'flex'
},
'& .time': {
display: ['flex', 'none']
}
}}
onClick={(e) => {
e.stopPropagation();
onClick={() => {
if (dataset.type === DatasetTypeEnum.folder) {
router.push({
pathname: '/dataset/list',
query: {
parentId: dataset._id
}
});
} else {
router.push({
pathname: '/dataset/detail',
query: {
datasetId: dataset._id
}
});
}
}}
>
<MyMenu
Button={
<Box w={'22px'} h={'22px'}>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
borderRadius={'md'}
cursor={'pointer'}
/>
</Box>
}
menuList={[
{
children: [
{
icon: 'edit',
label: commonT('dataset.Edit Info'),
onClick: () =>
setEditedDataset({
id: dataset._id,
name: dataset.name,
intro: dataset.intro,
avatar: dataset.avatar
})
},
{
icon: 'common/file/move',
label: t('common:Move'),
onClick: () => setMoveDatasetId(dataset._id)
},
...(dataset.permission.hasManagePer
? [
{
icon: 'support/team/key',
label: t('common:permission.Permission'),
onClick: () => setEditPerDatasetIndex(index)
}
]
: [])
]
},
...(dataset.type != DatasetTypeEnum.folder
? [
{
children: [
{
icon: 'export',
label: t('common:Export'),
onClick: () => {
exportDataset(dataset);
}
}
]
}
]
: []),
...(dataset.permission.hasManagePer
? [
{
children: [
{
icon: 'delete',
label: t('common:common.Delete'),
type: 'danger' as 'danger',
onClick: () => onClickDeleteDataset(dataset._id)
}
]
}
]
: [])
]}
/>
</Box>
)}
<HStack>
<Avatar src={dataset.avatar} borderRadius={6} w={'28px'} />
<Box flex={'1 0 0'} className="textEllipsis3">
{dataset.name}
</Box>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={dataset.avatar} borderRadius={'md'} w={'28px'} />
<Box mx={3} className="textEllipsis3">
{dataset.name}
</Box>
</Flex>
<Box
flex={1}
className={'textEllipsis3'}
py={1}
wordBreak={'break-all'}
fontSize={'xs'}
color={'myGray.500'}
>
{dataset.intro ||
(dataset.type === DatasetTypeEnum.folder
? t('common:core.dataset.Folder placeholder')
: t('common:core.dataset.Intro Placeholder'))}
</Box>
<Flex alignItems={'center'} fontSize={'sm'}>
<Box flex={1}>
<PermissionIconText
defaultPermission={dataset.defaultPermission}
color={'myGray.600'}
/>
</Box>
{dataset.type !== DatasetTypeEnum.folder && (
<DatasetTypeTag type={dataset.type} py={1} px={2} />
)}
</Flex>
</MyBox>
</MyTooltip>
))}
<Box mr={'-1.25rem'}>
{dataset.type !== DatasetTypeEnum.folder && (
<SideTag
type={dataset.type}
py={0.5}
px={2}
borderLeftRadius={'sm'}
borderRightRadius={0}
/>
)}
</Box>
</HStack>
<Box
flex={1}
className={'textEllipsis3'}
py={3}
wordBreak={'break-all'}
fontSize={'xs'}
color={'myGray.500'}
>
{dataset.intro ||
(dataset.type === DatasetTypeEnum.folder
? t('common:core.dataset.Folder placeholder')
: t('common:core.dataset.Intro Placeholder'))}
</Box>
<Flex
h={'24px'}
alignItems={'center'}
justifyContent={'space-between'}
fontSize={'12px'}
fontWeight={500}
color={'myGray.500'}
>
<HStack spacing={3.5}>
{owner && (
<HStack spacing={1}>
<Avatar src={owner.avatar} w={'0.875rem'} borderRadius={'50%'} />
<Box maxW={'150px'} className="textEllipsis">
{owner.memberName}
</Box>
</HStack>
)}
<PermissionIconText
iconColor="myGray.400"
defaultPermission={dataset.defaultPermission}
color={'myGray.500'}
/>
</HStack>
<HStack>
{isPc && (
<HStack spacing={1} className="time">
<MyIcon name={'history'} w={'0.85rem'} color={'myGray.400'} />
<Box color={'myGray.500'}>
{formatTimeToChatTime(dataset.updateTime)}
</Box>
</HStack>
)}
{dataset.permission.hasWritePer && (
<Box
className="more"
display={['', 'none']}
borderRadius={'md'}
_hover={{
'& .icon': {
bg: 'myGray.100'
}
}}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyMenu
Button={
<Box w={'22px'} h={'22px'}>
<MyIcon
className="icon"
name={'more'}
h={'16px'}
w={'16px'}
px={1}
py={1}
borderRadius={'md'}
cursor={'pointer'}
/>
</Box>
}
menuList={[
{
children: [
{
icon: 'edit',
label: commonT('dataset.Edit Info'),
onClick: () =>
setEditedDataset({
id: dataset._id,
name: dataset.name,
intro: dataset.intro,
avatar: dataset.avatar
})
},
{
icon: 'common/file/move',
label: t('common:Move'),
onClick: () => setMoveDatasetId(dataset._id)
},
...(dataset.permission.hasManagePer
? [
{
icon: 'support/team/key',
label: t('common:permission.Permission'),
onClick: () => setEditPerDatasetIndex(index)
}
]
: [])
]
},
...(dataset.type != DatasetTypeEnum.folder
? [
{
children: [
{
icon: 'export',
label: t('common:Export'),
onClick: () => {
exportDataset(dataset);
}
}
]
}
]
: []),
...(dataset.permission.hasManagePer
? [
{
children: [
{
icon: 'delete',
label: t('common:common.Delete'),
type: 'danger' as 'danger',
onClick: () => onClickDeleteDataset(dataset._id)
}
]
}
]
: [])
]}
/>
</Box>
)}
</HStack>
</Flex>
</MyBox>
</MyTooltip>
);
})}
</Grid>
)}
{myDatasets.length === 0 && (

View File

@@ -0,0 +1,53 @@
import { Box, Flex, FlexProps } from '@chakra-ui/react';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import MyIcon from '@fastgpt/web/components/common/Icon';
import React, { useMemo } from 'react';
import { useTranslation } from 'next-i18next';
const SideTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps) => {
if (type === DatasetTypeEnum.folder) return null;
const { t } = useTranslation();
const DatasetListTypeMap = useMemo(() => {
return {
[DatasetTypeEnum.dataset]: {
icon: 'core/dataset/commonDatasetOutline',
label: t('dataset:common_dataset'),
collectionLabel: 'common.File'
},
[DatasetTypeEnum.websiteDataset]: {
icon: 'core/dataset/websiteDatasetOutline',
label: t('dataset:website_dataset'),
collectionLabel: 'common.Website'
},
[DatasetTypeEnum.externalFile]: {
icon: 'core/dataset/externalDatasetOutline',
label: t('dataset:external_file'),
collectionLabel: 'common.File'
}
};
}, [t]);
const item = DatasetListTypeMap[type] || DatasetListTypeMap['dataset'];
return (
<Flex
bg={'myGray.100'}
borderWidth={'1px'}
borderColor={'myGray.200'}
py={'3px'}
pl={'8px'}
pr={'12px'}
borderRadius={'md'}
fontSize={'xs'}
alignItems={'center'}
{...props}
>
<MyIcon name={item.icon as any} w={'0.8rem'} color={'myGray.400'} />
<Box fontSize={'mini'} ml={1}>
{/* @ts-ignore */}
{item.label}
</Box>
</Flex>
);
};
export default SideTag;

View File

@@ -10,7 +10,6 @@ import {
Input
} from '@chakra-ui/react';
import { useRouter } from 'next/router';
import PageContainer from '@/components/PageContainer';
import { useTranslation } from 'next-i18next';
import { serviceSideProps } from '@/web/common/utils/i18n';
import ParentPaths from '@/components/common/folder/Path';
@@ -92,14 +91,17 @@ const Dataset = () => {
const RenderSearchInput = useMemo(
() => (
<InputGroup maxW={['auto', '250px']} pr={4}>
<InputGroup maxW={['auto', '250px']} pr={[0, 4]}>
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
<MyIcon name={'common/searchLight'} w={'1rem'} />
<MyIcon color={'myGray.600'} name={'common/searchLight'} w={'1rem'} />
</InputLeftElement>
<Input
pl={'34px'}
value={searchKey}
onChange={(e) => setSearchKey(e.target.value)}
placeholder={t('common:dataset.dataset_name')}
py={0}
lineHeight={'34px'}
maxLength={30}
bg={'white'}
/>
@@ -112,15 +114,23 @@ const Dataset = () => {
isLoading={myDatasets.length === 0 && isFetchingDatasets}
flexDirection={'column'}
h={'100%'}
overflowY={'auto'}
overflowX={'hidden'}
>
<Flex pt={[4, 6]} pl={3} pr={10}>
<Flex pt={[4, 6]} pl={3} pr={[3, 10]}>
<Flex flexGrow={1} flexDirection="column">
<Flex alignItems={'flex-start'} justifyContent={'space-between'}>
<ParentPaths
paths={paths}
FirstPathDom={
<Flex flex={1} alignItems={'center'}>
<Box pl={2} letterSpacing={1} fontSize={'1.25rem'} fontWeight={'bold'}>
<Box
pl={2}
letterSpacing={1}
fontSize={'1.25rem'}
fontWeight={'bold'}
color={'myGray.900'}
>
{t('common:core.dataset.My Dataset')}
</Box>
</Flex>
@@ -138,9 +148,11 @@ const Dataset = () => {
{userInfo?.team?.permission.hasWritePer && (
<MyMenu
offset={[-30, 5]}
offset={[0, 10]}
width={120}
iconSize="2rem"
iconRadius="6px"
placement="bottom-end"
Button={
<Button variant={'primary'} px="0">
<Flex alignItems={'center'} px={'20px'}>
@@ -204,7 +216,7 @@ const Dataset = () => {
name={folderDetail.name}
intro={folderDetail.intro}
onEdit={() => {
setEditedDataset({
setEditFolderData({
id: folderDetail._id,
name: folderDetail.name,
intro: folderDetail.intro
@@ -263,6 +275,7 @@ const Dataset = () => {
{!!editFolderData && (
<EditFolderModal
{...editFolderData}
onClose={() => setEditFolderData(undefined)}
onCreate={async ({ name, intro }) => {
try {