4.8.10 test (#2470)

* i18n

* perf: invoice type

* fix: helper line change error

* perf: base64 image

* perf: app list ui

* perf: upload max size check

* perf: init system plugin

* perf: dataset list ui

* perf: http node ui

* perf: ui

* perf: invoice tip

* fix: ts

* perf: invoice table

* perf: null check
This commit is contained in:
Archer
2024-08-22 13:43:19 +08:00
committed by GitHub
parent 19904e648b
commit b3acd570f7
33 changed files with 576 additions and 552 deletions

View File

@@ -34,8 +34,10 @@ STORE_LOG_LEVEL=warn
7. 商业版新增 - SSO 定制 7. 商业版新增 - SSO 定制
8. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 8. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
9. 优化 - 节点选择,避免切换 tab 时候path 加载报错。 9. 优化 - 节点选择,避免切换 tab 时候path 加载报错。
10. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记 10. 优化 - 最新 React Markdown 组件,支持 Base64 图片
11. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情 11. 优化 - 知识库列表 UI
12. 修复 - 选择 Milvus 部署时,无法导出知识库。 12. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记。
13. 修复 - 创建 APP 副本,无法复制系统配置 13. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情
14. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。 14. 修复 - 选择 Milvus 部署时,无法导出知识库。
15. 修复 - 创建 APP 副本,无法复制系统配置。
16. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。

View File

@@ -49,8 +49,8 @@ export const HttpNode468: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.custom], renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.number, valueType: WorkflowIOValueTypeEnum.number,
label: '', label: '',
value: 120, value: 30,
min: 30, min: 5,
max: 600, max: 600,
required: true required: true
}, },

View File

@@ -94,11 +94,11 @@ export type LafAccountType = {
export type TeamInvoiceHeaderType = { export type TeamInvoiceHeaderType = {
teamName: string; teamName: string;
unifiedCreditCode: string; unifiedCreditCode: string;
companyAddress: string; companyAddress?: string;
companyPhone: string; companyPhone?: string;
bankName: string; bankName?: string;
bankAccount: string; bankAccount?: string;
needSpecialInvoice?: boolean; needSpecialInvoice: boolean;
emailAddress: string; emailAddress: string;
}; };

View File

@@ -36,9 +36,10 @@ export type InvoiceType = {
} & TeamInvoiceHeaderType; } & TeamInvoiceHeaderType;
export type InvoiceSchemaType = { export type InvoiceSchemaType = {
teamId: string;
_id: string; _id: string;
teamId: string;
status: 1 | 2; status: 1 | 2;
createTime: Date; createTime: Date;
finishTime?: Date; finishTime?: Date;
file?: Buffer;
} & InvoiceType; } & InvoiceType;

View File

@@ -14,8 +14,12 @@ type FileType = {
size: number; size: number;
}; };
/*
maxSize: File max size (MB)
*/
export const getUploadModel = ({ maxSize = 500 }: { maxSize?: number }) => { export const getUploadModel = ({ maxSize = 500 }: { maxSize?: number }) => {
maxSize *= 1024 * 1024; maxSize *= 1024 * 1024;
class UploadModel { class UploadModel {
uploader = multer({ uploader = multer({
limits: { limits: {

View File

@@ -31,6 +31,7 @@ type HttpRequestProps = ModuleDispatchProps<{
[NodeInputKeyEnum.httpParams]: PropsArrType[]; [NodeInputKeyEnum.httpParams]: PropsArrType[];
[NodeInputKeyEnum.httpJsonBody]: string; [NodeInputKeyEnum.httpJsonBody]: string;
[NodeInputKeyEnum.addInputParam]: Record<string, any>; [NodeInputKeyEnum.addInputParam]: Record<string, any>;
[NodeInputKeyEnum.httpTimeout]?: number;
[key: string]: any; [key: string]: any;
}>; }>;
type HttpResponse = DispatchNodeResultType<{ type HttpResponse = DispatchNodeResultType<{
@@ -57,7 +58,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
system_httpHeader: httpHeader, system_httpHeader: httpHeader,
system_httpParams: httpParams = [], system_httpParams: httpParams = [],
system_httpJsonBody: httpJsonBody, system_httpJsonBody: httpJsonBody,
system_httpTimeout: httpTimeout, system_httpTimeout: httpTimeout = 60,
[NodeInputKeyEnum.addInputParam]: dynamicInput, [NodeInputKeyEnum.addInputParam]: dynamicInput,
...body ...body
} }

View File

@@ -20,6 +20,7 @@
"external_read_url": "External read url", "external_read_url": "External read url",
"external_read_url_tip": "You can configure the reading address of your file library. This allows users to read and authenticate. You can currently use the {{fileId}} variable to refer to the external file ID.", "external_read_url_tip": "You can configure the reading address of your file library. This allows users to read and authenticate. You can currently use the {{fileId}} variable to refer to the external file ID.",
"external_url": "File read url", "external_url": "File read url",
"file_model_function_tip": "For enhanced indexing and QA generation",
"filename": "filename", "filename": "filename",
"folder_dataset": "Folder", "folder_dataset": "Folder",
"rebuild_embedding_start_tip": "The task of switching index models has begun", "rebuild_embedding_start_tip": "The task of switching index models has begun",

View File

@@ -1,4 +1,7 @@
{ {
"bill": {
"not_need_invoice": "Balance payment, unable to issue invoice"
},
"bind_inform_account_error": "Abnormal binding notification account", "bind_inform_account_error": "Abnormal binding notification account",
"bind_inform_account_success": "Binding notification account successful", "bind_inform_account_success": "Binding notification account successful",
"code_error": { "code_error": {

View File

@@ -617,8 +617,7 @@
"success": "开始同步" "success": "开始同步"
} }
}, },
"training": { "training": {}
}
}, },
"data": { "data": {
"Auxiliary Data": "辅助数据", "Auxiliary Data": "辅助数据",

View File

@@ -20,6 +20,7 @@
"external_read_url": "外部预览地址", "external_read_url": "外部预览地址",
"external_read_url_tip": "可以配置你文件库的阅读地址。便于对用户进行阅读鉴权操作。目前可以使用 {{fileId}} 变量来指代外部文件 ID。", "external_read_url_tip": "可以配置你文件库的阅读地址。便于对用户进行阅读鉴权操作。目前可以使用 {{fileId}} 变量来指代外部文件 ID。",
"external_url": "文件访问 URL", "external_url": "文件访问 URL",
"file_model_function_tip": "用于增强索引和 QA 生成",
"filename": "文件名", "filename": "文件名",
"folder_dataset": "文件夹", "folder_dataset": "文件夹",
"rebuild_embedding_start_tip": "切换索引模型任务已开始", "rebuild_embedding_start_tip": "切换索引模型任务已开始",

View File

@@ -1,4 +1,7 @@
{ {
"bill": {
"not_need_invoice": "余额支付,无法开票"
},
"bind_inform_account_error": "绑定通知账号异常", "bind_inform_account_error": "绑定通知账号异常",
"bind_inform_account_success": "绑定通知账号成功", "bind_inform_account_success": "绑定通知账号成功",
"delete": { "delete": {

View File

@@ -32,7 +32,7 @@ SANDBOX_URL=http://localhost:3001
PRO_URL= PRO_URL=
# 首页路径 # 首页路径
HOME_URL=/ HOME_URL=/
# 日志等级: debug, info, warn, error # 日志等级: debug, info, warn, error
LOG_LEVEL=debug LOG_LEVEL=debug
STORE_LOG_LEVEL=warn STORE_LOG_LEVEL=warn
# Loki Log Path

View File

@@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { ImageProps, Skeleton } from '@chakra-ui/react'; import { Box, ImageProps, Skeleton } from '@chakra-ui/react';
import MyPhotoView from '@fastgpt/web/components/common/Image/PhotoView'; import MyPhotoView from '@fastgpt/web/components/common/Image/PhotoView';
import { useBoolean } from 'ahooks'; import { useBoolean } from 'ahooks';
@@ -8,6 +8,10 @@ const MdImage = ({ src, ...props }: { src?: string } & ImageProps) => {
const [renderSrc, setRenderSrc] = useState(src); const [renderSrc, setRenderSrc] = useState(src);
if (src?.includes('base64') && !src.startsWith('data:image')) {
return <Box>Invalid base64 image</Box>;
}
return ( return (
<Skeleton isLoaded={isLoaded}> <Skeleton isLoaded={isLoaded}>
<MyPhotoView <MyPhotoView

View File

@@ -1,4 +1,4 @@
import React, { useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import 'katex/dist/katex.min.css'; import 'katex/dist/katex.min.css';
import RemarkMath from 'remark-math'; // Math syntax import RemarkMath from 'remark-math'; // Math syntax
@@ -52,6 +52,10 @@ const Markdown = ({
return formatSource; return formatSource;
}, [source]); }, [source]);
const urlTransform = useCallback((val: string) => {
return val;
}, []);
return ( return (
<ReactMarkdown <ReactMarkdown
className={`markdown ${styles.markdown} className={`markdown ${styles.markdown}
@@ -60,6 +64,7 @@ const Markdown = ({
remarkPlugins={[RemarkMath, [RemarkGfm, { singleTilde: false }], RemarkBreaks]} remarkPlugins={[RemarkMath, [RemarkGfm, { singleTilde: false }], RemarkBreaks]}
rehypePlugins={[RehypeKatex, [RehypeExternalLinks, { target: '_blank' }]]} rehypePlugins={[RehypeKatex, [RehypeExternalLinks, { target: '_blank' }]]}
components={components} components={components}
urlTransform={urlTransform}
> >
{formatSource} {formatSource}
</ReactMarkdown> </ReactMarkdown>

View File

@@ -9,6 +9,7 @@ const NextHead = ({ title, icon, desc }: { title?: string; icon?: string; desc?:
name="viewport" name="viewport"
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no, viewport-fit=cover" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no, viewport-fit=cover"
/> />
<meta httpEquiv="Content-Security-Policy" content="img-src * data:;" />
{desc && <meta name="description" content={desc} />} {desc && <meta name="description" content={desc} />}
{icon && <link rel="icon" href={icon} />} {icon && <link rel="icon" href={icon} />}
</Head> </Head>

View File

@@ -409,7 +409,7 @@ const PlanUsage = () => {
return standardPlan ? ( return standardPlan ? (
<Box mt={[6, 0]}> <Box mt={[6, 0]}>
<Flex fontSize={'lg'} h={'30px'}> <Flex fontSize={['md', 'lg']} h={'30px'}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<MyIcon mr={2} name={'support/account/plans'} w={'20px'} /> <MyIcon mr={2} name={'support/account/plans'} w={'20px'} />
{t('common:support.wallet.subscription.Team plan and usage')} {t('common:support.wallet.subscription.Team plan and usage')}
@@ -428,7 +428,7 @@ const PlanUsage = () => {
borderColor={'borderColor.low'} borderColor={'borderColor.low'}
borderRadius={'md'} borderRadius={'md'}
> >
<Flex px={[5, 7]} py={[3, 6]}> <Flex px={[5, 7]} py={[3, 6]} whiteSpace={'nowrap'}>
<Box flex={'1 0 0'}> <Box flex={'1 0 0'}>
<Box color={'myGray.600'} fontSize="sm"> <Box color={'myGray.600'} fontSize="sm">
{t('common:support.wallet.subscription.Current plan')} {t('common:support.wallet.subscription.Current plan')}
@@ -475,8 +475,10 @@ const PlanUsage = () => {
> >
<Flex> <Flex>
<Flex flex={'1 0 0'} alignItems={'flex-end'}> <Flex flex={'1 0 0'} alignItems={'flex-end'}>
<Box fontSize={'md'}>{t('common:info.resource')}</Box> <Box fontSize={'md'} fontWeight={'bold'} color={'myGray.900'}>
<Box fontSize={'xs'} color={'myGray.500'}> {t('common:info.resource')}
</Box>
<Box ml={1} display={['none', 'block']} fontSize={'xs'} color={'myGray.500'}>
{t('common:info.include')} {t('common:info.include')}
</Box> </Box>
</Flex> </Flex>

View File

@@ -32,52 +32,25 @@ import MyBox from '@fastgpt/web/components/common/MyBox';
import { getTeamInvoiceHeader } from '@/web/support/user/team/api'; import { getTeamInvoiceHeader } from '@/web/support/user/team/api';
import { useToast } from '@fastgpt/web/hooks/useToast'; import { useToast } from '@fastgpt/web/hooks/useToast';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useForm } from 'react-hook-form';
type chosenBillDataType = { type chosenBillDataType = {
_id: string; _id: string;
price: number; price: number;
}; };
const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => { const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToast(); const router = useRouter();
const [chosenBillDataList, setChosenBillDataList] = useState<chosenBillDataType[]>([]); const [chosenBillDataList, setChosenBillDataList] = useState<chosenBillDataType[]>([]);
const [totalPrice, setTotalPrice] = useState(0); const [totalPrice, setTotalPrice] = useState(0);
const [formData, setFormData] = useState<TeamInvoiceHeaderType>({
teamName: '',
unifiedCreditCode: '',
companyAddress: '',
companyPhone: '',
bankName: '',
bankAccount: '',
needSpecialInvoice: undefined,
emailAddress: ''
});
const router = useRouter();
const { const {
isOpen: isOpenSettleModal, isOpen: isOpenSettleModal,
onOpen: onOpenSettleModal, onOpen: onOpenSettleModal,
onClose: onCloseSettleModal onClose: onCloseSettleModal
} = useDisclosure(); } = useDisclosure();
const handleChange = useCallback((e: any) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
}, []);
const handleRatiosChange = useCallback((v: string) => {
setFormData((prev) => ({ ...prev, needSpecialInvoice: v === 'true' }));
}, []);
const isHeaderValid = useCallback((v: TeamInvoiceHeaderType) => {
const emailRegex = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
for (const [key, value] of Object.entries(v)) {
if (typeof value === 'string' && value.trim() === '') {
return false;
}
}
return emailRegex.test(v.emailAddress);
}, []);
const { const {
loading: isLoading, loading: isLoading,
data: billsList, data: billsList,
@@ -86,12 +59,23 @@ const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => {
manual: false manual: false
}); });
const { run: handleSubmitInvoice, loading: isSubmitting } = useRequest2( const handleSingleCheck = useCallback(
() => (item: invoiceBillDataType) => {
if (chosenBillDataList.find((bill) => bill._id === item._id)) {
setChosenBillDataList(chosenBillDataList.filter((bill) => bill._id !== item._id));
} else {
setChosenBillDataList([...chosenBillDataList, { _id: item._id, price: item.price }]);
}
},
[chosenBillDataList]
);
const { runAsync: onSubmitApply, loading: isSubmitting } = useRequest2(
(data) =>
submitInvoice({ submitInvoice({
amount: totalPrice, amount: totalPrice,
billIdList: chosenBillDataList.map((item) => item._id), billIdList: chosenBillDataList.map((item) => item._id),
...formData ...data
}), }),
{ {
manual: true, manual: true,
@@ -104,39 +88,29 @@ const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => {
} }
); );
const inputForm = useForm<TeamInvoiceHeaderType>({
defaultValues: {
teamName: '',
unifiedCreditCode: '',
companyAddress: '',
companyPhone: '',
bankName: '',
bankAccount: '',
needSpecialInvoice: false,
emailAddress: ''
}
});
const { loading: isLoadingHeader } = useRequest2(() => getTeamInvoiceHeader(), { const { loading: isLoadingHeader } = useRequest2(() => getTeamInvoiceHeader(), {
manual: false, manual: false,
onSuccess: (res) => setFormData(res) onSuccess: (res) => inputForm.reset(res)
}); });
const handleSubmit = useCallback(async () => {
if (!isHeaderValid(formData)) {
toast({
title: t('common:support.wallet.invoice_data.in_valid'),
status: 'info'
});
return;
}
handleSubmitInvoice();
}, [formData, handleSubmitInvoice, isHeaderValid, t, toast]);
const handleBack = useCallback(() => { const handleBack = useCallback(() => {
setChosenBillDataList([]); setChosenBillDataList([]);
getInvoiceBills(); getInvoiceBills();
onCloseSettleModal(); onCloseSettleModal();
}, [getInvoiceBills, onCloseSettleModal]); }, [getInvoiceBills, onCloseSettleModal]);
const handleSingleCheck = useCallback(
(item: invoiceBillDataType) => {
if (chosenBillDataList.find((bill) => bill._id === item._id)) {
setChosenBillDataList(chosenBillDataList.filter((bill) => bill._id !== item._id));
} else {
setChosenBillDataList([...chosenBillDataList, { _id: item._id, price: item.price }]);
}
},
[chosenBillDataList]
);
return ( return (
<MyModal <MyModal
isOpen={true} isOpen={true}
@@ -258,11 +232,7 @@ const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => {
</Box> </Box>
<MyBox isLoading={isLoadingHeader}> <MyBox isLoading={isLoadingHeader}>
<Flex justify={'center'}> <Flex justify={'center'}>
<InvoiceHeaderSingleForm <InvoiceHeaderSingleForm inputForm={inputForm} />
formData={formData}
handleChange={handleChange}
handleRatiosChange={handleRatiosChange}
/>
</Flex> </Flex>
</MyBox> </MyBox>
<Flex <Flex
@@ -289,7 +259,7 @@ const ApplyInvoiceModal = ({ onClose }: { onClose: () => void }) => {
</Box> </Box>
</Flex> </Flex>
</Button> </Button>
<Button isLoading={isSubmitting} px="0" onClick={handleSubmit}> <Button isLoading={isSubmitting} px="0" onClick={inputForm.handleSubmit(onSubmitApply)}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<Box px={'1.25rem'} py={'0.5rem'}> <Box px={'1.25rem'} py={'0.5rem'}>
{t('common:common.Confirm')} {t('common:common.Confirm')}

View File

@@ -6,19 +6,22 @@ import { useTranslation } from 'next-i18next';
import ApplyInvoiceModal from './ApplyInvoiceModal'; import ApplyInvoiceModal from './ApplyInvoiceModal';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
export const InvoiceTabEnum = { export enum InvoiceTabEnum {
bill: 'bill', bill = 'bill',
invoice: 'invoice', invoice = 'invoice',
invoiceHeader: 'invoiceHeader' invoiceHeader = 'invoiceHeader'
}; }
const BillTable = dynamic(() => import('./BillTable')); const BillTable = dynamic(() => import('./BillTable'));
const InvoiceHeaderForm = dynamic(() => import('./InvoiceHeaderForm')); const InvoiceHeaderForm = dynamic(() => import('./InvoiceHeaderForm'));
const InvoiceTable = dynamic(() => import('./InvoiceTable')); const InvoiceTable = dynamic(() => import('./InvoiceTable'));
const BillAndInvoice = () => { const BillAndInvoice = () => {
const [isOpenInvoiceModal, setIsOpenInvoiceModal] = useState(false);
const router = useRouter();
const invoiceTab = (router.query.invoiceTab as string) || InvoiceTabEnum.bill;
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter();
const { invoiceTab = InvoiceTabEnum.bill } = router.query as { invoiceTab: `${InvoiceTabEnum}` };
const [isOpenInvoiceModal, setIsOpenInvoiceModal] = useState(false);
return ( return (
<> <>
<Box p={['1rem', '2rem']}> <Box p={['1rem', '2rem']}>
@@ -36,7 +39,7 @@ const BillAndInvoice = () => {
onChange={(e) => { onChange={(e) => {
router.replace({ router.replace({
query: { query: {
currentTab: router.query.currentTab, ...router.query,
invoiceTab: e invoiceTab: e
} }
}); });

View File

@@ -101,6 +101,7 @@ const BillTable = () => {
isLoading={isLoading || isRefreshing} isLoading={isLoading || isRefreshing}
position={'relative'} position={'relative'}
h={'100%'} h={'100%'}
minH={'50vh'}
overflow={'overlay'} overflow={'overlay'}
> >
<TableContainer> <TableContainer>
@@ -198,6 +199,10 @@ function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: ()
<FormLabel flex={'0 0 120px'}>{t('common:support.wallet.usage.Time')}:</FormLabel> <FormLabel flex={'0 0 120px'}>{t('common:support.wallet.usage.Time')}:</FormLabel>
<Box>{dayjs(bill.createTime).format('YYYY/MM/DD HH:mm:ss')}</Box> <Box>{dayjs(bill.createTime).format('YYYY/MM/DD HH:mm:ss')}</Box>
</Flex> </Flex>
<Flex alignItems={'center'} pb={4}>
<FormLabel flex={'0 0 120px'}>{t('common:support.wallet.bill.Type')}:</FormLabel>
<Box>{t(billTypeMap[bill.type]?.label as any)}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}> <Flex alignItems={'center'} pb={4}>
<FormLabel flex={'0 0 120px'}>{t('common:support.wallet.bill.Status')}:</FormLabel> <FormLabel flex={'0 0 120px'}>{t('common:support.wallet.bill.Status')}:</FormLabel>
<Box>{t(billStatusMap[bill.status]?.label as any)}</Box> <Box>{t(billStatusMap[bill.status]?.label as any)}</Box>
@@ -212,14 +217,18 @@ function BillDetailModal({ bill, onClose }: { bill: BillSchemaType; onClose: ()
<FormLabel flex={'0 0 120px'}>{t('common:support.wallet.Amount')}:</FormLabel> <FormLabel flex={'0 0 120px'}>{t('common:support.wallet.Amount')}:</FormLabel>
<Box>{commonT('common:pay.yuan', { amount: formatStorePrice2Read(bill.price) })}</Box> <Box>{commonT('common:pay.yuan', { amount: formatStorePrice2Read(bill.price) })}</Box>
</Flex> </Flex>
<Flex alignItems={'center'} pb={4}> {bill.metadata && (
<FormLabel flex={'0 0 120px'}>{t('common:support.wallet.bill.Type')}:</FormLabel>
<Box>{t(billTypeMap[bill.type]?.label as any)}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}> <Flex alignItems={'center'} pb={4}>
<FormLabel flex={'0 0 120px'}>{t('common:support.wallet.has_invoice')}:</FormLabel> <FormLabel flex={'0 0 120px'}>{t('common:support.wallet.has_invoice')}:</FormLabel>
<Box>{bill.hasInvoice ? t('common:yes') : t('common:no')}</Box> {bill.metadata.payWay === 'balance' ? (
t('user:bill.not_need_invoice')
) : (
<Box>
{(bill.metadata.payWay = bill.hasInvoice ? t('common:yes') : t('common:no'))}
</Box>
)}
</Flex> </Flex>
)}
{!!bill.metadata?.subMode && ( {!!bill.metadata?.subMode && (
<Flex alignItems={'center'} pb={4}> <Flex alignItems={'center'} pb={4}>
<FormLabel flex={'0 0 120px'}> <FormLabel flex={'0 0 120px'}>

View File

@@ -1,56 +1,28 @@
import Divider from '@/pages/app/detail/components/WorkflowComponents/Flow/components/Divider'; import Divider from '@/pages/app/detail/components/WorkflowComponents/Flow/components/Divider';
import { getTeamInvoiceHeader, updateTeamInvoiceHeader } from '@/web/support/user/team/api'; import { getTeamInvoiceHeader, updateTeamInvoiceHeader } from '@/web/support/user/team/api';
import { Box, Button, Flex, Input, Radio, RadioGroup, Stack } from '@chakra-ui/react'; import { Box, Button, Flex, HStack, Input, InputProps, Radio, RadioGroup } from '@chakra-ui/react';
import { TeamInvoiceHeaderType } from '@fastgpt/global/support/user/team/type'; import { TeamInvoiceHeaderType } from '@fastgpt/global/support/user/team/type';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useCallback, useState } from 'react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useToast } from '@fastgpt/web/hooks/useToast'; import { UseFormReturn, useForm } from 'react-hook-form';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
const InputItem = ({
label,
value,
onChange,
name
}: {
label: string;
value: string;
onChange: (e: any) => void;
name: string;
}) => {
return (
<>
<Flex justify={'space-between'} flexDir={['column', 'row']}>
<Box fontSize={'14px'} lineHeight={'2rem'}>
{label}
</Box>
<Input
bg={'myGray.50'}
border={'1px solid'}
borderColor={'myGray.200'}
w={'21.25rem'}
focusBorderColor="myGray.200"
placeholder={label}
value={value}
onChange={onChange}
name={name}
/>
</Flex>
</>
);
};
export const InvoiceHeaderSingleForm = ({ export const InvoiceHeaderSingleForm = ({
formData, inputForm
handleChange,
handleRatiosChange
}: { }: {
formData: TeamInvoiceHeaderType; inputForm: UseFormReturn<TeamInvoiceHeaderType, any>;
handleChange: (e: any) => void;
handleRatiosChange: (v: string) => void;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { watch, register } = inputForm;
const needSpecialInvoice = watch('needSpecialInvoice');
const styles: InputProps = {
bg: 'myGray.50',
w: '21.25rem'
};
return ( return (
<> <>
<Flex <Flex
@@ -61,138 +33,185 @@ export const InvoiceHeaderSingleForm = ({
color={'myGray.900'} color={'myGray.900'}
fontSize={'14px'} fontSize={'14px'}
> >
<InputItem <Flex
label={t('common:support.wallet.invoice_data.organization_name')} justify={'space-between'}
value={formData.teamName} alignItems={['flex-start', 'center']}
onChange={handleChange} flexDir={['column', 'row']}
name="teamName" >
<FormLabel required>
{t('common:support.wallet.invoice_data.organization_name')}
</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.organization_name')}
{...register('teamName', { required: true })}
/> />
<InputItem </Flex>
label={t('common:support.wallet.invoice_data.unit_code')} <Flex
value={formData.unifiedCreditCode} justify={'space-between'}
onChange={handleChange} alignItems={['flex-start', 'center']}
name="unifiedCreditCode" flexDir={['column', 'row']}
>
<FormLabel required>{t('common:support.wallet.invoice_data.unit_code')}</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.unit_code')}
{...register('unifiedCreditCode', { required: true })}
/> />
<InputItem </Flex>
label={t('common:support.wallet.invoice_data.company_address')} <Flex
value={formData.companyAddress} justify={'space-between'}
onChange={handleChange} alignItems={['flex-start', 'center']}
name="companyAddress" flexDir={['column', 'row']}
>
<FormLabel required={!!needSpecialInvoice}>
{t('common:support.wallet.invoice_data.company_address')}
</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.company_address')}
{...register('companyAddress', { required: !!needSpecialInvoice })}
/> />
<InputItem </Flex>
label={t('common:support.wallet.invoice_data.company_phone')} <Flex
value={formData.companyPhone} justify={'space-between'}
onChange={handleChange} alignItems={['flex-start', 'center']}
name="companyPhone" flexDir={['column', 'row']}
>
<FormLabel required={!!needSpecialInvoice}>
{t('common:support.wallet.invoice_data.company_phone')}
</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.company_phone')}
{...register('companyPhone', { required: !!needSpecialInvoice })}
/> />
<InputItem </Flex>
label={t('common:support.wallet.invoice_data.bank')} <Flex
value={formData.bankName} justify={'space-between'}
onChange={handleChange} alignItems={['flex-start', 'center']}
name="bankName" flexDir={['column', 'row']}
>
<FormLabel required={!!needSpecialInvoice}>
{t('common:support.wallet.invoice_data.bank')}
</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.bank')}
{...register('bankName', { required: !!needSpecialInvoice })}
/> />
<InputItem </Flex>
label={t('common:support.wallet.invoice_data.bank_account')} <Flex
value={formData.bankAccount} justify={'space-between'}
onChange={handleChange} alignItems={['flex-start', 'center']}
name="bankAccount" flexDir={['column', 'row']}
>
<FormLabel required={!!needSpecialInvoice}>
{t('common:support.wallet.invoice_data.bank_account')}
</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.bank_account')}
{...register('bankAccount', { required: !!needSpecialInvoice })}
/> />
<Flex justify={'space-between'} flexDir={['column', 'row']}> </Flex>
<Box fontSize={'14px'} lineHeight={'2rem'}> <Flex
justify={'space-between'}
alignItems={['flex-start', 'center']}
flexDir={['column', 'row']}
>
<FormLabel required>
{t('common:support.wallet.invoice_data.need_special_invoice')} {t('common:support.wallet.invoice_data.need_special_invoice')}
</Box> </FormLabel>
{/* @ts-ignore */}
<RadioGroup <RadioGroup
value={ value={`${needSpecialInvoice}`}
formData.needSpecialInvoice === undefined onChange={(e) => {
? '' inputForm.setValue('needSpecialInvoice', e === 'true');
: formData.needSpecialInvoice.toString() }}
}
onChange={handleRatiosChange}
w={'21.25rem'} w={'21.25rem'}
> >
<Stack direction="row" h={'2rem'}> <HStack h={'2rem'}>
<Radio value="true" pr={'1rem'}> <Radio value="true" pr={'1rem'}>
<Box fontSize={'14px'}>{t('common:yes')}</Box> <Box fontSize={'14px'}>{t('common:yes')}</Box>
</Radio> </Radio>
<Radio value="false"> <Radio value="false">
<Box fontSize={'14px'}>{t('common:no')}</Box> <Box fontSize={'14px'}>{t('common:no')}</Box>
</Radio> </Radio>
</Stack> </HStack>
</RadioGroup> </RadioGroup>
</Flex> </Flex>
<Box w={'100%'}> <Box w={'100%'}>
<Divider showBorderBottom={false} /> <Divider showBorderBottom={false} />
</Box> </Box>
<InputItem <Flex
label={t('common:support.wallet.invoice_data.email')} justify={'space-between'}
value={formData.emailAddress} alignItems={['flex-start', 'center']}
onChange={handleChange} flexDir={['column', 'row']}
name="emailAddress" >
<FormLabel required>{t('common:support.wallet.invoice_data.email')}</FormLabel>
<Input
{...styles}
placeholder={t('common:support.wallet.invoice_data.email')}
{...register('emailAddress', {
required: true,
pattern: {
value: /(^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$)/,
message: t('user:password.email_phone_error')
}
})}
/> />
</Flex> </Flex>
</Flex>
</> </>
); );
}; };
const InvoiceHeaderForm = () => { const InvoiceHeaderForm = () => {
const [formData, setFormData] = useState<TeamInvoiceHeaderType>({ const inputForm = useForm<TeamInvoiceHeaderType>({
defaultValues: {
teamName: '', teamName: '',
unifiedCreditCode: '', unifiedCreditCode: '',
companyAddress: '', companyAddress: '',
companyPhone: '', companyPhone: '',
bankName: '', bankName: '',
bankAccount: '', bankAccount: '',
needSpecialInvoice: undefined, needSpecialInvoice: false,
emailAddress: '' emailAddress: ''
}
}); });
const { loading: isLoading } = useRequest2(() => getTeamInvoiceHeader(), { const { loading: isLoading } = useRequest2(() => getTeamInvoiceHeader(), {
manual: false, manual: false,
onSuccess: (data) => { onSuccess: (data) => {
setFormData(data); console.log(data, '--');
inputForm.reset(data);
} }
}); });
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToast();
const handleChange = useCallback((e: any) => { const { loading: isSubmitting, runAsync: onUpdateHeader } = useRequest2(
const { name, value } = e.target; (data: TeamInvoiceHeaderType) => updateTeamInvoiceHeader(data),
setFormData((prev) => ({ ...prev, [name]: value }));
}, []);
const handleRatiosChange = useCallback((v: string) => {
setFormData((prev) => ({ ...prev, needSpecialInvoice: v === 'true' }));
}, []);
const isHeaderValid = useCallback((v: TeamInvoiceHeaderType) => {
const emailRegex = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
return emailRegex.test(v.emailAddress);
}, []);
const { loading: isSubmitting, run: handleSubmit } = useRequest2(
() => updateTeamInvoiceHeader(formData),
{ {
manual: true, manual: true,
successToast: t('common:common.Save Success'), successToast: t('common:common.Save Success'),
errorToast: t('common:common.Save Failed') errorToast: t('common:common.Save Failed')
} }
); );
const onSubmit = useCallback(() => {
if (!isHeaderValid(formData)) {
toast({
title: t('common:support.wallet.invoice_data.in_valid'),
status: 'info'
});
return;
}
handleSubmit();
}, [handleSubmit, formData, isHeaderValid, toast, t]);
return ( return (
<> <>
<MyBox isLoading={isLoading} pt={['1rem', '3.5rem']}> <MyBox isLoading={isLoading} pt={['1rem', '3.5rem']}>
<Flex w={'100%'} overflow={'auto'} justify={'center'} flexDir={'column'} align={'center'}> <Flex w={'100%'} overflow={'auto'} justify={'center'} flexDir={'column'} align={'center'}>
<InvoiceHeaderSingleForm <InvoiceHeaderSingleForm inputForm={inputForm} />
formData={formData}
handleChange={handleChange}
handleRatiosChange={handleRatiosChange}
/>
<Flex w={'100%'} justify={'center'} mt={'3rem'}> <Flex w={'100%'} justify={'center'} mt={'3rem'}>
<Button variant={'primary'} px="0" onClick={onSubmit} isLoading={isSubmitting}> <Button
variant={'primary'}
px="0"
onClick={inputForm.handleSubmit(onUpdateHeader)}
isLoading={isSubmitting}
>
<Flex alignItems={'center'} px={'20px'}> <Flex alignItems={'center'} px={'20px'}>
<Box px={'1.25rem'} py={'0.5rem'}> <Box px={'1.25rem'} py={'0.5rem'}>
{t('common:common.Save')} {t('common:common.Save')}

View File

@@ -197,11 +197,11 @@ function InvoiceDetailModal({
); );
} }
function LabelItem({ label, value }: { label: string; value: string }) { function LabelItem({ label, value }: { label: string; value?: string }) {
return ( return (
<Flex alignItems={'center'} justify={'space-between'}> <Flex alignItems={'center'} justify={'space-between'}>
<FormLabel flex={'0 0 120px'}>{label}</FormLabel> <FormLabel flex={'0 0 120px'}>{label}</FormLabel>
<Box>{value}</Box> <Box>{value || '-'}</Box>
</Flex> </Flex>
); );
} }

View File

@@ -26,7 +26,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const start = Date.now(); const start = Date.now();
/* Creates the multer uploader */ /* Creates the multer uploader */
const upload = getUploadModel({ const upload = getUploadModel({
maxSize: (global.feConfigs?.uploadFileMaxSize || 500) * 1024 * 1024 maxSize: global.feConfigs?.uploadFileMaxSize
}); });
const { file, bucketName, metadata } = await upload.doUpload(req, res); const { file, bucketName, metadata } = await upload.doUpload(req, res);
filePaths.push(file.path); filePaths.push(file.path);

View File

@@ -30,7 +30,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): CreateCo
* Creates the multer uploader * Creates the multer uploader
*/ */
const upload = getUploadModel({ const upload = getUploadModel({
maxSize: (global.feConfigs?.uploadFileMaxSize || 500) * 1024 * 1024 maxSize: global.feConfigs?.uploadFileMaxSize
}); });
let filePaths: string[] = []; let filePaths: string[] = [];

View File

@@ -279,7 +279,7 @@ export const useWorkflow = () => {
const [helperLineHorizontal, setHelperLineHorizontal] = useState<THelperLine>(); const [helperLineHorizontal, setHelperLineHorizontal] = useState<THelperLine>();
const [helperLineVertical, setHelperLineVertical] = useState<THelperLine>(); const [helperLineVertical, setHelperLineVertical] = useState<THelperLine>();
const customApplyNodeChanges = (changes: NodeChange[], nodes: Node[]): Node[] => { const customApplyNodeChanges = (changes: NodeChange[], nodes: Node[]) => {
const positionChange = const positionChange =
changes[0].type === 'position' && changes[0].dragging ? changes[0] : undefined; changes[0].type === 'position' && changes[0].dragging ? changes[0] : undefined;
@@ -316,14 +316,10 @@ export const useWorkflow = () => {
setHelperLineHorizontal(undefined); setHelperLineHorizontal(undefined);
setHelperLineVertical(undefined); setHelperLineVertical(undefined);
} }
return applyNodeChanges(changes, nodes);
}; };
/* node */ /* node */
const handleNodesChange = (changes: NodeChange[]) => { const handleNodesChange = (changes: NodeChange[]) => {
setNodes((nodes) => customApplyNodeChanges(changes, nodes));
for (const change of changes) { for (const change of changes) {
if (change.type === 'remove') { if (change.type === 'remove') {
const node = nodes.find((n) => n.id === change.id); const node = nodes.find((n) => n.id === change.id);
@@ -345,6 +341,8 @@ export const useWorkflow = () => {
} }
} }
customApplyNodeChanges(changes, nodes);
onNodesChange(changes); onNodesChange(changes);
}; };
const handleEdgeChange = useCallback( const handleEdgeChange = useCallback(

View File

@@ -390,8 +390,7 @@ const RenderHttpTimeout = ({
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
return ( return (
<Box> <Flex alignItems={'center'} justifyContent={'space-between'}>
<Box mb={2} display={'flex'} justifyContent={'space-between'}>
<Box fontWeight={'medium'} color={'myGray.600'}> <Box fontWeight={'medium'} color={'myGray.600'}>
{t('common:core.module.Http timeout')} {t('common:core.module.Http timeout')}
</Box> </Box>
@@ -401,6 +400,7 @@ const RenderHttpTimeout = ({
defaultValue={timeout.value} defaultValue={timeout.value}
min={timeout.min} min={timeout.min}
max={timeout.max} max={timeout.max}
bg={'white'}
onBlur={() => setIsEditTimeout(false)} onBlur={() => setIsEditTimeout(false)}
onChange={(e) => { onChange={(e) => {
onChangeNode({ onChangeNode({
@@ -414,7 +414,7 @@ const RenderHttpTimeout = ({
}); });
}} }}
> >
<NumberInputField bg={'white'} px={3} borderRadius={'sm'} /> <NumberInputField autoFocus bg={'white'} px={3} borderRadius={'sm'} />
<NumberInputStepper> <NumberInputStepper>
<NumberIncrementStepper /> <NumberIncrementStepper />
<NumberDecrementStepper /> <NumberDecrementStepper />
@@ -422,14 +422,13 @@ const RenderHttpTimeout = ({
</NumberInput> </NumberInput>
) : ( ) : (
<Button <Button
variant={'ghost'} variant={'whiteBase'}
color={'myGray.600'} color={'myGray.600'}
onClick={() => setIsEditTimeout(true)} onClick={() => setIsEditTimeout(true)}
>{`${timeout?.value} s`}</Button> >{`${timeout?.value} s`}</Button>
)} )}
</Box> </Box>
</Box> </Flex>
</Box>
); );
}; };
const RenderForm = ({ const RenderForm = ({

View File

@@ -201,7 +201,7 @@ const NodeCard = (props: Props) => {
</Button> </Button>
</MyTooltip> </MyTooltip>
)} )}
{!!nodeTemplate?.diagram && ( {!!nodeTemplate?.diagram && !hasNewVersion && (
<MyTooltip <MyTooltip
label={ label={
<Image src={nodeTemplate?.diagram} w={'100%'} minH={['auto', '200px']} alt={''} /> <Image src={nodeTemplate?.diagram} w={'100%'} minH={['auto', '200px']} alt={''} />

View File

@@ -149,8 +149,8 @@ const ListItem = () => {
app.type === AppTypeEnum.folder app.type === AppTypeEnum.folder
? t('common:common.folder.Open folder') ? t('common:common.folder.Open folder')
: app.permission.hasWritePer : app.permission.hasWritePer
? appT('edit_app') ? t('app:edit_app')
: appT('go_to_chat') : t('app:go_to_chat')
} }
> >
<MyBox <MyBox

View File

@@ -138,7 +138,7 @@ const MyApps = () => {
flex={'1 0 0'} flex={'1 0 0'}
flexDirection={'column'} flexDirection={'column'}
h={'100%'} h={'100%'}
pr={folderDetail ? [4, 2] : [4, 10]} pr={folderDetail ? [3, 2] : [3, 10]}
pl={3} pl={3}
overflowY={'auto'} overflowY={'auto'}
overflowX={'hidden'} overflowX={'hidden'}

View File

@@ -143,9 +143,10 @@ const Info = ({ datasetId }: { datasetId: string }) => {
<Box flex={1}>{datasetDetail._id}</Box> <Box flex={1}>{datasetDetail._id}</Box>
</Flex> </Flex>
<Flex mt={8} w={'100%'} alignItems={'center'} flexWrap={'wrap'}> <Flex mt={8} w={'100%'} alignItems={'center'} flexWrap={'wrap'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}> <HStack flex={['0 0 90px', '0 0 160px']} w={0} spacing={1}>
{t('common:core.ai.model.Vector Model')} <FormLabel>{t('common:core.ai.model.Vector Model')}</FormLabel>
</FormLabel> <QuestionTip label={t('common:core.dataset.embedding model tip')} />
</HStack>
<Box flex={[1, '0 0 320px']}> <Box flex={[1, '0 0 320px']}>
<AIModelSelector <AIModelSelector
w={'100%'} w={'100%'}
@@ -177,9 +178,10 @@ const Info = ({ datasetId }: { datasetId: string }) => {
<Box flex={[1, '0 0 320px']}>{vectorModel.maxToken}</Box> <Box flex={[1, '0 0 320px']}>{vectorModel.maxToken}</Box>
</Flex> </Flex>
<Flex mt={6} alignItems={'center'} flexWrap={'wrap'}> <Flex mt={6} alignItems={'center'} flexWrap={'wrap'}>
<FormLabel flex={['0 0 90px', '0 0 160px']} w={0}> <HStack flex={['0 0 90px', '0 0 160px']} w={0} spacing={1}>
{t('common:core.ai.model.Dataset Agent Model')} <FormLabel>{t('common:core.ai.model.Dataset Agent Model')}</FormLabel>
</FormLabel> <QuestionTip label={t('dataset:file_model_function_tip')} />
</HStack>
<Box flex={[1, '0 0 320px']}> <Box flex={[1, '0 0 320px']}>
<AIModelSelector <AIModelSelector
w={'100%'} w={'100%'}

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { Box, Flex, Button, ModalFooter, ModalBody, Input } from '@chakra-ui/react'; import { Box, Flex, Button, ModalFooter, ModalBody, Input, HStack } from '@chakra-ui/react';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { compressImgFileAndUpload } from '@/web/common/file/controller'; import { compressImgFileAndUpload } from '@/web/common/file/controller';
@@ -19,6 +19,7 @@ import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'
import AIModelSelector from '@/components/Select/AIModelSelector'; import AIModelSelector from '@/components/Select/AIModelSelector';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
export type CreateDatasetType = export type CreateDatasetType =
| DatasetTypeEnum.dataset | DatasetTypeEnum.dataset
@@ -163,19 +164,18 @@ const CreateModal = ({
justify={'space-between'} justify={'space-between'}
flexDir={['column', 'row']} flexDir={['column', 'row']}
> >
<Flex <HStack
spacing={1}
alignItems={'center'} alignItems={'center'}
flex={['', '0 0 100px']} flex={['', '0 0 110px']}
fontSize={'sm'} fontSize={'sm'}
color={'myGray.900'} color={'myGray.900'}
fontWeight={500} fontWeight={500}
pb={['12px', '0']} pb={['12px', '0']}
> >
{t('common:core.ai.model.Vector Model')} <Box>{t('common:core.ai.model.Vector Model')}</Box>
<MyTooltip label={t('common:core.dataset.embedding model tip')}> <QuestionTip label={t('common:core.dataset.embedding model tip')} />
<MyIcon w={'16px'} h={'16px'} color={'myGray.500'} ml={'4px'} name="common/help" /> </HStack>
</MyTooltip>
</Flex>
<Box w={['100%', '300px']}> <Box w={['100%', '300px']}>
<AIModelSelector <AIModelSelector
w={['100%', '300px']} w={['100%', '300px']}
@@ -198,15 +198,17 @@ const CreateModal = ({
justify={'space-between'} justify={'space-between'}
flexDir={['column', 'row']} flexDir={['column', 'row']}
> >
<Box <HStack
flex={['', '0 0 100px']} spacing={1}
flex={['', '0 0 110px']}
fontSize={'sm'} fontSize={'sm'}
color={'myGray.900'} color={'myGray.900'}
fontWeight={500} fontWeight={500}
pb={['12px', '0']} pb={['12px', '0']}
> >
{t('common:core.ai.model.Dataset Agent Model')} <Box>{t('common:core.ai.model.Dataset Agent Model')}</Box>
</Box> <QuestionTip label={t('dataset:file_model_function_tip')} />
</HStack>
<Box w={['100%', '300px']}> <Box w={['100%', '300px']}>
<AIModelSelector <AIModelSelector
w={['100%', '300px']} w={['100%', '300px']}
@@ -224,7 +226,7 @@ const CreateModal = ({
)} )}
</ModalBody> </ModalBody>
<ModalFooter pt={'0px'} pb={'24px'}> <ModalFooter px={'36px'}>
<Button variant={'whiteBase'} mr={3} onClick={onClose}> <Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common:common.Close')} {t('common:common.Close')}
</Button> </Button>

View File

@@ -1,6 +1,5 @@
import React, { useMemo, useRef, useState } from 'react'; import React, { useMemo, useRef, useState } from 'react';
import { resumeInheritPer } from '@/web/core/dataset/api'; import { resumeInheritPer } from '@/web/core/dataset/api';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { Box, Flex, Grid, HStack } from '@chakra-ui/react'; import { Box, Flex, Grid, HStack } from '@chakra-ui/react';
import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants'; import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
import MyMenu from '@fastgpt/web/components/common/MyMenu'; import MyMenu from '@fastgpt/web/components/common/MyMenu';
@@ -39,6 +38,8 @@ import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import SideTag from './SideTag'; import SideTag from './SideTag';
const EditResourceModal = dynamic(() => import('@/components/common/Modal/EditResourceModal'));
function List() { function List() {
const { setLoading } = useSystemStore(); const { setLoading } = useSystemStore();
const { toast } = useToast(); const { toast } = useToast();
@@ -76,7 +77,7 @@ function List() {
} }
}); });
const { data: members = [], loading: isLoadMembers } = useRequest2(loadAndGetTeamMembers, { const { data: members = [] } = useRequest2(loadAndGetTeamMembers, {
manual: false manual: false
}); });
@@ -111,8 +112,6 @@ function List() {
errorToast: t('common:dataset.Export Dataset Limit Error') errorToast: t('common:dataset.Export Dataset Limit Error')
}); });
const EditResourceModal = dynamic(() => import('@/components/common/Modal/EditResourceModal'));
const DeleteTipsMap = useRef({ const DeleteTipsMap = useRef({
[DatasetTypeEnum.folder]: t('common:dataset.deleteFolderTips'), [DatasetTypeEnum.folder]: t('common:dataset.deleteFolderTips'),
[DatasetTypeEnum.dataset]: t('common:core.dataset.Delete Confirm'), [DatasetTypeEnum.dataset]: t('common:core.dataset.Delete Confirm'),
@@ -161,8 +160,7 @@ function List() {
gridGap={5} gridGap={5}
alignItems={'stretch'} alignItems={'stretch'}
> >
{!isLoadMembers && {formatDatasets.map((dataset, index) => {
formatDatasets.map((dataset, index) => {
const owner = members.find((v) => v.tmbId === dataset.tmbId); const owner = members.find((v) => v.tmbId === dataset.tmbId);
return ( return (
<MyTooltip <MyTooltip
@@ -171,8 +169,8 @@ function List() {
<Flex flexDirection={'column'} alignItems={'center'}> <Flex flexDirection={'column'} alignItems={'center'}>
<Box fontSize={'xs'} color={'myGray.500'}> <Box fontSize={'xs'} color={'myGray.500'}>
{dataset.type === DatasetTypeEnum.folder {dataset.type === DatasetTypeEnum.folder
? t('common.folder.Open folder') ? t('common:common.folder.Open folder')
: t('common.folder.open_dataset')} : t('common:common.folder.open_dataset')}
</Box> </Box>
</Flex> </Flex>
} }
@@ -290,9 +288,7 @@ function List() {
{isPc && ( {isPc && (
<HStack spacing={1} className="time"> <HStack spacing={1} className="time">
<MyIcon name={'history'} w={'0.85rem'} color={'myGray.400'} /> <MyIcon name={'history'} w={'0.85rem'} color={'myGray.400'} />
<Box color={'myGray.500'}> <Box color={'myGray.500'}>{formatTimeToChatTime(dataset.updateTime)}</Box>
{formatTimeToChatTime(dataset.updateTime)}
</Box>
</HStack> </HStack>
)} )}
{dataset.permission.hasWritePer && ( {dataset.permission.hasWritePer && (
@@ -415,7 +411,6 @@ function List() {
intro: data.intro, intro: data.intro,
avatar: data.avatar avatar: data.avatar
}); });
setEditedDataset(undefined);
}} }}
/> />
)} )}

View File

@@ -11,18 +11,15 @@ const SideTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps)
return { return {
[DatasetTypeEnum.dataset]: { [DatasetTypeEnum.dataset]: {
icon: 'core/dataset/commonDatasetOutline', icon: 'core/dataset/commonDatasetOutline',
label: t('dataset:common_dataset'), label: t('dataset:common_dataset')
collectionLabel: 'common.File'
}, },
[DatasetTypeEnum.websiteDataset]: { [DatasetTypeEnum.websiteDataset]: {
icon: 'core/dataset/websiteDatasetOutline', icon: 'core/dataset/websiteDatasetOutline',
label: t('dataset:website_dataset'), label: t('dataset:website_dataset')
collectionLabel: 'common.Website'
}, },
[DatasetTypeEnum.externalFile]: { [DatasetTypeEnum.externalFile]: {
icon: 'core/dataset/externalDatasetOutline', icon: 'core/dataset/externalDatasetOutline',
label: t('dataset:external_file'), label: t('dataset:external_file')
collectionLabel: 'common.File'
} }
}; };
}, [t]); }, [t]);
@@ -31,8 +28,6 @@ const SideTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps)
return ( return (
<Flex <Flex
bg={'myGray.100'} bg={'myGray.100'}
borderWidth={'1px'}
borderColor={'myGray.200'}
py={'3px'} py={'3px'}
pl={'8px'} pl={'8px'}
pr={'12px'} pr={'12px'}
@@ -43,7 +38,6 @@ const SideTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps)
> >
<MyIcon name={item.icon as any} w={'0.8rem'} color={'myGray.400'} /> <MyIcon name={item.icon as any} w={'0.8rem'} color={'myGray.400'} />
<Box fontSize={'mini'} ml={1}> <Box fontSize={'mini'} ml={1}>
{/* @ts-ignore */}
{item.label} {item.label}
</Box> </Box>
</Flex> </Flex>

View File

@@ -12,7 +12,7 @@ import { startMongoWatch } from './common/system/volumnMongoWatch';
import { startTrainingQueue } from './core/dataset/training/utils'; import { startTrainingQueue } from './core/dataset/training/utils';
import { systemStartCb } from '@fastgpt/service/common/system/tools'; import { systemStartCb } from '@fastgpt/service/common/system/tools';
import { addLog } from '@fastgpt/service/common/system/log'; import { addLog } from '@fastgpt/service/common/system/log';
import { getSystemPluginCb } from './core/app/plugin'; import { getSystemPluginCb, getSystemPlugins } from './core/app/plugin';
/** /**
* This function is equivalent to the entry to the service * This function is equivalent to the entry to the service
@@ -32,7 +32,13 @@ export function connectToDatabase() {
systemStartCb(); systemStartCb();
//init system configinit vector databaseinit root user //init system configinit vector databaseinit root user
await Promise.all([getInitConfig(), getSystemPluginCb(), initVectorStore(), initRootUser()]); await Promise.all([
getInitConfig(),
getSystemPluginCb(),
getSystemPlugins(),
initVectorStore(),
initRootUser()
]);
startMongoWatch(); startMongoWatch();
// cron // cron