New dpcs structure and dataset i18n (#551)

* perf: check balance

* md

* lock way

* i18n

* docs

* doc

* i18n

* update doc

* feat: one link sync

* feat: one link sync

* feat: one link sync

* feat: one link sync

* feat: one link sync

* feat: one link sync

* feat: one link sync
This commit is contained in:
Archer
2023-12-04 21:37:07 +08:00
committed by GitHub
parent c3ae38df8b
commit 62e87551ac
141 changed files with 961 additions and 469 deletions

View File

@@ -1,20 +1,13 @@
import React, {
useCallback,
useState,
useRef,
forwardRef,
useImperativeHandle,
ForwardedRef
} from 'react';
import React, { useCallback, useState, useMemo } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, Button, FormControl, IconButton, Input, Textarea } from '@chakra-ui/react';
import { QuestionOutlineIcon, DeleteIcon } from '@chakra-ui/icons';
import { Box, Flex, Button, IconButton, Input, Textarea } from '@chakra-ui/react';
import { DeleteIcon } from '@chakra-ui/icons';
import { delDatasetById } from '@/web/core/dataset/api';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useToast } from '@/web/common/hooks/useToast';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { UseFormReturn } from 'react-hook-form';
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 '@/components/Avatar';
@@ -23,26 +16,22 @@ import { useTranslation } from 'next-i18next';
import PermissionRadio from '@/components/support/permission/Radio';
import MySelect from '@/components/Select';
import { qaModelList } from '@/web/common/system/staticData';
import { useRequest } from '@/web/common/hooks/useRequest';
const Info = ({
datasetId,
form
}: {
datasetId: string;
form: UseFormReturn<DatasetItemType, any>;
}) => {
const Info = ({ datasetId }: { datasetId: string }) => {
const { t } = useTranslation();
const { getValues, formState, setValue, register, handleSubmit } = form;
const InputRef = useRef<HTMLInputElement>(null);
const { datasetDetail, loadDatasets, updateDataset } = useDatasetStore();
const { getValues, setValue, register, handleSubmit } = useForm<DatasetItemType>({
defaultValues: datasetDetail
});
const { toast } = useToast();
const router = useRouter();
const [btnLoading, setBtnLoading] = useState(false);
const [refresh, setRefresh] = useState(false);
const { openConfirm, ConfirmModal } = useConfirm({
content: '确认删除该知识库?数据将无法恢复,请确认!'
content: t('core.dataset.Delete Confirm'),
type: 'delete'
});
const { File, onOpen: onOpenSelectFile } = useSelectFile({
@@ -50,107 +39,68 @@ const Info = ({
multiple: false
});
const { datasetDetail, loadDatasets, updateDataset } = useDatasetStore();
/* 点击删除 */
const onclickDelKb = useCallback(async () => {
setBtnLoading(true);
try {
await delDatasetById(datasetId);
toast({
title: '删除成功',
status: 'success'
});
const { mutate: onclickDelete, isLoading: isDeleting } = useRequest({
mutationFn: () => {
return delDatasetById(datasetId);
},
onSuccess() {
router.replace(`/dataset/list`);
await loadDatasets();
} catch (err: any) {
toast({
title: err?.message || '删除失败',
status: 'error'
},
successToast: t('common.Delete Success'),
errorToast: t('common.Delete Failed')
});
const { mutate: onclickSave, isLoading: isSaving } = useRequest({
mutationFn: (data: DatasetItemType) => {
return updateDataset({
id: datasetId,
...data
});
}
setBtnLoading(false);
}, [setBtnLoading, datasetId, toast, router, loadDatasets]);
const saveSubmitSuccess = useCallback(
async (data: DatasetItemType) => {
setBtnLoading(true);
try {
await updateDataset({
id: datasetId,
...data
});
toast({
title: '更新成功',
status: 'success'
});
loadDatasets();
} catch (err: any) {
toast({
title: err?.message || '更新失败',
status: 'error'
});
}
setBtnLoading(false);
},
[updateDataset, datasetId, toast, loadDatasets]
);
const saveSubmitError = useCallback(() => {
// deep search message
const deepSearch = (obj: any): string => {
if (!obj) return '提交表单错误';
if (!!obj.message) {
return obj.message;
}
return deepSearch(Object.values(obj)[0]);
};
toast({
title: deepSearch(formState.errors),
status: 'error',
duration: 4000,
isClosable: true
});
}, [formState.errors, toast]);
onSuccess() {
loadDatasets();
},
successToast: t('common.Update Success'),
errorToast: t('common.Update Failed')
});
const onSelectFile = useCallback(
async (e: File[]) => {
const { mutate: onSelectFile, isLoading: isSelecting } = useRequest({
mutationFn: (e: File[]) => {
const file = e[0];
if (!file) return;
try {
const src = await compressImgFileAndUpload({
file,
maxW: 300,
maxH: 300
});
if (!file) return Promise.resolve(null);
return compressImgFileAndUpload({
file,
maxW: 300,
maxH: 300
});
},
onSuccess(src: string | null) {
if (src) {
setValue('avatar', src);
setRefresh((state) => !state);
} catch (err: any) {
toast({
title: typeof err === 'string' ? err : '头像选择异常',
status: 'warning'
});
}
},
[setRefresh, setValue, toast]
);
errorToast: t('common.avatar.Select Failed')
});
const btnLoading = useMemo(() => isDeleting || isSaving, [isDeleting, isSaving]);
return (
<Box py={5} px={[5, 10]}>
<Flex mt={5} w={'100%'} alignItems={'center'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
ID
{t('core.dataset.Dataset ID')}
</Box>
<Box flex={1}>{datasetDetail._id}</Box>
</Flex>
<Flex mt={5} w={'100%'} alignItems={'center'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
{t('core.dataset.Avatar')}
</Box>
<Box flex={[1, '0 0 300px']}>
<MyTooltip label={'点击切换头像'}>
<MyTooltip label={t('common.avatar.Select Avatar')}>
<Avatar
m={'auto'}
src={getValues('avatar')}
@@ -164,19 +114,13 @@ const Info = ({
</Flex>
<Flex mt={8} w={'100%'} alignItems={'center'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
{t('core.dataset.Name')}
</Box>
<Input
flex={[1, '0 0 300px']}
maxLength={30}
{...register('name', {
required: '知识库名称不能为空'
})}
/>
<Input flex={[1, '0 0 300px']} maxLength={30} {...register('name')} />
</Flex>
<Flex mt={8} w={'100%'} alignItems={'center'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
{t('core.ai.model.Vector Model')}
</Box>
<Box flex={[1, '0 0 300px']}>{getValues('vectorModel').name}</Box>
</Flex>
@@ -188,7 +132,7 @@ const Info = ({
</Flex>
<Flex mt={6} alignItems={'center'}>
<Box flex={['0 0 90px', '0 0 160px']} w={0}>
{t('dataset.Agent Model')}
{t('core.ai.model.Dataset Agent Model')}
</Box>
<Box flex={[1, '0 0 300px']}>
<MySelect
@@ -234,9 +178,9 @@ const Info = ({
isLoading={btnLoading}
mr={4}
w={'100px'}
onClick={handleSubmit(saveSubmitSuccess, saveSubmitError)}
onClick={handleSubmit((data) => onclickSave(data))}
>
{t('common.Save')}
</Button>
{datasetDetail.isOwner && (
<IconButton
@@ -249,7 +193,7 @@ const Info = ({
color: 'red.600',
borderColor: 'red.600'
}}
onClick={openConfirm(onclickDelKb)}
onClick={openConfirm(onclickDelete)}
/>
)}
</Flex>