|
|
|
|
@ -2,11 +2,58 @@ import { useState, useRef, useEffect, useMemo } from 'react';
|
|
|
|
|
import { Node, Edge } from '@xyflow/react';
|
|
|
|
|
import { debounce } from 'lodash';
|
|
|
|
|
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
|
|
|
|
|
import { updateCanvasDataMap } from '@/store/ideContainer';
|
|
|
|
|
import { updateCanvasDataMap, updateNodeStatus } from '@/store/ideContainer';
|
|
|
|
|
import { getCurrentAppKey } from '@/utils/flow/runtime';
|
|
|
|
|
import { getNodeData } from '@/api/appIns';
|
|
|
|
|
|
|
|
|
|
import { Dispatch } from 'redux';
|
|
|
|
|
|
|
|
|
|
const getRuntimeNodeStatus = (state: any) => {
|
|
|
|
|
switch (state) {
|
|
|
|
|
case 0:
|
|
|
|
|
case '0':
|
|
|
|
|
return 'running';
|
|
|
|
|
case 1:
|
|
|
|
|
case '1':
|
|
|
|
|
return 'success';
|
|
|
|
|
case -1:
|
|
|
|
|
case '-1':
|
|
|
|
|
return 'failed';
|
|
|
|
|
default:
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const collectRuntimeNodes = (runtimeData: any) => {
|
|
|
|
|
if (!runtimeData) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(runtimeData)) {
|
|
|
|
|
return runtimeData.flatMap((item) => {
|
|
|
|
|
if (Array.isArray(item?.nodes)) {
|
|
|
|
|
return item.nodes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return item?.nodeId || item?.id ? [item] : [];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(runtimeData?.main?.nodeLogs)) {
|
|
|
|
|
return runtimeData.main.nodeLogs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(runtimeData?.nodes)) {
|
|
|
|
|
return runtimeData.nodes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(runtimeData?.data)) {
|
|
|
|
|
return collectRuntimeNodes(runtimeData.data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useFlowEditorState = (initialData?: any, readOnly?: boolean) => {
|
|
|
|
|
const [nodes, setNodes] = useState<Node[]>([]);
|
|
|
|
|
const [edges, setEdges] = useState<Edge[]>([]);
|
|
|
|
|
@ -46,6 +93,11 @@ export const useFlowEditorState = (initialData?: any, readOnly?: boolean) => {
|
|
|
|
|
// 在组件顶部添加历史记录相关状态
|
|
|
|
|
const [historyInitialized, setHistoryInitialized] = useState(false);
|
|
|
|
|
const historyTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
|
const syncedRuntimeKeyRef = useRef('');
|
|
|
|
|
const currentRunId =
|
|
|
|
|
currentAppKey && appRuntimeData[currentAppKey]
|
|
|
|
|
? appRuntimeData[currentAppKey].runId
|
|
|
|
|
: '';
|
|
|
|
|
|
|
|
|
|
// 更新节点状态,将从store获取的状态应用到节点上
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
@ -112,6 +164,70 @@ export const useFlowEditorState = (initialData?: any, readOnly?: boolean) => {
|
|
|
|
|
readOnly,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (
|
|
|
|
|
readOnly ||
|
|
|
|
|
!currentAppKey ||
|
|
|
|
|
!currentAppIsRunning ||
|
|
|
|
|
!currentRunId ||
|
|
|
|
|
nodes.length === 0
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const syncKey = `${currentAppKey}:${currentRunId}`;
|
|
|
|
|
if (syncedRuntimeKeyRef.current === syncKey) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let canceled = false;
|
|
|
|
|
syncedRuntimeKeyRef.current = syncKey;
|
|
|
|
|
|
|
|
|
|
const syncRuntimeNodeStatus = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const nodeDataRes: any = await getNodeData(currentRunId);
|
|
|
|
|
const runtimeData = nodeDataRes?.data || nodeDataRes;
|
|
|
|
|
const runtimeNodes = collectRuntimeNodes(runtimeData);
|
|
|
|
|
|
|
|
|
|
if (canceled || runtimeNodes.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runtimeNodes.forEach((node) => {
|
|
|
|
|
const nodeId = node?.nodeId || node?.id;
|
|
|
|
|
const status = getRuntimeNodeStatus(node?.state);
|
|
|
|
|
|
|
|
|
|
if (nodeId && status) {
|
|
|
|
|
dispatch(updateNodeStatus({
|
|
|
|
|
nodeId,
|
|
|
|
|
status,
|
|
|
|
|
appId: currentAppKey,
|
|
|
|
|
actionType: 'RUNTIME_RECONNECT_SYNC',
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (!canceled) {
|
|
|
|
|
syncedRuntimeKeyRef.current = '';
|
|
|
|
|
console.error('同步运行实例节点状态失败:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
syncRuntimeNodeStatus();
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
canceled = true;
|
|
|
|
|
};
|
|
|
|
|
}, [
|
|
|
|
|
currentAppKey,
|
|
|
|
|
currentAppIsRunning,
|
|
|
|
|
currentRunId,
|
|
|
|
|
dispatch,
|
|
|
|
|
nodes.length,
|
|
|
|
|
readOnly,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const updateCanvasDataMapDebounced = useRef(
|
|
|
|
|
debounce(
|
|
|
|
|
(
|
|
|
|
|
|