mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-29 09:44:47 +00:00
4.8 test fix (#1386)
* fix: boolean of if else input * fix laf node * fix laf bind * fix laf input type * fix if else check * fix * fix
This commit is contained in:
@@ -22,20 +22,55 @@ type Response = DispatchNodeResultType<{
|
|||||||
[NodeOutputKeyEnum.ifElseResult]: string;
|
[NodeOutputKeyEnum.ifElseResult]: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
function isEmpty(value: any) {
|
||||||
|
return (
|
||||||
|
// 检查未定义或null值
|
||||||
|
value === undefined ||
|
||||||
|
value === null ||
|
||||||
|
// 检查空字符串
|
||||||
|
(typeof value === 'string' && value.trim() === '') ||
|
||||||
|
// 检查NaN
|
||||||
|
(typeof value === 'number' && isNaN(value)) ||
|
||||||
|
// 检查空数组
|
||||||
|
(Array.isArray(value) && value.length === 0) ||
|
||||||
|
// 检查空对象
|
||||||
|
(typeof value === 'object' && Object.keys(value).length === 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInclude(value: any, target: any) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((item: any) => String(item)).includes(target);
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
return value.includes(target);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
|
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
|
||||||
const operations = {
|
const operations = {
|
||||||
[VariableConditionEnum.isEmpty]: () => !variableValue,
|
[VariableConditionEnum.isEmpty]: () => isEmpty(variableValue),
|
||||||
[VariableConditionEnum.isNotEmpty]: () => !!variableValue,
|
[VariableConditionEnum.isNotEmpty]: () => !isEmpty(variableValue),
|
||||||
[VariableConditionEnum.equalTo]: () => variableValue === value,
|
|
||||||
[VariableConditionEnum.notEqual]: () => variableValue !== value,
|
[VariableConditionEnum.equalTo]: () => String(variableValue) === value,
|
||||||
|
[VariableConditionEnum.notEqual]: () => String(variableValue) !== value,
|
||||||
|
|
||||||
|
// number
|
||||||
[VariableConditionEnum.greaterThan]: () => Number(variableValue) > Number(value),
|
[VariableConditionEnum.greaterThan]: () => Number(variableValue) > Number(value),
|
||||||
[VariableConditionEnum.lessThan]: () => Number(variableValue) < Number(value),
|
[VariableConditionEnum.lessThan]: () => Number(variableValue) < Number(value),
|
||||||
[VariableConditionEnum.greaterThanOrEqualTo]: () => Number(variableValue) >= Number(value),
|
[VariableConditionEnum.greaterThanOrEqualTo]: () => Number(variableValue) >= Number(value),
|
||||||
[VariableConditionEnum.lessThanOrEqualTo]: () => Number(variableValue) <= Number(value),
|
[VariableConditionEnum.lessThanOrEqualTo]: () => Number(variableValue) <= Number(value),
|
||||||
[VariableConditionEnum.include]: () => variableValue?.includes(value),
|
|
||||||
[VariableConditionEnum.notInclude]: () => !variableValue?.includes(value),
|
// array or string
|
||||||
|
[VariableConditionEnum.include]: () => isInclude(variableValue, value),
|
||||||
|
[VariableConditionEnum.notInclude]: () => !isInclude(variableValue, value),
|
||||||
|
|
||||||
|
// string
|
||||||
[VariableConditionEnum.startWith]: () => variableValue?.startsWith(value),
|
[VariableConditionEnum.startWith]: () => variableValue?.startsWith(value),
|
||||||
[VariableConditionEnum.endWith]: () => variableValue?.endsWith(value),
|
[VariableConditionEnum.endWith]: () => variableValue?.endsWith(value),
|
||||||
|
|
||||||
|
// array
|
||||||
[VariableConditionEnum.lengthEqualTo]: () => variableValue?.length === Number(value),
|
[VariableConditionEnum.lengthEqualTo]: () => variableValue?.length === Number(value),
|
||||||
[VariableConditionEnum.lengthNotEqualTo]: () => variableValue?.length !== Number(value),
|
[VariableConditionEnum.lengthNotEqualTo]: () => variableValue?.length !== Number(value),
|
||||||
[VariableConditionEnum.lengthGreaterThan]: () => variableValue?.length > Number(value),
|
[VariableConditionEnum.lengthGreaterThan]: () => variableValue?.length > Number(value),
|
||||||
|
@@ -17,6 +17,7 @@ import {
|
|||||||
arrayConditionList,
|
arrayConditionList,
|
||||||
booleanConditionList,
|
booleanConditionList,
|
||||||
numberConditionList,
|
numberConditionList,
|
||||||
|
objectConditionList,
|
||||||
stringConditionList
|
stringConditionList
|
||||||
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
@@ -133,7 +134,8 @@ const ListItem = ({
|
|||||||
if (index === i) {
|
if (index === i) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
variable: e
|
variable: e,
|
||||||
|
condition: undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
@@ -334,10 +336,10 @@ const ConditionSelect = ({
|
|||||||
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
|
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
|
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayObject ||
|
valueType === WorkflowIOValueTypeEnum.arrayObject ||
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayString ||
|
valueType === WorkflowIOValueTypeEnum.arrayString
|
||||||
valueType === WorkflowIOValueTypeEnum.object
|
|
||||||
)
|
)
|
||||||
return arrayConditionList;
|
return arrayConditionList;
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.object) return objectConditionList;
|
||||||
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
|
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
|
||||||
|
|
||||||
@@ -395,6 +397,10 @@ const ConditionValueInput = ({
|
|||||||
onchange={onChange}
|
onchange={onChange}
|
||||||
value={value}
|
value={value}
|
||||||
placeholder={'选择值'}
|
placeholder={'选择值'}
|
||||||
|
isDisabled={
|
||||||
|
condition === VariableConditionEnum.isEmpty ||
|
||||||
|
condition === VariableConditionEnum.isNotEmpty
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -33,6 +33,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '../../context';
|
import { WorkflowContext } from '../../context';
|
||||||
|
import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||||
|
|
||||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||||
|
|
||||||
@@ -47,20 +48,11 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
|
|
||||||
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
||||||
|
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo, initUserInfo } = useUserStore();
|
||||||
|
|
||||||
const token = userInfo?.team.lafAccount?.token;
|
const token = userInfo?.team.lafAccount?.token;
|
||||||
const appid = userInfo?.team.lafAccount?.appid;
|
const appid = userInfo?.team.lafAccount?.appid;
|
||||||
|
|
||||||
// not config laf
|
|
||||||
if (!token || !appid) {
|
|
||||||
return (
|
|
||||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
|
||||||
<ConfigLaf />
|
|
||||||
</NodeCard>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: lafData,
|
data: lafData,
|
||||||
isLoading: isLoadingFunctions,
|
isLoading: isLoadingFunctions,
|
||||||
@@ -69,24 +61,32 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
['getLafFunctionList'],
|
['getLafFunctionList'],
|
||||||
async () => {
|
async () => {
|
||||||
// load laf app detail
|
// load laf app detail
|
||||||
const appDetail = await getLafAppDetail(appid);
|
try {
|
||||||
|
const appDetail = await getLafAppDetail(appid || '');
|
||||||
|
// load laf app functions
|
||||||
|
const schemaUrl = `https://${appDetail?.domain.domain}/_/api-docs?token=${appDetail?.openapi_token}`;
|
||||||
|
|
||||||
// load laf app functions
|
const schema = await getApiSchemaByUrl(schemaUrl);
|
||||||
const schemaUrl = `https://${appDetail?.domain.domain}/_/api-docs?token=${appDetail?.openapi_token}`;
|
const openApiSchema = await str2OpenApiSchema(JSON.stringify(schema));
|
||||||
|
const filterPostSchema = openApiSchema.pathData.filter((item) => item.method === 'post');
|
||||||
|
|
||||||
const schema = await getApiSchemaByUrl(schemaUrl);
|
return {
|
||||||
const openApiSchema = await str2OpenApiSchema(JSON.stringify(schema));
|
lafApp: appDetail,
|
||||||
const filterPostSchema = openApiSchema.pathData.filter((item) => item.method === 'post');
|
lafFunctions: filterPostSchema.map((item) => ({
|
||||||
|
...item,
|
||||||
return {
|
requestUrl: `https://${appDetail?.domain.domain}${item.path}`
|
||||||
lafApp: appDetail,
|
}))
|
||||||
lafFunctions: filterPostSchema.map((item) => ({
|
};
|
||||||
...item,
|
} catch (err) {
|
||||||
requestUrl: `https://${appDetail?.domain.domain}${item.path}`
|
await putUpdateTeam({
|
||||||
}))
|
teamId: userInfo?.team.teamId || '',
|
||||||
};
|
lafAccount: { token: '', appid: '', pat: '' }
|
||||||
|
});
|
||||||
|
initUserInfo();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
enabled: !!token && !!appid,
|
||||||
onError(err) {
|
onError(err) {
|
||||||
toast({
|
toast({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
@@ -155,14 +155,14 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
desc: bodyParams[key].description,
|
desc: bodyParams[key].description,
|
||||||
required: requiredParams?.includes(key) || false,
|
required: requiredParams?.includes(key) || false,
|
||||||
value: `{{${key}}}`,
|
value: `{{${key}}}`,
|
||||||
type: 'string'
|
type: bodyParams[key].type
|
||||||
}))
|
}))
|
||||||
].filter((item) => !inputs.find((input) => input.key === item.name));
|
].filter((item) => !inputs.find((input) => input.key === item.name));
|
||||||
|
|
||||||
allParams.forEach((param) => {
|
allParams.forEach((param) => {
|
||||||
const newInput: FlowNodeInputItemType = {
|
const newInput: FlowNodeInputItemType = {
|
||||||
key: param.name,
|
key: param.name,
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
valueType: param.type,
|
||||||
label: param.name,
|
label: param.name,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
required: param.required,
|
required: param.required,
|
||||||
@@ -215,54 +215,63 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
successToast: t('common.Sync success')
|
successToast: t('common.Sync success')
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
// not config laf
|
||||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
if (!token || !appid) {
|
||||||
<Container>
|
return (
|
||||||
{/* select function */}
|
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||||
<MySelect
|
<ConfigLaf />
|
||||||
isLoading={isLoadingFunctions}
|
</NodeCard>
|
||||||
list={lafFunctionSelectList}
|
);
|
||||||
placeholder={t('core.module.laf.Select laf function')}
|
} else {
|
||||||
onchange={(e) => {
|
return (
|
||||||
onChangeNode({
|
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||||
nodeId,
|
<Container>
|
||||||
type: 'updateInput',
|
{/* select function */}
|
||||||
key: NodeInputKeyEnum.httpReqUrl,
|
<MySelect
|
||||||
value: {
|
isLoading={isLoadingFunctions}
|
||||||
...requestUrl,
|
list={lafFunctionSelectList}
|
||||||
value: e
|
placeholder={t('core.module.laf.Select laf function')}
|
||||||
}
|
onchange={(e) => {
|
||||||
});
|
onChangeNode({
|
||||||
}}
|
nodeId,
|
||||||
value={selectedFunction}
|
type: 'updateInput',
|
||||||
/>
|
key: NodeInputKeyEnum.httpReqUrl,
|
||||||
{/* auto set params and go to edit */}
|
value: {
|
||||||
{!!selectedFunction && (
|
...requestUrl,
|
||||||
<Flex justifyContent={'flex-end'} mt={2} gap={2}>
|
value: e
|
||||||
<Button isLoading={isSyncing} variant={'grayBase'} size={'sm'} onClick={onSyncParams}>
|
}
|
||||||
{t('core.module.Laf sync params')}
|
});
|
||||||
</Button>
|
}}
|
||||||
<Button
|
value={selectedFunction}
|
||||||
variant={'grayBase'}
|
/>
|
||||||
size={'sm'}
|
{/* auto set params and go to edit */}
|
||||||
onClick={() => {
|
{!!selectedFunction && (
|
||||||
const lafFunction = lafData?.lafFunctions.find(
|
<Flex justifyContent={'flex-end'} mt={2} gap={2}>
|
||||||
(item) => item.requestUrl === selectedFunction
|
<Button isLoading={isSyncing} variant={'grayBase'} size={'sm'} onClick={onSyncParams}>
|
||||||
);
|
{t('core.module.Laf sync params')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={'grayBase'}
|
||||||
|
size={'sm'}
|
||||||
|
onClick={() => {
|
||||||
|
const lafFunction = lafData?.lafFunctions.find(
|
||||||
|
(item) => item.requestUrl === selectedFunction
|
||||||
|
);
|
||||||
|
|
||||||
if (!lafFunction) return;
|
if (!lafFunction) return;
|
||||||
const url = `${feConfigs.lafEnv}/app/${lafData?.lafApp?.appid}/function${lafFunction?.path}?templateid=FastGPT_Laf`;
|
const url = `${feConfigs.lafEnv}/app/${lafData?.lafApp?.appid}/function${lafFunction?.path}?templateid=FastGPT_Laf`;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('plugin.go to laf')}
|
{t('plugin.go to laf')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
{!!selectedFunction && <RenderIO {...props} />}
|
{!!selectedFunction && <RenderIO {...props} />}
|
||||||
</NodeCard>
|
</NodeCard>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
export default React.memo(NodeLaf);
|
export default React.memo(NodeLaf);
|
||||||
|
|
||||||
|
@@ -67,7 +67,7 @@ const LafAccountModal = ({
|
|||||||
enabled: !!lafToken,
|
enabled: !!lafToken,
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (!getValues('appid') && data.length > 0) {
|
if (!getValues('appid') && data.length > 0) {
|
||||||
setValue('appid', data[0].appid);
|
setValue('appid', data.filter((app) => app.state === 'Running')[0]?.appid);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
@@ -175,7 +175,13 @@ const LafAccountModal = ({
|
|||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant={'whiteBase'} onClick={onClose}>
|
<Button
|
||||||
|
variant={'whiteBase'}
|
||||||
|
onClick={() => {
|
||||||
|
initUserInfo();
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
{t('common.Close')}
|
{t('common.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
{appid && (
|
{appid && (
|
||||||
|
Reference in New Issue
Block a user