4.8.10 fix (#2572)

* fix: circle workflow response modal

* perf: workflow runtime check
This commit is contained in:
Archer 2024-08-29 18:00:56 +08:00 committed by GitHub
parent 322ca757af
commit 813eaacfd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 143 additions and 97 deletions

View File

@ -151,6 +151,7 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */ /* ------- response data ------------ */
export type ChatHistoryItemResType = DispatchNodeResponseType & { export type ChatHistoryItemResType = DispatchNodeResponseType & {
nodeId: string; nodeId: string;
id: string;
moduleType: FlowNodeTypeEnum; moduleType: FlowNodeTypeEnum;
moduleName: string; moduleName: string;
}; };

View File

@ -159,6 +159,9 @@ export type DispatchNodeResponseType = {
// user select // user select
userSelectResult?: string; userSelectResult?: string;
// update var
updateVarResult?: any[];
}; };
export type DispatchNodeResultType<T> = { export type DispatchNodeResultType<T> = {

View File

@ -117,39 +117,6 @@ export const filterWorkflowEdges = (edges: RuntimeEdgeItemType[]) => {
); );
}; };
/*
线线
线 nodes
*/
export const splitEdges2WorkflowEdges = ({
edges,
allEdges,
currentNode
}: {
edges: RuntimeEdgeItemType[];
allEdges: RuntimeEdgeItemType[];
currentNode: RuntimeNodeItemType;
}) => {
const commonEdges: RuntimeEdgeItemType[] = [];
const recursiveEdges: RuntimeEdgeItemType[] = [];
edges.forEach((edge) => {
const checkIsCurrentNode = (edge: RuntimeEdgeItemType): boolean => {
const sourceEdge = allEdges.find((item) => item.target === edge.source);
if (!sourceEdge) return false;
if (sourceEdge.source === currentNode.nodeId) return true;
return checkIsCurrentNode(sourceEdge);
};
if (checkIsCurrentNode(edge)) {
recursiveEdges.push(edge);
} else {
commonEdges.push(edge);
}
});
return { commonEdges, recursiveEdges };
};
/* /*
1. 线线线 1. 线线线
2. 线 waiting 线 waiting 2. 线 waiting 线 waiting
@ -161,31 +128,72 @@ export const checkNodeRunStatus = ({
node: RuntimeNodeItemType; node: RuntimeNodeItemType;
runtimeEdges: RuntimeEdgeItemType[]; runtimeEdges: RuntimeEdgeItemType[];
}) => { }) => {
const workflowEdges = filterWorkflowEdges(runtimeEdges).filter( /*
线线
线 nodes
*/
const splitEdges2WorkflowEdges = ({
sourceEdges,
allEdges,
currentNode
}: {
sourceEdges: RuntimeEdgeItemType[];
allEdges: RuntimeEdgeItemType[];
currentNode: RuntimeNodeItemType;
}) => {
const commonEdges: RuntimeEdgeItemType[] = [];
const recursiveEdges: RuntimeEdgeItemType[] = [];
const checkIsCircular = (edge: RuntimeEdgeItemType, visited: Set<string>): boolean => {
if (edge.source === currentNode.nodeId) {
return true; // 检测到环,并且环中包含当前节点
}
if (visited.has(edge.source)) {
return false; // 检测到环,但不包含当前节点(子节点成环)
}
visited.add(edge.source);
const nextEdges = allEdges.filter((item) => item.target === edge.source);
return nextEdges.some((nextEdge) => checkIsCircular(nextEdge, new Set(visited)));
};
sourceEdges.forEach((edge) => {
if (checkIsCircular(edge, new Set([currentNode.nodeId]))) {
recursiveEdges.push(edge);
} else {
commonEdges.push(edge);
}
});
return { commonEdges, recursiveEdges };
};
const runtimeNodeSourceEdge = filterWorkflowEdges(runtimeEdges).filter(
(item) => item.target === node.nodeId (item) => item.target === node.nodeId
); );
// Entry // Entry
if (workflowEdges.length === 0) { if (runtimeNodeSourceEdge.length === 0) {
return 'run'; return 'run';
} }
// Classify edges
const { commonEdges, recursiveEdges } = splitEdges2WorkflowEdges({ const { commonEdges, recursiveEdges } = splitEdges2WorkflowEdges({
edges: workflowEdges, sourceEdges: runtimeNodeSourceEdge,
allEdges: runtimeEdges, allEdges: runtimeEdges,
currentNode: node currentNode: node
}); });
// check skip // check skip(其中一组边,全 skip
if (commonEdges.every((item) => item.status === 'skipped')) { if (commonEdges.length > 0 && commonEdges.every((item) => item.status === 'skipped')) {
return 'skip'; return 'skip';
} }
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status === 'skipped')) { if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status === 'skipped')) {
return 'skip'; return 'skip';
} }
// check active // check active(有一类边,不全是 wait 即可运行)
if (commonEdges.every((item) => item.status !== 'waiting')) { if (commonEdges.length > 0 && commonEdges.every((item) => item.status !== 'waiting')) {
return 'run'; return 'run';
} }
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status !== 'waiting')) { if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status !== 'waiting')) {

View File

@ -19,7 +19,7 @@ import {
FlowNodeInputTypeEnum, FlowNodeInputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '@fastgpt/global/core/workflow/node/constant'; } from '@fastgpt/global/core/workflow/node/constant';
import { replaceVariable } from '@fastgpt/global/common/string/tools'; import { getNanoid, replaceVariable } from '@fastgpt/global/common/string/tools';
import { getSystemTime } from '@fastgpt/global/common/time/timezone'; import { getSystemTime } from '@fastgpt/global/common/time/timezone';
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils'; import { replaceEditorVariable } from '@fastgpt/global/core/workflow/utils';
@ -434,6 +434,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
const formatResponseData: ChatHistoryItemResType = (() => { const formatResponseData: ChatHistoryItemResType = (() => {
if (!dispatchRes[DispatchNodeResponseKeyEnum.nodeResponse]) return undefined; if (!dispatchRes[DispatchNodeResponseKeyEnum.nodeResponse]) return undefined;
return { return {
id: getNanoid(),
nodeId: node.nodeId, nodeId: node.nodeId,
moduleName: node.name, moduleName: node.name,
moduleType: node.flowNodeType, moduleType: node.flowNodeType,

View File

@ -19,12 +19,12 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
const { params, variables, runtimeNodes, workflowStreamResponse, node } = props; const { params, variables, runtimeNodes, workflowStreamResponse, node } = props;
const { updateList } = params; const { updateList } = params;
updateList.forEach((item) => { const result = updateList.map((item) => {
const varNodeId = item.variable?.[0]; const varNodeId = item.variable?.[0];
const varKey = item.variable?.[1]; const varKey = item.variable?.[1];
if (!varNodeId || !varKey) { if (!varNodeId || !varKey) {
return; return null;
} }
const value = (() => { const value = (() => {
@ -48,10 +48,11 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
} }
})(); })();
// Global variable
if (varNodeId === VARIABLE_NODE_ID) { if (varNodeId === VARIABLE_NODE_ID) {
// update global variable
variables[varKey] = value; variables[varKey] = value;
} else { } else {
// Other nodes
runtimeNodes runtimeNodes
.find((node) => node.nodeId === varNodeId) .find((node) => node.nodeId === varNodeId)
?.outputs?.find((output) => { ?.outputs?.find((output) => {
@ -61,6 +62,8 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
} }
}); });
} }
return value;
}); });
workflowStreamResponse?.({ workflowStreamResponse?.({
@ -70,7 +73,7 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
return { return {
[DispatchNodeResponseKeyEnum.nodeResponse]: { [DispatchNodeResponseKeyEnum.nodeResponse]: {
totalPoints: 0 updateVarResult: result
} }
}; };
}; };

View File

@ -565,6 +565,7 @@
"plugin output": "Plugin output value", "plugin output": "Plugin output value",
"search using reRank": "Result rearrangement", "search using reRank": "Result rearrangement",
"text output": "text output", "text output": "text output",
"update_var_result": "Variable update results (display multiple variable update results in order)",
"user_select_result": "User select result" "user_select_result": "User select result"
}, },
"retry": "Regenerate", "retry": "Regenerate",

View File

@ -10,6 +10,8 @@
"auto_renew_q": "订阅套餐会自动续费么?", "auto_renew_q": "订阅套餐会自动续费么?",
"change_package_a": "当前套餐价格大于新套餐时,无法立即切换,将会在当前套餐过期后以“续费”形式进行切换。\n当前套餐价格小于新套餐时系统会自动计算当前套餐剩余余额您可支付差价进行套餐切换。", "change_package_a": "当前套餐价格大于新套餐时,无法立即切换,将会在当前套餐过期后以“续费”形式进行切换。\n当前套餐价格小于新套餐时系统会自动计算当前套餐剩余余额您可支付差价进行套餐切换。",
"change_package_q": "能否切换订阅套餐?", "change_package_q": "能否切换订阅套餐?",
"check_subscription_a": "账号-个人信息-套餐详情-使用情况。您可以查看所拥有套餐的生效和到期时间。当付费套餐到期后将自动切换免费版。",
"check_subscription_q": "在哪里查看已订阅的套餐?",
"dataset_compute_a": "1条知识库存储等于1条知识库索引。一条知识库数据可以包含1条或多条知识库索引。增强训练中1条数据会生成5条索引。", "dataset_compute_a": "1条知识库存储等于1条知识库索引。一条知识库数据可以包含1条或多条知识库索引。增强训练中1条数据会生成5条索引。",
"dataset_compute_q": "知识库存储怎么计算?", "dataset_compute_q": "知识库存储怎么计算?",
"dataset_index_a": "不会。但知识库索引超出时,无法插入和更新知识库内容。", "dataset_index_a": "不会。但知识库索引超出时,无法插入和更新知识库内容。",
@ -18,19 +20,15 @@
"free_user_clean_q": "免费版数据会清除么?", "free_user_clean_q": "免费版数据会清除么?",
"package_overlay_a": "可以的。每次购买的资源包都是独立的在其有效期内将会叠加使用。AI积分会优先扣除最先过期的资源包。", "package_overlay_a": "可以的。每次购买的资源包都是独立的在其有效期内将会叠加使用。AI积分会优先扣除最先过期的资源包。",
"package_overlay_q": "额外资源包可以叠加么?", "package_overlay_q": "额外资源包可以叠加么?",
"switch_package_q": "是否切换订阅套餐?",
"switch_package_a": "套餐使用规则为优先使用更高级的套餐,因此,购买的新套餐若比当前套餐更高级,则新套餐立即生效:否则将继续使用当前套餐。", "switch_package_a": "套餐使用规则为优先使用更高级的套餐,因此,购买的新套餐若比当前套餐更高级,则新套餐立即生效:否则将继续使用当前套餐。",
"check_subscription_q": "在哪里查看已订阅的套餐?", "switch_package_q": "是否切换订阅套餐?"
"check_subscription_a": "账号-个人信息-套餐详情-使用情况。您可以查看所拥有套餐的生效和到期时间。当付费套餐到期后将自动切换免费版。"
}, },
"Folder": "文件夹", "Folder": "文件夹",
"Login": "登录", "Login": "登录",
"is_using": "正在使用",
"Move": "移动", "Move": "移动",
"Name": "名称", "Name": "名称",
"Rename": "重命名", "Rename": "重命名",
"Resume": "恢复", "Resume": "恢复",
"free": "免费",
"Running": "运行中", "Running": "运行中",
"UnKnow": "未知", "UnKnow": "未知",
"Warning": "提示", "Warning": "提示",
@ -119,7 +117,6 @@
"Cancel": "取消", "Cancel": "取消",
"Choose": "选择", "Choose": "选择",
"Close": "关闭", "Close": "关闭",
"base_config": "基础配置",
"Config": "配置", "Config": "配置",
"Confirm": "确认", "Confirm": "确认",
"Confirm Create": "确认创建", "Confirm Create": "确认创建",
@ -224,6 +221,7 @@
"Select Avatar": "点击选择头像", "Select Avatar": "点击选择头像",
"Select Failed": "选择头像异常" "Select Failed": "选择头像异常"
}, },
"base_config": "基础配置",
"choosable": "可选", "choosable": "可选",
"confirm": { "confirm": {
"Common Tip": "操作确认" "Common Tip": "操作确认"
@ -567,6 +565,7 @@
"plugin output": "插件输出值", "plugin output": "插件输出值",
"search using reRank": "结果重排", "search using reRank": "结果重排",
"text output": "文本输出", "text output": "文本输出",
"update_var_result": "变量更新结果(按顺序展示多个变量更新结果)",
"user_select_result": "用户选择结果" "user_select_result": "用户选择结果"
}, },
"retry": "重新生成", "retry": "重新生成",
@ -639,7 +638,8 @@
"success": "开始同步" "success": "开始同步"
} }
}, },
"training": {} "training": {
}
}, },
"data": { "data": {
"Auxiliary Data": "辅助数据", "Auxiliary Data": "辅助数据",
@ -775,7 +775,6 @@
"test result tip": "根据知识库内容与测试文本的相似度进行排序,你可以根据测试结果调整对应的文本。\n注意测试记录中的数据可能已经被修改过点击某条测试数据后将展示最新的数据。" "test result tip": "根据知识库内容与测试文本的相似度进行排序,你可以根据测试结果调整对应的文本。\n注意测试记录中的数据可能已经被修改过点击某条测试数据后将展示最新的数据。"
}, },
"training": { "training": {
"tag": "排队情况",
"Agent queue": "QA 训练排队", "Agent queue": "QA 训练排队",
"Auto mode": "增强处理(实验)", "Auto mode": "增强处理(实验)",
"Auto mode Tip": "通过子索引以及调用模型生成相关问题与摘要,来增加数据块的语义丰富度,更利于检索。需要消耗更多的存储空间和增加 AI 调用次数。", "Auto mode Tip": "通过子索引以及调用模型生成相关问题与摘要,来增加数据块的语义丰富度,更利于检索。需要消耗更多的存储空间和增加 AI 调用次数。",
@ -785,7 +784,8 @@
"QA mode": "问答拆分", "QA mode": "问答拆分",
"Vector queue": "索引排队", "Vector queue": "索引排队",
"Waiting": "预计 5 分钟", "Waiting": "预计 5 分钟",
"Website Sync": "Web 站点同步" "Website Sync": "Web 站点同步",
"tag": "排队情况"
}, },
"website": { "website": {
"Base Url": "根地址", "Base Url": "根地址",
@ -1078,6 +1078,7 @@
}, },
"extraction_results": "提取结果", "extraction_results": "提取结果",
"field_name": "字段名", "field_name": "字段名",
"free": "免费",
"get_QR_failed": "获取二维码失败", "get_QR_failed": "获取二维码失败",
"get_app_failed": "获取应用失败", "get_app_failed": "获取应用失败",
"get_laf_failed": "获取Laf函数列表失败", "get_laf_failed": "获取Laf函数列表失败",
@ -1097,6 +1098,7 @@
}, },
"invalid_variable": "无效变量", "invalid_variable": "无效变量",
"is_open": "是否开启", "is_open": "是否开启",
"is_using": "正在使用",
"item_description": "字段描述", "item_description": "字段描述",
"item_name": "字段名", "item_name": "字段名",
"key_repetition": "key 重复", "key_repetition": "key 重复",
@ -1125,14 +1127,14 @@
"notice": "请勿关闭页面", "notice": "请勿关闭页面",
"old_package_price": "旧套餐余额", "old_package_price": "旧套餐余额",
"other": "其他金额,请取整数", "other": "其他金额,请取整数",
"to_recharge": "余额不足,去充值",
"wechat": "请微信扫码支付: {{price}}元\n请勿关闭页面",
"yuan": "{{amount}}元",
"package_tip": { "package_tip": {
"buy": "您购买的套餐等级低于当前套餐,该套餐将在当前套餐过期后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "buy": "您购买的套餐等级低于当前套餐,该套餐将在当前套餐过期后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。",
"renewal": "您正在续费套餐。您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "renewal": "您正在续费套餐。您可在账号—个人信息—套餐详情里,查看套餐使用情况。",
"upgrade": "您购买的套餐等级高于当前套餐,该套餐将即刻生效,当前套餐将延后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。" "upgrade": "您购买的套餐等级高于当前套餐,该套餐将即刻生效,当前套餐将延后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。"
} },
"to_recharge": "余额不足,去充值",
"wechat": "请微信扫码支付: {{price}}元\n请勿关闭页面",
"yuan": "{{amount}}元"
}, },
"permission": { "permission": {
"Collaborator": "协作者", "Collaborator": "协作者",
@ -1217,8 +1219,8 @@
"standard": { "standard": {
"AI Bonus Points": "AI 积分", "AI Bonus Points": "AI 积分",
"Expired Time": "结束时间", "Expired Time": "结束时间",
"due_date": "到期时间",
"Start Time": "开始时间", "Start Time": "开始时间",
"due_date": "到期时间",
"storage": "存储量", "storage": "存储量",
"type": "类型" "type": "类型"
}, },
@ -1334,11 +1336,6 @@
"noBill": "无账单记录~", "noBill": "无账单记录~",
"no_invoice": "暂无开票记录", "no_invoice": "暂无开票记录",
"subscription": { "subscription": {
"status": {
"expired": "已过期",
"active": "生效中",
"inactive": "待使用"
},
"AI points": "AI 积分", "AI points": "AI 积分",
"AI points click to read tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分(类似于 token。点击可查看详细计算规则。", "AI points click to read tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分(类似于 token。点击可查看详细计算规则。",
"AI points usage": "AI 积分使用量", "AI points usage": "AI 积分使用量",
@ -1384,13 +1381,18 @@
"standardSubLevel": { "standardSubLevel": {
"custom": "自定义版", "custom": "自定义版",
"enterprise": "企业版", "enterprise": "企业版",
"enterprise_desc": "适合中小企业在生产环境构建知识库应用",
"experience": "体验版", "experience": "体验版",
"experience_desc": "可解锁 FastGPT 完整功能",
"free": "免费版", "free": "免费版",
"free desc": "每月均可免费使用基础功能,连续 30 天未登录系统,将会自动清除知识库", "free desc": "每月均可免费使用基础功能,连续 30 天未登录系统,将会自动清除知识库",
"team": "团队版", "team": "团队版",
"experience_desc": "可解锁 FastGPT 完整功能", "team_desc": "适合小团队构建知识库应用并提供对外服务"
"team_desc": "适合小团队构建知识库应用并提供对外服务", },
"enterprise_desc": "适合中小企业在生产环境构建知识库应用" "status": {
"active": "生效中",
"expired": "已过期",
"inactive": "待使用"
}, },
"token_compute": "点击查看在线 Tokens 计算器", "token_compute": "点击查看在线 Tokens 计算器",
"type": { "type": {

View File

@ -24,7 +24,8 @@ type sideTabItemType = {
moduleName: string; moduleName: string;
runningTime?: number; runningTime?: number;
moduleType: string; moduleType: string;
nodeId: string; // nodeId:string; // abandon
id: string;
children: sideTabItemType[]; children: sideTabItemType[];
}; };
@ -149,18 +150,28 @@ export const ResponseBox = React.memo(function ResponseBox({
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { isPc } = useSystem(); const { isPc } = useSystem();
const flattedResponse = useMemo(() => flattenArray(response), [response]);
const flattedResponse = useMemo(
() =>
flattenArray(response).map((item) => ({
...item,
id: item.id ?? item.nodeId
})),
[response]
);
const [currentNodeId, setCurrentNodeId] = useState( const [currentNodeId, setCurrentNodeId] = useState(
flattedResponse[0]?.nodeId ? flattedResponse[0].nodeId : '' flattedResponse[0]?.id ?? flattedResponse[0]?.nodeId ?? ''
); );
const activeModule = useMemo( const activeModule = useMemo(
() => flattedResponse.find((item) => item.nodeId === currentNodeId) as ChatHistoryItemResType, () => flattedResponse.find((item) => item.id === currentNodeId) as ChatHistoryItemResType,
[currentNodeId, flattedResponse] [currentNodeId, flattedResponse]
); );
const sideResponse: sideTabItemType[] = useMemo(() => {
const sliderResponseList: sideTabItemType[] = useMemo(() => {
return pretreatmentResponse(response); return pretreatmentResponse(response);
}, [response]); }, [response]);
const { const {
isOpen: isOpenMobileModal, isOpen: isOpenMobileModal,
onOpen: onOpenMobileModal, onOpen: onOpenMobileModal,
@ -174,7 +185,7 @@ export const ResponseBox = React.memo(function ResponseBox({
<Box flex={'2 0 0'} borderRight={'sm'} p={3}> <Box flex={'2 0 0'} borderRight={'sm'} p={3}>
<Box overflow={'auto'} height={'100%'}> <Box overflow={'auto'} height={'100%'}>
<WholeResponseSideTab <WholeResponseSideTab
response={sideResponse} response={sliderResponseList}
value={currentNodeId} value={currentNodeId}
onChange={setCurrentNodeId} onChange={setCurrentNodeId}
/> />
@ -192,7 +203,7 @@ export const ResponseBox = React.memo(function ResponseBox({
<Box h={'100%'} overflow={'auto'}> <Box h={'100%'} overflow={'auto'}>
{!isOpenMobileModal && ( {!isOpenMobileModal && (
<WholeResponseSideTab <WholeResponseSideTab
response={sideResponse} response={sliderResponseList}
value={currentNodeId} value={currentNodeId}
onChange={(item: string) => { onChange={(item: string) => {
setCurrentNodeId(item); setCurrentNodeId(item);
@ -442,11 +453,11 @@ export const WholeResponseContent = ({
/> />
{/* code */} {/* code */}
<> <>
<Row label={t('workflow:response.Custom inputs')} value={activeModule?.customInputs} />
<Row <Row
label={t('workflow:response.Custom outputs')} label={t('workflow:response.Custom outputs')}
value={activeModule?.customOutputs} value={activeModule?.customOutputs}
/> />
<Row label={t('workflow:response.Custom inputs')} value={activeModule?.customInputs} />
<Row label={t('workflow:response.Code log')} value={activeModule?.codeLog} /> <Row label={t('workflow:response.Code log')} value={activeModule?.codeLog} />
</> </>
@ -491,6 +502,12 @@ export const WholeResponseContent = ({
label={t('common:core.chat.response.user_select_result')} label={t('common:core.chat.response.user_select_result')}
value={activeModule?.userSelectResult} value={activeModule?.userSelectResult}
/> />
{/* update var */}
<Row
label={t('common:core.chat.response.update_var_result')}
value={activeModule?.updateVarResult}
/>
</Box> </Box>
)} )}
</> </>
@ -512,7 +529,7 @@ const WholeResponseSideTab = ({
<> <>
{response.map((item) => ( {response.map((item) => (
<Box <Box
key={item.nodeId} key={item.id}
bg={isMobile ? 'myGray.100' : ''} bg={isMobile ? 'myGray.100' : ''}
m={isMobile ? 3 : 0} m={isMobile ? 3 : 0}
borderRadius={'md'} borderRadius={'md'}
@ -532,7 +549,7 @@ const AccordionSideTabItem = ({
index index
}: { }: {
sideBarItem: sideTabItemType; sideBarItem: sideTabItemType;
onChange: (nodeId: string) => void; onChange: (id: string) => void;
value: string; value: string;
index: number; index: number;
}) => { }) => {
@ -565,7 +582,7 @@ const AccordionSideTabItem = ({
{sideBarItem.children.map((item) => ( {sideBarItem.children.map((item) => (
<SideTabItem <SideTabItem
value={value} value={value}
key={item.nodeId} key={item.id}
sideBarItem={item} sideBarItem={item}
onChange={onChange} onChange={onChange}
index={index + 1} index={index + 1}
@ -585,7 +602,7 @@ const NormalSideTabItem = ({
children children
}: { }: {
sideBarItem: sideTabItemType; sideBarItem: sideTabItemType;
onChange: (nodeId: string) => void; onChange: (id: string) => void;
value: string; value: string;
index: number; index: number;
children?: React.ReactNode; children?: React.ReactNode;
@ -596,9 +613,9 @@ const NormalSideTabItem = ({
<Flex <Flex
alignItems={'center'} alignItems={'center'}
onClick={() => { onClick={() => {
onChange(sideBarItem.nodeId); onChange(sideBarItem.id);
}} }}
background={value === sideBarItem.nodeId ? 'myGray.100' : ''} background={value === sideBarItem.id ? 'myGray.100' : ''}
_hover={{ background: 'myGray.100' }} _hover={{ background: 'myGray.100' }}
p={2} p={2}
width={'100%'} width={'100%'}
@ -647,7 +664,7 @@ const SideTabItem = ({
index index
}: { }: {
sideBarItem: sideTabItemType; sideBarItem: sideTabItemType;
onChange: (nodeId: string) => void; onChange: (id: string) => void;
value: string; value: string;
index: number; index: number;
}) => { }) => {
@ -668,6 +685,7 @@ const SideTabItem = ({
); );
}; };
/* Format response data to slider data */
function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] { function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] {
return res.map((item) => { return res.map((item) => {
let children: sideTabItemType[] = []; let children: sideTabItemType[] = [];
@ -681,12 +699,13 @@ function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[]
moduleName: item.moduleName, moduleName: item.moduleName,
runningTime: item.runningTime, runningTime: item.runningTime,
moduleType: item.moduleType, moduleType: item.moduleType,
nodeId: item.nodeId, id: item.id ?? item.nodeId,
children children
}; };
}); });
} }
/* Flat response */
function flattenArray(arr: ChatHistoryItemResType[]) { function flattenArray(arr: ChatHistoryItemResType[]) {
const result: ChatHistoryItemResType[] = []; const result: ChatHistoryItemResType[] = [];

View File

@ -56,9 +56,9 @@ const FlowController = React.memo(function FlowController() {
<> <>
<MiniMap <MiniMap
style={{ style={{
height: 98, height: 92,
width: 184, width: 150,
marginBottom: 72, marginBottom: 62,
borderRadius: '10px', borderRadius: '10px',
boxShadow: '0px 0px 1px rgba(19, 51, 107, 0.10), 0px 4px 10px rgba(19, 51, 107, 0.10)' boxShadow: '0px 0px 1px rgba(19, 51, 107, 0.10), 0px 4px 10px rgba(19, 51, 107, 0.10)'
}} }}
@ -68,7 +68,7 @@ const FlowController = React.memo(function FlowController() {
position={'bottom-right'} position={'bottom-right'}
style={{ style={{
display: 'flex', display: 'flex',
marginBottom: 24, marginBottom: 16,
padding: '5px 8px', padding: '5px 8px',
background: 'white', background: 'white',
borderRadius: '6px', borderRadius: '6px',

View File

@ -375,15 +375,21 @@ const ConditionSelect = ({
return []; return [];
}, [valueType]); }, [valueType]);
const filterQuiredConditionList = useMemo(() => { const filterQuiredConditionList = useMemo(() => {
if (required) { const list = (() => {
return conditionList.filter( if (required) {
(item) => return conditionList.filter(
item.value !== VariableConditionEnum.isEmpty && (item) =>
item.value !== VariableConditionEnum.isNotEmpty item.value !== VariableConditionEnum.isEmpty &&
); item.value !== VariableConditionEnum.isNotEmpty
} );
return conditionList; }
}, [conditionList, required]); return conditionList;
})();
return list.map((item) => ({
...item,
label: t(item.label)
}));
}, [conditionList, required, t]);
return ( return (
<MySelect <MySelect

View File

@ -87,7 +87,9 @@ export const getEditorVariables = ({
appDetail: AppDetailType; appDetail: AppDetailType;
t: TFunction; t: TFunction;
}) => { }) => {
const currentNode = nodeList.find((node) => node.nodeId === nodeId)!; const currentNode = nodeList.find((node) => node.nodeId === nodeId);
if (!currentNode) return [];
const nodeVariables = currentNode.inputs const nodeVariables = currentNode.inputs
.filter((input) => input.canEdit) .filter((input) => input.canEdit)
.map((item) => ({ .map((item) => ({