mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 21:13:50 +00:00
perf: Dataset new ui (#2555)
* perf: dataset detail ui * fix: collection tag modal * perf: data card support markdown * fix :ts
This commit is contained in:
@@ -5,9 +5,14 @@ import { Box, Image, ImageProps } from '@chakra-ui/react';
|
||||
import { useSystem } from '../../../hooks/useSystem';
|
||||
import Loading from '../MyLoading';
|
||||
|
||||
const MyPhotoView = (props: ImageProps) => {
|
||||
const MyPhotoView = ({
|
||||
forbidImgPreview,
|
||||
...props
|
||||
}: ImageProps & { forbidImgPreview?: boolean }) => {
|
||||
const { isPc } = useSystem();
|
||||
return (
|
||||
return forbidImgPreview ? (
|
||||
<Image {...props} />
|
||||
) : (
|
||||
<PhotoProvider
|
||||
maskOpacity={0.6}
|
||||
bannerVisible={!isPc}
|
||||
|
@@ -19,8 +19,8 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import type { ButtonProps, MenuItemProps } from '@chakra-ui/react';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
import { useLoading } from '../../../hooks/useLoading';
|
||||
import MyIcon from '../Icon';
|
||||
import { useRequest2 } from '../../../hooks/useRequest';
|
||||
|
||||
export type SelectProps<T = any> = ButtonProps & {
|
||||
value?: T;
|
||||
@@ -32,7 +32,7 @@ export type SelectProps<T = any> = ButtonProps & {
|
||||
value: T;
|
||||
}[];
|
||||
isLoading?: boolean;
|
||||
onchange?: (val: T) => void;
|
||||
onchange?: (val: T) => any | Promise<any>;
|
||||
};
|
||||
|
||||
const MySelect = <T = any,>(
|
||||
@@ -82,6 +82,10 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const { runAsync: onChange, loading } = useRequest2((val: T) => onchange?.(val));
|
||||
|
||||
const isSelecting = loading || isLoading;
|
||||
|
||||
return (
|
||||
<Box
|
||||
css={css({
|
||||
@@ -92,7 +96,7 @@ const MySelect = <T = any,>(
|
||||
>
|
||||
<Menu
|
||||
autoSelect={false}
|
||||
isOpen={isOpen}
|
||||
isOpen={isOpen && !isSelecting}
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
strategy={'fixed'}
|
||||
@@ -118,7 +122,7 @@ const MySelect = <T = any,>(
|
||||
{...props}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
{isLoading && <MyIcon mr={2} name={'common/loading'} w={'16px'} />}
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'16px'} />}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
@@ -160,8 +164,8 @@ const MySelect = <T = any,>(
|
||||
color: 'myGray.900'
|
||||
})}
|
||||
onClick={() => {
|
||||
if (onchange && value !== item.value) {
|
||||
onchange(item.value);
|
||||
if (onChange && value !== item.value) {
|
||||
onChange(item.value);
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Flex, Grid, Image } from '@chakra-ui/react';
|
||||
import { Box, Flex, Grid } from '@chakra-ui/react';
|
||||
import type { FlexProps, GridProps } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Avatar from '../Avatar';
|
||||
@@ -9,7 +9,7 @@ type Props<ValueType = string> = Omit<GridProps, 'onChange'> & {
|
||||
value: ValueType;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
inlineStyles?: FlexProps;
|
||||
activatedColor?: string;
|
||||
activeColor?: string;
|
||||
onChange: (value: ValueType) => void;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ const LightRowTabs = <ValueType = string,>({
|
||||
list,
|
||||
size = 'md',
|
||||
value,
|
||||
activatedColor = 'primary.600',
|
||||
activeColor = 'primary.600',
|
||||
onChange,
|
||||
inlineStyles,
|
||||
...props
|
||||
@@ -68,10 +68,10 @@ const LightRowTabs = <ValueType = string,>({
|
||||
whiteSpace={'nowrap'}
|
||||
{...(value === item.value
|
||||
? {
|
||||
color: activatedColor,
|
||||
color: activeColor,
|
||||
cursor: 'default',
|
||||
fontWeight: 'bold',
|
||||
borderBottomColor: activatedColor
|
||||
borderBottomColor: activeColor
|
||||
}
|
||||
: {
|
||||
cursor: 'pointer'
|
||||
|
@@ -3,7 +3,7 @@ import { Box, ImageProps, Skeleton } from '@chakra-ui/react';
|
||||
import MyPhotoView from '@fastgpt/web/components/common/Image/PhotoView';
|
||||
import { useBoolean } from 'ahooks';
|
||||
|
||||
const MdImage = ({ src, ...props }: { src?: string } & ImageProps) => {
|
||||
const MdImage = ({ src, ...props }: { src?: string; forbidImgPreview?: boolean } & ImageProps) => {
|
||||
const [isLoaded, { setTrue }] = useBoolean(false);
|
||||
|
||||
const [renderSrc, setRenderSrc] = useState(src);
|
||||
@@ -11,7 +11,6 @@ const MdImage = ({ src, ...props }: { src?: string } & ImageProps) => {
|
||||
if (src?.includes('base64') && !src.startsWith('data:image')) {
|
||||
return <Box>Invalid base64 image</Box>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Skeleton isLoaded={isLoaded}>
|
||||
<MyPhotoView
|
||||
|
@@ -28,20 +28,22 @@ const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false
|
||||
|
||||
const Markdown = ({
|
||||
source = '',
|
||||
showAnimation = false
|
||||
showAnimation = false,
|
||||
forbidImgPreview = false
|
||||
}: {
|
||||
source?: string;
|
||||
showAnimation?: boolean;
|
||||
forbidImgPreview?: boolean;
|
||||
}) => {
|
||||
const components = useMemo<any>(
|
||||
() => ({
|
||||
img: Image,
|
||||
img: (props: any) => <Image {...props} forbidImgPreview={forbidImgPreview} />,
|
||||
pre: RewritePre,
|
||||
p: (pProps: any) => <p {...pProps} dir="auto" />,
|
||||
code: Code,
|
||||
a: A
|
||||
}),
|
||||
[]
|
||||
[forbidImgPreview]
|
||||
);
|
||||
|
||||
const formatSource = useMemo(() => {
|
||||
@@ -74,7 +76,7 @@ const Markdown = ({
|
||||
export default React.memo(Markdown);
|
||||
|
||||
/* Custom dom */
|
||||
const Code = React.memo(function Code(e: any) {
|
||||
function Code(e: any) {
|
||||
const { className, codeBlock, children } = e;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const codeType = match?.[1];
|
||||
@@ -103,11 +105,13 @@ const Code = React.memo(function Code(e: any) {
|
||||
}, [codeType, className, codeBlock, match, children, strChildren]);
|
||||
|
||||
return Component;
|
||||
});
|
||||
const Image = React.memo(function Image({ src }: { src?: string }) {
|
||||
return <MdImage src={src} />;
|
||||
});
|
||||
const A = React.memo(function A({ children, ...props }: any) {
|
||||
}
|
||||
|
||||
function Image({ src, forbidImgPreview }: { forbidImgPreview: boolean; src?: string }) {
|
||||
return <MdImage forbidImgPreview={forbidImgPreview} src={src} />;
|
||||
}
|
||||
|
||||
function A({ children, ...props }: any) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// empty href link
|
||||
@@ -152,7 +156,7 @@ const A = React.memo(function A({ children, ...props }: any) {
|
||||
}
|
||||
|
||||
return <Link {...props}>{children}</Link>;
|
||||
});
|
||||
}
|
||||
|
||||
function RewritePre({ children }: any) {
|
||||
const modifiedChildren = React.Children.map(children, (child) => {
|
||||
|
@@ -61,7 +61,7 @@ const AIModelSelector = ({ list, onchange, disableTip, ...props }: Props) => {
|
||||
router.push(AI_POINT_USAGE_CARD_ROUTE);
|
||||
return;
|
||||
}
|
||||
onchange?.(e);
|
||||
return onchange?.(e);
|
||||
},
|
||||
[onchange, router]
|
||||
);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Box, BoxProps, ButtonProps } from '@chakra-ui/react';
|
||||
import { Box, BoxProps } 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,7 +20,6 @@ type Props = Omit<BoxProps, 'onChange'> & {
|
||||
writePer?: PermissionValueType;
|
||||
onChange: (v: PermissionValueType) => Promise<any> | any;
|
||||
isInheritPermission?: boolean;
|
||||
isDisabled?: boolean;
|
||||
hasParent?: boolean;
|
||||
};
|
||||
|
||||
@@ -42,15 +41,12 @@ const DefaultPermissionList = ({
|
||||
{ label: t('user:permission.team_write'), value: writePer }
|
||||
];
|
||||
|
||||
const { runAsync: onRequestChange, loading } = useRequest2((v: PermissionValueType) =>
|
||||
onChange(v)
|
||||
);
|
||||
const { runAsync: onRequestChange } = useRequest2((v: PermissionValueType) => onChange(v));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box {...styles}>
|
||||
<MySelect
|
||||
isLoading={loading}
|
||||
list={defaultPermissionSelectList}
|
||||
value={per}
|
||||
onchange={(per) => {
|
||||
|
@@ -1,5 +1,14 @@
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import { Box, Flex, MenuButton, Button, Link, useTheme, useDisclosure } from '@chakra-ui/react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
MenuButton,
|
||||
Button,
|
||||
Link,
|
||||
useTheme,
|
||||
useDisclosure,
|
||||
HStack
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
getDatasetCollectionPathById,
|
||||
postDatasetCollection,
|
||||
@@ -114,8 +123,9 @@ const Header = ({}: {}) => {
|
||||
const isWebSite = datasetDetail?.type === DatasetTypeEnum.websiteDataset;
|
||||
|
||||
return (
|
||||
<Flex px={[2, 6]} alignItems={'flex-start'} h={'35px'}>
|
||||
<Box flex={1} fontWeight={'500'} color={'myGray.900'} h={'100%'}>
|
||||
<Box display={['block', 'flex']} alignItems={'center'} gap={2}>
|
||||
<HStack flex={1}>
|
||||
<Box flex={1} fontWeight={'500'} color={'myGray.900'}>
|
||||
<ParentPath
|
||||
paths={paths.map((path, i) => ({
|
||||
parentId: path.parentId,
|
||||
@@ -162,7 +172,6 @@ const Header = ({}: {}) => {
|
||||
|
||||
{/* search input */}
|
||||
{isPc && (
|
||||
<Flex alignItems={'center'} mr={4}>
|
||||
<MyInput
|
||||
w={['100%', '250px']}
|
||||
size={'sm'}
|
||||
@@ -192,14 +201,15 @@ const Header = ({}: {}) => {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{/* Tag */}
|
||||
{datasetDetail.permission.hasWritePer && feConfigs?.isPlus && <HeaderTagPopOver />}
|
||||
</HStack>
|
||||
|
||||
{/* diff collection button */}
|
||||
{datasetDetail.permission.hasWritePer && (
|
||||
<Flex gap={3}>
|
||||
{feConfigs?.isPlus && <HeaderTagPopOver />}
|
||||
|
||||
<Box textAlign={'end'} mt={[3, 0]}>
|
||||
{datasetDetail?.type === DatasetTypeEnum.dataset && (
|
||||
<MyMenu
|
||||
offset={[0, 5]}
|
||||
@@ -396,7 +406,7 @@ const Header = ({}: {}) => {
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* modal */}
|
||||
@@ -427,7 +437,7 @@ const Header = ({}: {}) => {
|
||||
)}
|
||||
<EditCreateVirtualFileModal iconSrc={'modal/manualDataset'} closeBtnText={''} />
|
||||
{isOpenFileSourceSelector && <FileSourceSelector onClose={onCloseFileSourceSelector} />}
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -29,7 +29,7 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
|
||||
const loadDatasetTags = useContextSelector(DatasetPageContext, (v) => v.loadDatasetTags);
|
||||
const loadAllDatasetTags = useContextSelector(DatasetPageContext, (v) => v.loadAllDatasetTags);
|
||||
const { getData, collections } = useContextSelector(CollectionPageContext, (v) => v);
|
||||
const { getData, pageNum, collections } = useContextSelector(CollectionPageContext, (v) => v);
|
||||
|
||||
const tagInputRef = useRef<HTMLInputElement>(null);
|
||||
const editInputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -73,15 +73,14 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
errorToast: t('common:common.Create Failed')
|
||||
});
|
||||
|
||||
const { mutate: onDeleteCollectionTag, isLoading: isDeleteCollectionTagLoading } = useRequest({
|
||||
mutationFn: async (tag: string) => {
|
||||
const id = await delDatasetCollectionTag({
|
||||
const { runAsync: onDeleteCollectionTag, loading: isDeleteCollectionTagLoading } = useRequest2(
|
||||
(tag: string) => {
|
||||
return delDatasetCollectionTag({
|
||||
datasetId: datasetDetail._id,
|
||||
id: tag
|
||||
});
|
||||
return id;
|
||||
},
|
||||
|
||||
{
|
||||
onSuccess() {
|
||||
fetchData(1);
|
||||
loadDatasetTags({ id: datasetDetail._id, searchKey: '' });
|
||||
@@ -89,26 +88,28 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
},
|
||||
successToast: t('common:common.Delete Success'),
|
||||
errorToast: t('common:common.Delete Failed')
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const { mutate: onUpdateCollectionTag, isLoading: isUpdateCollectionTagLoading } = useRequest({
|
||||
mutationFn: async (tag: DatasetTagType) => {
|
||||
const id = await updateDatasetCollectionTag({
|
||||
const { runAsync: onUpdateCollectionTag, loading: isUpdateCollectionTagLoading } = useRequest2(
|
||||
async (tag: DatasetTagType) => {
|
||||
return updateDatasetCollectionTag({
|
||||
datasetId: datasetDetail._id,
|
||||
tagId: tag._id,
|
||||
tag: tag.tag
|
||||
});
|
||||
return id;
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
fetchData(1);
|
||||
loadDatasetTags({ id: datasetDetail._id, searchKey: '' });
|
||||
loadAllDatasetTags({ id: datasetDetail._id });
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const { mutate: onSaveCollectionTag, isLoading: isSaveCollectionTagLoading } = useRequest({
|
||||
mutationFn: async ({
|
||||
const { runAsync: onSaveCollectionTag, loading: isSaveCollectionTagLoading } = useRequest2(
|
||||
async ({
|
||||
tag,
|
||||
originCollectionIds,
|
||||
collectionIds
|
||||
@@ -117,22 +118,21 @@ const TagManageModal = ({ onClose }: { onClose: () => void }) => {
|
||||
originCollectionIds: string[];
|
||||
collectionIds: string[];
|
||||
}) => {
|
||||
try {
|
||||
await postAddTagsToCollections({
|
||||
return postAddTagsToCollections({
|
||||
tag,
|
||||
originCollectionIds,
|
||||
collectionIds,
|
||||
datasetId: datasetDetail._id
|
||||
});
|
||||
} catch (error) {}
|
||||
},
|
||||
|
||||
onSuccess() {
|
||||
getData(1);
|
||||
{
|
||||
onFinally() {
|
||||
getData(pageNum);
|
||||
},
|
||||
successToast: t('common:common.Save Success'),
|
||||
errorToast: t('common:common.Save Failed')
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
list,
|
||||
@@ -379,11 +379,9 @@ const AddTagToCollections = ({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
|
||||
const [selectedCollections, setSelectedCollections] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedCollections(currentAddTag.collections);
|
||||
}, []);
|
||||
const [selectedCollections, setSelectedCollections] = useState<string[]>(
|
||||
currentAddTag.collections
|
||||
);
|
||||
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
|
@@ -21,7 +21,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
@@ -119,23 +119,22 @@ const CollectionCard = () => {
|
||||
successToast: t('common:common.Update Success')
|
||||
}
|
||||
);
|
||||
const { mutate: onDelCollection, isLoading: isDeleting } = useRequest({
|
||||
mutationFn: (collectionId: string) => {
|
||||
const { runAsync: onDelCollection, loading: isDeleting } = useRequest2(
|
||||
(collectionId: string) => {
|
||||
return delDatasetCollectionById({
|
||||
id: collectionId
|
||||
});
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
getData(pageNum);
|
||||
},
|
||||
successToast: t('common:common.Delete Success'),
|
||||
errorToast: t('common:common.Delete Failed')
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const { mutate: onclickStartSync, isLoading: isSyncing } = useRequest({
|
||||
mutationFn: (collectionId: string) => {
|
||||
return postLinkCollectionSync(collectionId);
|
||||
},
|
||||
const { runAsync: onclickStartSync, loading: isSyncing } = useRequest2(postLinkCollectionSync, {
|
||||
onSuccess(res: DatasetCollectionSyncResultEnum) {
|
||||
getData(pageNum);
|
||||
toast({
|
||||
@@ -186,12 +185,12 @@ const CollectionCard = () => {
|
||||
|
||||
return (
|
||||
<MyBox isLoading={isLoading} h={'100%'} py={[2, 4]}>
|
||||
<Flex ref={BoxRef} flexDirection={'column'} py={[1, 0]} h={'100%'}>
|
||||
<Flex ref={BoxRef} flexDirection={'column'} py={[1, 0]} h={'100%'} px={[2, 6]}>
|
||||
{/* header */}
|
||||
<Header />
|
||||
|
||||
{/* collection table */}
|
||||
<TableContainer px={[2, 6]} mt={[0, 3]} overflowY={'auto'} fontSize={'sm'}>
|
||||
<TableContainer mt={3} overflowY={'auto'} fontSize={'sm'}>
|
||||
<Table variant={'simple'} draggable={false}>
|
||||
<Thead draggable={false}>
|
||||
<Tr>
|
||||
@@ -237,7 +236,7 @@ const CollectionCard = () => {
|
||||
>
|
||||
<Td minW={'150px'} maxW={['200px', '300px']} draggable py={2}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={collection.icon as any} w={'18px'} mr={2} />
|
||||
<MyIcon name={collection.icon as any} w={'1.25rem'} mr={2} />
|
||||
<MyTooltip
|
||||
label={t('common:common.folder.Drag Tip')}
|
||||
shouldWrapChildren={false}
|
||||
@@ -287,8 +286,8 @@ const CollectionCard = () => {
|
||||
offset={[-70, 5]}
|
||||
Button={
|
||||
<MenuButton
|
||||
w={'22px'}
|
||||
h={'22px'}
|
||||
w={'1.5rem'}
|
||||
h={'1.5rem'}
|
||||
borderRadius={'md'}
|
||||
_hover={{
|
||||
color: 'primary.500',
|
||||
@@ -300,8 +299,8 @@ const CollectionCard = () => {
|
||||
<MyIcon
|
||||
className="icon"
|
||||
name={'more'}
|
||||
h={'16px'}
|
||||
w={'16px'}
|
||||
h={'1rem'}
|
||||
w={'1rem'}
|
||||
px={1}
|
||||
py={1}
|
||||
borderRadius={'md'}
|
||||
@@ -317,7 +316,11 @@ const CollectionCard = () => {
|
||||
{
|
||||
label: (
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'common/refreshLight'} w={'14px'} mr={2} />
|
||||
<MyIcon
|
||||
name={'common/refreshLight'}
|
||||
w={'0.9rem'}
|
||||
mr={2}
|
||||
/>
|
||||
{t('common:core.dataset.collection.Sync')}
|
||||
</Flex>
|
||||
),
|
||||
@@ -331,7 +334,7 @@ const CollectionCard = () => {
|
||||
{
|
||||
label: (
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'common/file/move'} w={'14px'} mr={2} />
|
||||
<MyIcon name={'common/file/move'} w={'0.9rem'} mr={2} />
|
||||
{t('common:Move')}
|
||||
</Flex>
|
||||
),
|
||||
@@ -341,7 +344,7 @@ const CollectionCard = () => {
|
||||
{
|
||||
label: (
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'edit'} w={'14px'} mr={2} />
|
||||
<MyIcon name={'edit'} w={'0.9rem'} mr={2} />
|
||||
{t('common:Rename')}
|
||||
</Flex>
|
||||
),
|
||||
@@ -365,7 +368,7 @@ const CollectionCard = () => {
|
||||
<MyIcon
|
||||
mr={1}
|
||||
name={'delete'}
|
||||
w={'14px'}
|
||||
w={'0.9rem'}
|
||||
_hover={{ color: 'red.600' }}
|
||||
/>
|
||||
<Box>{t('common:common.Delete')}</Box>
|
||||
|
@@ -47,7 +47,7 @@ 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';
|
||||
import Markdown from '@/components/Markdown';
|
||||
|
||||
const DataCard = () => {
|
||||
const BoxRef = useRef<HTMLDivElement>(null);
|
||||
@@ -232,6 +232,7 @@ const DataCard = () => {
|
||||
setEditDataId(item._id);
|
||||
}}
|
||||
>
|
||||
{/* Data tag */}
|
||||
<Flex
|
||||
position={'absolute'}
|
||||
zIndex={1}
|
||||
@@ -259,53 +260,18 @@ const DataCard = () => {
|
||||
ID:{item._id}
|
||||
</Box>
|
||||
</MyTag>
|
||||
|
||||
{/* {item.forbid ? (
|
||||
<MyTag colorSchema="gray" bg={'transparent'} px={1} showDot>
|
||||
{datasetT('Disabled')}
|
||||
</MyTag>
|
||||
) : (
|
||||
<MyTag colorSchema="green" bg={'transparent'} px={1} showDot>
|
||||
{datasetT('Enabled')}
|
||||
</MyTag>
|
||||
)}
|
||||
<HStack
|
||||
borderLeftWidth={'1.5px'}
|
||||
className="forbid-switch"
|
||||
display={['flex', 'none']}
|
||||
borderLeftColor={'myGray.200'}
|
||||
pl={1}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
h={'12px'}
|
||||
>
|
||||
<Switch
|
||||
size={'sm'}
|
||||
isChecked={!item.forbid}
|
||||
onChange={(e) => {
|
||||
e.stopPropagation();
|
||||
onUpdate({
|
||||
dataId: item._id,
|
||||
forbid: !e.target.checked
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</HStack> */}
|
||||
</Flex>
|
||||
<Box
|
||||
maxH={'135px'}
|
||||
minH={'90px'}
|
||||
overflow={'hidden'}
|
||||
wordBreak={'break-all'}
|
||||
pt={1}
|
||||
pb={3}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
<Box color={'black'} mb={1}>
|
||||
{item.q}
|
||||
|
||||
{/* Data content */}
|
||||
<Box wordBreak={'break-all'} fontSize={'sm'}>
|
||||
<Markdown source={item.q} forbidImgPreview />
|
||||
{!!item.a && (
|
||||
<>
|
||||
<MyDivider />
|
||||
<Markdown source={item.a} forbidImgPreview />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<Box color={'myGray.700'}>{item.a}</Box>
|
||||
|
||||
{/* Mask */}
|
||||
<Flex
|
||||
@@ -349,7 +315,7 @@ const DataCard = () => {
|
||||
display={'flex'}
|
||||
p={1}
|
||||
boxShadow={'1'}
|
||||
icon={<MyIcon name={'common/trash'} w={'14px'} color={'myGray.600'} />}
|
||||
icon={<MyIcon name={'common/trash'} w={'14px'} />}
|
||||
variant={'whiteDanger'}
|
||||
size={'xsSquare'}
|
||||
aria-label={'delete'}
|
||||
@@ -370,7 +336,6 @@ const DataCard = () => {
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Card>
|
||||
))}
|
||||
</Flex>
|
||||
|
@@ -1,7 +1,6 @@
|
||||
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';
|
||||
import { Box, Flex, Input } from '@chakra-ui/react';
|
||||
import { delDatasetById } from '@/web/core/dataset/api';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
@@ -9,7 +8,6 @@ import { useForm } from 'react-hook-form';
|
||||
import { compressImgFileAndUpload } from '@/web/common/file/controller';
|
||||
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
@@ -56,7 +54,6 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
defaultValues: datasetDetail
|
||||
});
|
||||
|
||||
const avatar = watch('avatar');
|
||||
const vectorModel = watch('vectorModel');
|
||||
const agentModel = watch('agentModel');
|
||||
const defaultPermission = watch('defaultPermission');
|
||||
@@ -77,8 +74,20 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
multiple: false
|
||||
});
|
||||
|
||||
const { mutate: onSave, isLoading: isSaving } = useRequest({
|
||||
mutationFn: (data: DatasetItemType) => {
|
||||
/* 点击删除 */
|
||||
const { mutate: onclickDelete, isLoading: isDeleting } = useRequest({
|
||||
mutationFn: () => {
|
||||
return delDatasetById(datasetId);
|
||||
},
|
||||
onSuccess() {
|
||||
router.replace(`/dataset/list`);
|
||||
},
|
||||
successToast: t('common:common.Delete Success'),
|
||||
errorToast: t('common:common.Delete Failed')
|
||||
});
|
||||
|
||||
const { runAsync: onSave, loading: isSaving } = useRequest2(
|
||||
(data: DatasetItemType) => {
|
||||
return updateDataset({
|
||||
id: datasetId,
|
||||
agentModel: data.agentModel,
|
||||
@@ -86,12 +95,14 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
defaultPermission: data.defaultPermission
|
||||
});
|
||||
},
|
||||
{
|
||||
successToast: t('common:common.Update Success'),
|
||||
errorToast: t('common:common.Update Failed')
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const { mutate: onSelectFile, isLoading: isSelecting } = useRequest({
|
||||
mutationFn: (e: File[]) => {
|
||||
const { runAsync: onSelectFile, loading: isSelecting } = useRequest2(
|
||||
(e: File[]) => {
|
||||
const file = e[0];
|
||||
if (!file) return Promise.resolve(null);
|
||||
return compressImgFileAndUpload({
|
||||
@@ -101,37 +112,41 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
maxH: 300
|
||||
});
|
||||
},
|
||||
{
|
||||
onSuccess(src: string | null) {
|
||||
if (src) {
|
||||
setValue('avatar', src);
|
||||
}
|
||||
},
|
||||
errorToast: t('common:common.avatar.Select Failed')
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const { mutate: onRebuilding, isLoading: isRebuilding } = useRequest({
|
||||
mutationFn: (vectorModel: VectorModelItemType) => {
|
||||
const { runAsync: onRebuilding, loading: isRebuilding } = useRequest2(
|
||||
(vectorModel: VectorModelItemType) => {
|
||||
return postRebuildEmbedding({
|
||||
datasetId,
|
||||
vectorModel: vectorModel.model
|
||||
});
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
refetchDatasetTraining();
|
||||
loadDatasetDetail(datasetId);
|
||||
},
|
||||
successToast: t('dataset:rebuild_embedding_start_tip'),
|
||||
errorToast: t('common:common.Update Failed')
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const { runAsync: onEditBaseInfo } = useRequest2((data) => updateDataset(data), {
|
||||
manual: true,
|
||||
const { runAsync: onEditBaseInfo } = useRequest2(updateDataset, {
|
||||
onSuccess() {
|
||||
setEditedDataset(undefined);
|
||||
},
|
||||
successToast: t('common:common.Update Success'),
|
||||
errorToast: t('common:common.Update Failed')
|
||||
});
|
||||
|
||||
const totalLoading = isSelecting || isSaving || isRebuilding;
|
||||
|
||||
return (
|
||||
<Box w={'100%'} h={'100%'} p={6}>
|
||||
<Box>
|
||||
@@ -225,7 +240,7 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
if (!vectorModel) return;
|
||||
return onOpenConfirmRebuild(() => {
|
||||
setValue('vectorModel', vectorModel);
|
||||
onRebuilding(vectorModel);
|
||||
return onRebuilding(vectorModel);
|
||||
})();
|
||||
}}
|
||||
/>
|
||||
@@ -260,7 +275,6 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
setValue('agentModel', agentModel);
|
||||
return handleSubmit((data) => onSave({ ...data, agentModel: agentModel }))();
|
||||
}}
|
||||
isDisabled={totalLoading}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -311,7 +325,6 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
fontSize={'mini'}
|
||||
per={defaultPermission}
|
||||
defaultPer={DatasetDefaultPermissionVal}
|
||||
isDisabled={totalLoading}
|
||||
onChange={(v) => {
|
||||
setValue('defaultPermission', v);
|
||||
return handleSubmit((data) => onSave({ ...data, defaultPermission: v }))();
|
||||
@@ -349,18 +362,15 @@ const Info = ({ datasetId }: { datasetId: string }) => {
|
||||
<EditResourceModal
|
||||
{...editedDataset}
|
||||
title={t('common:dataset.Edit Info')}
|
||||
onClose={() => {
|
||||
setEditedDataset(undefined);
|
||||
}}
|
||||
onEdit={async (data) => {
|
||||
await onEditBaseInfo({
|
||||
onClose={() => setEditedDataset(undefined)}
|
||||
onEdit={(data) =>
|
||||
onEditBaseInfo({
|
||||
id: editedDataset.id,
|
||||
name: data.name,
|
||||
intro: data.intro,
|
||||
avatar: data.avatar
|
||||
});
|
||||
setEditedDataset(undefined);
|
||||
}}
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
@@ -115,7 +115,7 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
w={'100%'}
|
||||
list={tabList}
|
||||
value={currentTab}
|
||||
activatedColor="blue.700"
|
||||
activeColor="primary.700"
|
||||
onChange={setCurrentTab}
|
||||
inlineStyles={{
|
||||
fontSize: '1rem',
|
||||
@@ -193,7 +193,7 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
</MyPopover>
|
||||
</Flex>
|
||||
) : (
|
||||
<Box mb={3}>
|
||||
<Box mb={2}>
|
||||
<LightRowTabs<TabEnum>
|
||||
m={'auto'}
|
||||
w={'full'}
|
||||
|
@@ -4,7 +4,7 @@ import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useSearchTestStore, SearchTestStoreItemType } from '@/web/core/dataset/store/searchTest';
|
||||
import { postSearchText } from '@/web/core/dataset/api';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
@@ -48,7 +48,6 @@ type FormType = {
|
||||
|
||||
const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { llmModelList } = useSystemStore();
|
||||
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
|
||||
@@ -86,9 +85,10 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
onClose: onCloseSelectMode
|
||||
} = useDisclosure();
|
||||
|
||||
const { mutate: onTextTest, isLoading: textTestIsLoading } = useRequest({
|
||||
mutationFn: ({ inputText, searchParams }: FormType) =>
|
||||
const { runAsync: onTextTest, loading: textTestIsLoading } = useRequest2(
|
||||
({ inputText, searchParams }: FormType) =>
|
||||
postSearchText({ datasetId, text: inputText.trim(), ...searchParams }),
|
||||
{
|
||||
onSuccess(res: SearchTestResponse) {
|
||||
if (!res || res.list.length === 0) {
|
||||
return toast({
|
||||
@@ -119,7 +119,8 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const onSelectFile = async (files: File[]) => {
|
||||
const file = files[0];
|
||||
@@ -329,6 +330,7 @@ const TestHistories = React.memo(function TestHistories({
|
||||
() => datasetTestList.filter((item) => item.datasetId === datasetId),
|
||||
[datasetId, datasetTestList]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex alignItems={'center'} color={'myGray.900'}>
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { Box, Flex, FlexProps } 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';
|
||||
import dynamic from 'next/dynamic';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
@@ -36,6 +35,13 @@ export enum TabEnum {
|
||||
}
|
||||
type Props = { datasetId: string; currentTab: TabEnum };
|
||||
|
||||
const sliderStyles: FlexProps = {
|
||||
bg: 'white',
|
||||
borderRadius: 'md',
|
||||
overflowY: 'scroll',
|
||||
boxShadow: 2
|
||||
};
|
||||
|
||||
const Detail = ({ datasetId, currentTab }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
@@ -64,20 +70,10 @@ const Detail = ({ datasetId, currentTab }: Props) => {
|
||||
<NextHead title={datasetDetail?.name} icon={datasetDetail?.avatar} />
|
||||
|
||||
{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'}
|
||||
>
|
||||
<Flex h={'100%'} py={3} pl={1} pr={3} gap={2}>
|
||||
<Flex flex={1} w={0} bg={'white'} flexDir={'column'} boxShadow={'2'} borderRadius={'md'}>
|
||||
{currentTab !== TabEnum.import && <NavBar currentTab={currentTab} />}
|
||||
<Box flex={'1 0 0'} w={'100%'} overflow={'auto'}>
|
||||
<Box flex={'1'} overflow={'auto'}>
|
||||
{currentTab === TabEnum.collectionCard && (
|
||||
<CollectionPageContextProvider>
|
||||
<CollectionCard />
|
||||
@@ -88,27 +84,24 @@ const Detail = ({ datasetId, currentTab }: Props) => {
|
||||
{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 ? (
|
||||
|
||||
{/* Slider */}
|
||||
<>
|
||||
{currentTab === TabEnum.dataCard && (
|
||||
<Flex {...sliderStyles} flex={'0 0 20rem'}>
|
||||
<MetaDataCard datasetId={datasetId} />
|
||||
) : (
|
||||
<Info datasetId={datasetId} />
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
{[TabEnum.collectionCard, TabEnum.test].includes(currentTab) && (
|
||||
<Flex {...sliderStyles} flex={'0 0 17rem'}>
|
||||
<Info datasetId={datasetId} />
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
</Flex>
|
||||
) : (
|
||||
<PageContainer insertProps={{ bg: 'white' }}>
|
||||
<MyBox display={'flex'} flexDirection={['column', 'row']} h={'100%'} pt={[4, 0]}>
|
||||
<MyBox display={'flex'} flexDirection={'column'} h={'100%'} pt={1}>
|
||||
<NavBar currentTab={currentTab} />
|
||||
|
||||
{!!datasetDetail._id && (
|
||||
|
@@ -120,7 +120,7 @@ export const putDatasetCollectionById = (data: UpdateDatasetCollectionParams) =>
|
||||
export const delDatasetCollectionById = (params: { id: string }) =>
|
||||
DELETE(`/core/dataset/collection/delete`, params);
|
||||
export const postLinkCollectionSync = (collectionId: string) =>
|
||||
POST<`${DatasetCollectionSyncResultEnum}`>(`/core/dataset/collection/sync/link`, {
|
||||
POST<DatasetCollectionSyncResultEnum>(`/core/dataset/collection/sync/link`, {
|
||||
collectionId
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user