mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-02 12:48:30 +00:00
V4.6.9-first commit (#899)
* perf: insert mongo dataset data session * perf: dataset data index * remove delay * rename bill schema * rename bill record * perf: bill table * perf: prompt * perf: sub plan * change the usage count * feat: usage bill * publish usages * doc * 新增团队聊天功能 (#20) * perf: doc * feat 添加标签部分 feat 信息团队标签配置 feat 新增团队同步管理 feat team分享页面 feat 完成team分享页面 feat 实现模糊搜索 style 格式化 fix 修复迷糊匹配 style 样式修改 fix 团队标签功能修复 * fix 修复鉴权功能 * merge 合并代码 * fix 修复引用错误 * fix 修复pr问题 * fix 修复ts格式问题 --------- Co-authored-by: archer <545436317@qq.com> Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> * update extra plan * fix: ts * format * perf: bill field * feat: standard plan * fix: ts * feat 个人账号页面修改 (#22) * feat 添加标签部分 feat 信息团队标签配置 feat 新增团队同步管理 feat team分享页面 feat 完成team分享页面 feat 实现模糊搜索 style 格式化 fix 修复迷糊匹配 style 样式修改 fix 团队标签功能修复 * fix 修复鉴权功能 * merge 合并代码 * fix 修复引用错误 * fix 修复pr问题 * fix 修复ts格式问题 * feat 修改个人账号页 --------- Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> * sub plan page (#23) * fix chunk index; error page text * feat: dataset process Integral prediction * feat: stand plan field * feat: sub plan limit * perf: index * query extension * perf: share link push app name * perf: plan point unit * perf: get sub plan * perf: account page * feat 新增套餐详情弹窗代码 (#24) * merge 合并代码 * fix 新增套餐详情弹框 * fix 修复pr问题 * feat: change http node input to prompt editor (#21) * feat: change http node input to prompt editor * fix * split PromptEditor to HttpInput * Team plans (#25) * perf: pay check * perf: team plan test * plan limit check * replace sensitive text * perf: fix some null * collection null check * perf: plans modal * perf: http module * pacakge (#26) * individuation page and pay modal amount (#27) * feat: individuation page * team chat config * pay modal * plan count and replace invalid chars (#29) * fix: user oneapi * fix: training queue * fix: qa queue * perf: remove space chars * replace invalid chars * change httpinput dropdown menu (#28) * perf: http * reseet free plan * perf: plan code to packages * remove llm config to package * perf: code * perf: faq * fix: get team plan --------- Co-authored-by: yst <77910600+yu-and-liu@users.noreply.github.com> Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
@@ -27,6 +27,8 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import SelectAiModel from '@/components/Select/SelectAiModel';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
|
||||
export type DatasetParamsProps = {
|
||||
searchMode: `${DatasetSearchModeEnum}`;
|
||||
@@ -61,6 +63,8 @@ const DatasetParamsModal = ({
|
||||
}: DatasetParamsProps & { onClose: () => void; onSuccess: (e: DatasetParamsProps) => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { teamPlanStatus } = useUserStore();
|
||||
const { reRankModelList, llmModelList } = useSystemStore();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const [currentTabType, setCurrentTabType] = useState(SearchSettingTabEnum.searchMode);
|
||||
@@ -71,7 +75,7 @@ const DatasetParamsModal = ({
|
||||
limit,
|
||||
similarity,
|
||||
searchMode,
|
||||
usingReRank,
|
||||
usingReRank: !!usingReRank && !!teamPlanStatus?.standardConstants?.permissionReRank,
|
||||
datasetSearchUsingExtensionQuery,
|
||||
datasetSearchExtensionModel: datasetSearchExtensionModel ?? llmModelList[0]?.model,
|
||||
datasetSearchExtensionBg
|
||||
@@ -105,6 +109,10 @@ const DatasetParamsModal = ({
|
||||
return true;
|
||||
}, [getValues, similarity]);
|
||||
|
||||
const showReRank = useMemo(() => {
|
||||
return usingReRank !== undefined && reRankModelList.length > 0;
|
||||
}, [reRankModelList.length, usingReRank]);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen={true}
|
||||
@@ -148,7 +156,7 @@ const DatasetParamsModal = ({
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
{usingReRank !== undefined && reRankModelList.length > 0 && (
|
||||
{showReRank && (
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
@@ -168,6 +176,15 @@ const DatasetParamsModal = ({
|
||||
}
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
if (
|
||||
teamPlanStatus?.standardConstants &&
|
||||
!teamPlanStatus?.standardConstants?.permissionReRank
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('support.team.limit.No permission rerank')
|
||||
});
|
||||
}
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
@@ -273,7 +290,7 @@ const DatasetParamsModal = ({
|
||||
{currentTabType === SearchSettingTabEnum.queryExtension && (
|
||||
<Box>
|
||||
<Box fontSize={'xs'} color={'myGray.500'}>
|
||||
{t('core.module.template.Query extension intro')}
|
||||
{t('core.dataset.Query extension intro')}
|
||||
</Box>
|
||||
<Flex mt={3} alignItems={'center'}>
|
||||
<Box flex={'1 0 0'}>{t('core.dataset.search.Using query extension')}</Box>
|
||||
|
@@ -0,0 +1,185 @@
|
||||
import React from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { ModalBody, Button, ModalFooter, useDisclosure, Textarea, Box } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { onChangeNode } from '../../../FlowProvider';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import yaml from 'js-yaml';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
||||
const methodMap: { [K in RequestMethod]: string } = {
|
||||
get: 'GET',
|
||||
post: 'POST',
|
||||
put: 'PUT',
|
||||
delete: 'DELETE',
|
||||
patch: 'PATCH'
|
||||
};
|
||||
|
||||
const OpenApiImportModal = ({
|
||||
children,
|
||||
moduleId,
|
||||
inputs
|
||||
}: {
|
||||
children: React.ReactElement;
|
||||
moduleId: string;
|
||||
inputs: FlowNodeInputItemType[];
|
||||
}) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { t } = useTranslation();
|
||||
const { register, handleSubmit } = useForm({
|
||||
defaultValues: {
|
||||
openapiContent: ''
|
||||
}
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleFileProcessing = async (content: string) => {
|
||||
try {
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(content);
|
||||
} catch (jsonError) {
|
||||
try {
|
||||
data = yaml.load(content, { schema: yaml.FAILSAFE_SCHEMA });
|
||||
} catch (yamlError) {
|
||||
console.error(yamlError);
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
const firstPathName = Object.keys(data.paths)[0];
|
||||
const firstPathData = data.paths[firstPathName];
|
||||
const firstRequestMethod = Object.keys(firstPathData)[0];
|
||||
const firstRequestMethodData = firstPathData[firstRequestMethod];
|
||||
const firstRequestParameters = firstRequestMethodData.parameters || [];
|
||||
|
||||
const pathParams = [];
|
||||
const headerParams = [];
|
||||
for (const parameter of firstRequestParameters) {
|
||||
if (parameter.in === 'path') {
|
||||
pathParams.push({
|
||||
key: parameter.name,
|
||||
type: parameter.schema.type
|
||||
});
|
||||
} else {
|
||||
headerParams.push({
|
||||
key: parameter.name,
|
||||
type: parameter.schema.type
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const requestBodySchema =
|
||||
firstRequestMethodData.requestBody?.content?.['application/json']?.schema;
|
||||
let requestBodyValue = '';
|
||||
if (requestBodySchema) {
|
||||
requestBodyValue = JSON.stringify(requestBodySchema, null, 2);
|
||||
}
|
||||
|
||||
const requestUrl = inputs.find((item) => item.key === ModuleInputKeyEnum.httpReqUrl);
|
||||
const requestMethod = inputs.find((item) => item.key === ModuleInputKeyEnum.httpMethod);
|
||||
const params = inputs.find((item) => item.key === ModuleInputKeyEnum.httpParams);
|
||||
const headers = inputs.find((item) => item.key === ModuleInputKeyEnum.httpHeaders);
|
||||
const jsonBody = inputs.find((item) => item.key === ModuleInputKeyEnum.httpJsonBody);
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.httpReqUrl,
|
||||
value: {
|
||||
...requestUrl,
|
||||
value: firstPathName
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.httpMethod,
|
||||
value: {
|
||||
...requestMethod,
|
||||
value: methodMap[firstRequestMethod.toLowerCase() as RequestMethod] || 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.httpParams,
|
||||
value: {
|
||||
...params,
|
||||
value: pathParams
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.httpHeaders,
|
||||
value: {
|
||||
...headers,
|
||||
value: headerParams
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.httpJsonBody,
|
||||
value: {
|
||||
...jsonBody,
|
||||
value: requestBodyValue
|
||||
}
|
||||
});
|
||||
|
||||
onClose();
|
||||
|
||||
toast({
|
||||
title: t('common.Import success'),
|
||||
status: 'success'
|
||||
});
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: t('common.Import failed'),
|
||||
description: error.message,
|
||||
status: 'error'
|
||||
});
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{children && <Box onClick={onOpen}>{children}</Box>}
|
||||
<MyModal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
iconSrc="modal/edit"
|
||||
title={t('common.Import')}
|
||||
m={'auto'}
|
||||
w={500}
|
||||
>
|
||||
<ModalBody>
|
||||
<Textarea
|
||||
height={400}
|
||||
maxH={500}
|
||||
mt={2}
|
||||
{...register('openapiContent')}
|
||||
placeholder={t('core.module.http.OpenAPI import placeholder')}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={handleSubmit((data) => handleFileProcessing(data.openapiContent))}>
|
||||
{t('common.Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(OpenApiImportModal);
|
@@ -1,11 +1,11 @@
|
||||
import React, { useCallback, useMemo, useState, useTransition } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState, useTransition } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../render/NodeCard';
|
||||
import NodeCard from '../../render/NodeCard';
|
||||
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
import Divider from '../../modules/Divider';
|
||||
import Container from '../../modules/Container';
|
||||
import RenderInput from '../../render/RenderInput';
|
||||
import RenderOutput from '../../render/RenderOutput';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
@@ -16,17 +16,17 @@ import {
|
||||
Tr,
|
||||
Th,
|
||||
Td,
|
||||
TableContainer
|
||||
TableContainer,
|
||||
Button
|
||||
} from '@chakra-ui/react';
|
||||
import MySelect from '@/components/Select';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../FlowProvider';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import JSONEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
||||
@@ -36,6 +36,9 @@ import {
|
||||
splitGuideModule
|
||||
} from '@fastgpt/global/core/module/utils';
|
||||
import { EditorVariablePickerType } from '@fastgpt/web/components/common/Textarea/PromptEditor/type';
|
||||
import HttpInput from '@fastgpt/web/components/common/Input/HttpInput';
|
||||
import dynamic from 'next/dynamic';
|
||||
const OpenApiImportModal = dynamic(() => import('./OpenApiImportModal'));
|
||||
|
||||
enum TabEnum {
|
||||
params = 'params',
|
||||
@@ -133,11 +136,18 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={2}>{t('core.module.Http request settings')}</Box>
|
||||
<Box mb={2} display={'flex'} justifyContent={'space-between'}>
|
||||
<span>{t('core.module.Http request settings')}</span>
|
||||
<span>
|
||||
<OpenApiImportModal moduleId={moduleId} inputs={inputs}>
|
||||
<Button variant={'link'}>{t('core.module.http.OpenAPI import')}</Button>
|
||||
</OpenApiImportModal>
|
||||
</span>
|
||||
</Box>
|
||||
<Flex alignItems={'center'} className="nodrag">
|
||||
<MySelect
|
||||
h={'34px'}
|
||||
w={'80px'}
|
||||
w={'88px'}
|
||||
bg={'myGray.50'}
|
||||
width={'100%'}
|
||||
value={requestMethods?.value}
|
||||
@@ -149,6 +159,18 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
{
|
||||
label: 'POST',
|
||||
value: 'POST'
|
||||
},
|
||||
{
|
||||
label: 'PUT',
|
||||
value: 'PUT'
|
||||
},
|
||||
{
|
||||
label: 'DELETE',
|
||||
value: 'DELETE'
|
||||
},
|
||||
{
|
||||
label: 'PATCH',
|
||||
value: 'PATCH'
|
||||
}
|
||||
]}
|
||||
onchange={(e) => {
|
||||
@@ -178,10 +200,6 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
);
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
key: '',
|
||||
value: ''
|
||||
};
|
||||
function RenderHttpProps({
|
||||
moduleId,
|
||||
inputs
|
||||
@@ -261,7 +279,7 @@ function RenderHttpProps({
|
||||
<Tabs
|
||||
list={[
|
||||
{ label: <RenderPropsItem text="Params" num={paramsLength} />, id: TabEnum.params },
|
||||
...(requestMethods === 'POST'
|
||||
...(!['GET', 'DELETE'].includes(requestMethods)
|
||||
? [
|
||||
{
|
||||
label: (
|
||||
@@ -303,36 +321,75 @@ const RenderForm = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const [_, startSts] = useTransition();
|
||||
const { register, reset, handleSubmit } = useForm({
|
||||
defaultValues: defaultForm
|
||||
});
|
||||
|
||||
const list = useMemo(() => (input.value || []) as PropsArrType[], [input.value]);
|
||||
const [list, setList] = useState<PropsArrType[]>(input.value || []);
|
||||
const [updateTrigger, setUpdateTrigger] = useState(false);
|
||||
const [shouldUpdateNode, setShouldUpdateNode] = useState(false);
|
||||
|
||||
const addNewProps = useCallback(
|
||||
({ key, value }: { key: string; value: string }) => {
|
||||
const checkExist = list.find((item) => item.key === key);
|
||||
if (checkExist) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('core.module.http.Key already exists')
|
||||
});
|
||||
}
|
||||
if (!key) return;
|
||||
const leftVariables = useMemo(() => {
|
||||
return variables.filter((variable) => {
|
||||
const existVariables = list.map((item) => item.key);
|
||||
return !existVariables.includes(variable.key);
|
||||
});
|
||||
}, [list, variables]);
|
||||
|
||||
useEffect(() => {
|
||||
setList(input.value || []);
|
||||
}, [input.value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldUpdateNode) {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: input.key,
|
||||
value: {
|
||||
...input,
|
||||
value: [...list, { key, type: 'string', value }]
|
||||
value: list
|
||||
}
|
||||
});
|
||||
reset(defaultForm);
|
||||
},
|
||||
[input, list, moduleId, reset, t, toast]
|
||||
);
|
||||
setShouldUpdateNode(false);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [list]);
|
||||
|
||||
const handleKeyChange = (index: number, newKey: string) => {
|
||||
setList((prevList) => {
|
||||
if (!newKey) {
|
||||
setUpdateTrigger((prev) => !prev);
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: t('core.module.http.Key cannot be empty')
|
||||
});
|
||||
return prevList;
|
||||
}
|
||||
const checkExist = prevList.find((item, i) => i !== index && item.key == newKey);
|
||||
if (checkExist) {
|
||||
setUpdateTrigger((prev) => !prev);
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: t('core.module.http.Key already exists')
|
||||
});
|
||||
return prevList;
|
||||
}
|
||||
return prevList.map((item, i) => (i === index ? { ...item, key: newKey } : item));
|
||||
});
|
||||
setShouldUpdateNode(true);
|
||||
};
|
||||
|
||||
const handleAddNewProps = (key: string, value: string = '') => {
|
||||
const checkExist = list.find((item) => item.key === key);
|
||||
if (checkExist) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('core.module.http.Key already exists')
|
||||
});
|
||||
}
|
||||
if (!key) return;
|
||||
|
||||
setList((prevList) => [...prevList, { key, type: 'string', value }]);
|
||||
setShouldUpdateNode(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
@@ -347,103 +404,69 @@ const RenderForm = ({
|
||||
{list.map((item, index) => (
|
||||
<Tr key={`${input.key}${index}`}>
|
||||
<Td p={0} w={'150px'}>
|
||||
<Input
|
||||
w={'150px'}
|
||||
defaultValue={item.key}
|
||||
variant={'unstyled'}
|
||||
paddingLeft={2}
|
||||
placeholder={t('core.module.http.Props name')}
|
||||
onBlur={(e) => {
|
||||
const val = e.target.value;
|
||||
if (!val) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('core.module.http.Key cannot be empty')
|
||||
});
|
||||
}
|
||||
|
||||
const checkExist = list.find((item, i) => i !== index && item.key == val);
|
||||
if (checkExist) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('core.module.http.Key already exists')
|
||||
});
|
||||
}
|
||||
|
||||
startSts(() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: input.key,
|
||||
value: {
|
||||
...input,
|
||||
value: list.map((item, i) => (i === index ? { ...item, key: val } : item))
|
||||
}
|
||||
});
|
||||
});
|
||||
<HttpInput
|
||||
hasVariablePlugin={false}
|
||||
hasDropDownPlugin={true}
|
||||
setDropdownValue={(value) => {
|
||||
handleKeyChange(index, value);
|
||||
setUpdateTrigger((prev) => !prev);
|
||||
}}
|
||||
placeholder={t('core.module.http.Props name')}
|
||||
value={item.key}
|
||||
variables={leftVariables}
|
||||
onBlur={(val) => {
|
||||
handleKeyChange(index, val);
|
||||
}}
|
||||
updateTrigger={updateTrigger}
|
||||
/>
|
||||
</Td>
|
||||
<Td p={0} display={'flex'} alignItems={'center'}>
|
||||
<Input
|
||||
flex={'1 0 0'}
|
||||
w={'150px'}
|
||||
defaultValue={item.value}
|
||||
variant={'unstyled'}
|
||||
paddingLeft={2}
|
||||
placeholder={t('core.module.http.Props value')}
|
||||
onBlur={(e) => {
|
||||
const val = e.target.value;
|
||||
startSts(() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: input.key,
|
||||
value: {
|
||||
...input,
|
||||
value: list.map((item, i) =>
|
||||
i === index ? { ...item, value: val } : item
|
||||
)
|
||||
}
|
||||
});
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<MyIcon
|
||||
name={'delete'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'red.600' }}
|
||||
w={'14px'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: input.key,
|
||||
value: {
|
||||
...input,
|
||||
value: list.filter((val) => val.key !== item.key)
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Td p={0}>
|
||||
<Box display={'flex'} alignItems={'center'}>
|
||||
<HttpInput
|
||||
placeholder={t('core.module.http.Props value')}
|
||||
value={item.value}
|
||||
variables={variables}
|
||||
onBlur={(val) => {
|
||||
setList((prevList) =>
|
||||
prevList.map((item, i) => (i === index ? { ...item, value: val } : item))
|
||||
);
|
||||
setShouldUpdateNode(true);
|
||||
}}
|
||||
/>
|
||||
<MyIcon
|
||||
name={'delete'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'red.600' }}
|
||||
w={'14px'}
|
||||
onClick={() => {
|
||||
setList((prevlist) => prevlist.filter((val) => val.key !== item.key));
|
||||
setShouldUpdateNode(true);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
<Tr>
|
||||
<Td p={0} w={'150px'}>
|
||||
<Input
|
||||
w={'150px'}
|
||||
variant={'unstyled'}
|
||||
paddingLeft={2}
|
||||
<HttpInput
|
||||
hasDropDownPlugin={true}
|
||||
setDropdownValue={(val) => {
|
||||
handleAddNewProps(val);
|
||||
}}
|
||||
placeholder={t('core.module.http.Add props')}
|
||||
{...register('key', {
|
||||
onBlur: handleSubmit(addNewProps)
|
||||
})}
|
||||
value={''}
|
||||
h={40}
|
||||
variables={leftVariables}
|
||||
onBlur={(val) => {
|
||||
handleAddNewProps(val);
|
||||
}}
|
||||
/>
|
||||
</Td>
|
||||
<Td p={0}>
|
||||
<Input variant={'unstyled'} paddingLeft={2} {...register('value')} />
|
||||
<Box display={'flex'} alignItems={'center'}>
|
||||
<HttpInput />
|
||||
</Box>
|
||||
</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
@@ -460,7 +483,9 @@ const RenderJson = ({
|
||||
input: FlowNodeInputItemType;
|
||||
variables: EditorVariablePickerType[];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [_, startSts] = useTransition();
|
||||
|
||||
return (
|
||||
<Box mt={1}>
|
||||
<JSONEditor
|
||||
@@ -468,6 +493,7 @@ const RenderJson = ({
|
||||
height={200}
|
||||
resize
|
||||
value={input.value}
|
||||
placeholder={t('core.module.template.http body placeholder')}
|
||||
onChange={(e) => {
|
||||
startSts(() => {
|
||||
onChangeNode({
|
||||
@@ -488,7 +514,7 @@ const RenderJson = ({
|
||||
};
|
||||
const RenderPropsItem = ({ text, num }: { text: string; num: number }) => {
|
||||
return (
|
||||
<Flex alignItems={'center'} fontSize={'xs'} transform={'scale(0.8)'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box>{text}</Box>
|
||||
{num > 0 && (
|
||||
<Box ml={1} borderRadius={'50%'} bg={'myGray.200'} px={2} py={'1px'}>
|
||||
@@ -500,6 +526,7 @@ const RenderPropsItem = ({ text, num }: { text: string; num: number }) => {
|
||||
};
|
||||
|
||||
const NodeHttp = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
|
||||
const CustomComponents = useMemo(
|
||||
@@ -511,12 +538,12 @@ const NodeHttp = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
<>
|
||||
<RenderHttpProps moduleId={moduleId} inputs={inputs} />
|
||||
<Box mt={2} transform={'translateY(10px)'}>
|
||||
外部参数输入
|
||||
{t('core.module.Variable import')}
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}),
|
||||
[inputs, moduleId]
|
||||
[inputs, moduleId, t]
|
||||
);
|
||||
|
||||
return (
|
@@ -93,47 +93,38 @@ const FieldEditModal = ({
|
||||
const { register, getValues, setValue, handleSubmit, watch } = useForm<EditNodeFieldType>({
|
||||
defaultValues: defaultField
|
||||
});
|
||||
const inputType = watch('inputType');
|
||||
const outputType = watch('outputType');
|
||||
const valueType = watch('valueType');
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const showDataTypeSelect = useMemo(() => {
|
||||
if (!editField.dataType) return false;
|
||||
const inputType = getValues('inputType');
|
||||
const outputType = getValues('outputType');
|
||||
|
||||
if (inputType === FlowNodeInputTypeEnum.target) return true;
|
||||
|
||||
if (outputType === FlowNodeOutputTypeEnum.source) return true;
|
||||
|
||||
return false;
|
||||
}, [editField.dataType, getValues, refresh]);
|
||||
}, [editField.dataType, inputType, outputType]);
|
||||
|
||||
const showRequired = useMemo(() => {
|
||||
const inputType = getValues('inputType');
|
||||
const valueType = getValues('valueType');
|
||||
if (inputType === FlowNodeInputTypeEnum.addInputParam) return false;
|
||||
|
||||
return editField.required;
|
||||
}, [editField.required, getValues, refresh]);
|
||||
}, [editField.required, inputType]);
|
||||
|
||||
const showNameInput = useMemo(() => {
|
||||
const inputType = getValues('inputType');
|
||||
|
||||
return editField.name;
|
||||
}, [editField.name, getValues, refresh]);
|
||||
}, [editField.name]);
|
||||
|
||||
const showKeyInput = useMemo(() => {
|
||||
const inputType = getValues('inputType');
|
||||
const valueType = getValues('valueType');
|
||||
if (inputType === FlowNodeInputTypeEnum.addInputParam) return false;
|
||||
|
||||
return editField.key;
|
||||
}, [editField.key, getValues, refresh]);
|
||||
}, [editField.key, inputType]);
|
||||
|
||||
const showDescriptionInput = useMemo(() => {
|
||||
const inputType = getValues('inputType');
|
||||
|
||||
return editField.description;
|
||||
}, [editField.description, getValues, refresh]);
|
||||
}, [editField.description]);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
@@ -209,7 +200,18 @@ const FieldEditModal = ({
|
||||
{showKeyInput && (
|
||||
<Flex mb={5} alignItems={'center'}>
|
||||
<Box flex={'0 0 70px'}>{t('core.module.Field key')}</Box>
|
||||
<Input placeholder="appointment/sql" {...register('key', { required: true })} />
|
||||
<Input
|
||||
placeholder="appointment/sql"
|
||||
{...register('key', {
|
||||
required: true,
|
||||
onChange: (e) => {
|
||||
const value = e.target.value;
|
||||
if (!showNameInput) {
|
||||
setValue('label', value);
|
||||
}
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{showDescriptionInput && (
|
||||
|
@@ -46,11 +46,7 @@ const RenderList: {
|
||||
Component: dynamic(() => import('./templates/AiSetting'))
|
||||
},
|
||||
{
|
||||
types: [
|
||||
FlowNodeInputTypeEnum.selectChatModel,
|
||||
FlowNodeInputTypeEnum.selectCQModel,
|
||||
FlowNodeInputTypeEnum.selectExtractModel
|
||||
],
|
||||
types: [FlowNodeInputTypeEnum.selectLLMModel],
|
||||
Component: dynamic(() => import('./templates/SelectAiModel'))
|
||||
},
|
||||
{
|
||||
|
@@ -55,7 +55,7 @@ const JsonEditor = ({ inputs = [], item, moduleId }: RenderInputProps) => {
|
||||
return (
|
||||
<JSONEditor
|
||||
bg={'myGray.50'}
|
||||
placeholder={t(item.placeholder || '')}
|
||||
placeholder={item.placeholder}
|
||||
resize
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
|
@@ -33,7 +33,7 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
||||
[FlowNodeTypeEnum.pluginInput]: dynamic(() => import('./components/nodes/NodePluginInput')),
|
||||
[FlowNodeTypeEnum.pluginOutput]: dynamic(() => import('./components/nodes/NodePluginOutput')),
|
||||
[FlowNodeTypeEnum.pluginModule]: NodeSimple,
|
||||
[FlowNodeTypeEnum.cfr]: NodeSimple
|
||||
[FlowNodeTypeEnum.queryExtension]: NodeSimple
|
||||
};
|
||||
const edgeTypes = {
|
||||
[EDGE_TYPE]: ButtonEdge
|
||||
|
Reference in New Issue
Block a user