diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx index 6ab1644ca1..ffdd166ed2 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx @@ -38,7 +38,7 @@ const LastRun: FC = ({ const noLastRun = (error as any)?.status === 404 const runResult = (canRunLastRun ? lastRunResult : singleRunResult) || {} - if (isFetching) { + if (isFetching && !runResult) { return (
diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts index 57ae06c20c..367eac0a0d 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts @@ -99,7 +99,7 @@ const useGetDataForCheckMoreHooks = (nodeType: BlockEnum) => { } } -type Params = OneStepRunParams +type Params = Omit, 'isRunAfterSingleRun'> const useLastRun = ({ ...oneStepRunParams }: Params) => { @@ -112,6 +112,8 @@ const useLastRun = ({ const { getData: getDataForCheckMore, } = useGetDataForCheckMoreHooks(blockType)(oneStepRunParams.id, oneStepRunParams.data) + const [isRunAfterSingleRun, setIsRunAfterSingleRun] = useState(false) + const { id, data, @@ -120,6 +122,7 @@ const useLastRun = ({ ...oneStepRunParams, iteratorInputKey: blockType === BlockEnum.Iteration ? `${id}.input_selector` : '', moreDataForCheckValid: getDataForCheckMore(), + isRunAfterSingleRun, }) const { @@ -180,7 +183,6 @@ const useLastRun = ({ } const [tabType, setTabType] = useState(TabType.settings) - const [isRunAfterSingleRun, setIsRunAfterSingleRun] = useState(false) const handleRunWithParams = async (data: Record) => { setIsRunAfterSingleRun(true) setTabType(TabType.lastRun) diff --git a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts index 56a5cfcd73..04adb56ece 100644 --- a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts +++ b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts @@ -77,6 +77,7 @@ export type Params = { moreDataForCheckValid?: any iteratorInputKey?: string loopInputKey?: string + isRunAfterSingleRun: boolean } const varTypeToInputVarType = (type: VarType, { @@ -109,6 +110,7 @@ const useOneStepRun = ({ moreDataForCheckValid, iteratorInputKey, loopInputKey, + isRunAfterSingleRun, }: Params) => { const { t } = useTranslation() const { getBeforeNodesInSameBranch, getBeforeNodesInSameBranchIncludeParent } = useWorkflow() as any @@ -170,8 +172,15 @@ const useOneStepRun = ({ invalidateSysVarValues, invalidateConversationVarValues, } = useInspectVarsCrud() + const runningStatus = data._singleRunningStatus || NodeRunningStatus.NotStart + const setRunResult = useCallback(async (data: NodeRunResult | null) => { - doSetRunResult(data) + const canRunLastRun = !isRunAfterSingleRun || runningStatus === NodeRunningStatus.Succeeded + if(!canRunLastRun) { + doSetRunResult(data) + return + } + // run fail may also update the inspect vars when the node set the error default output. const vars = await fetchNodeInspectVars(appId!, id) const { getNodes } = store.getState() @@ -183,7 +192,7 @@ const useOneStepRun = ({ invalidateSysVarValues() invalidateConversationVarValues() // loop, iteration, variable assigner node can update the conversation variables, but to simple the logic(some nodes may also can update in the future), all nodes refresh. } - }, [invalidLastRun, appId, id, store, appendNodeInspectVars, isStartNode, invalidateSysVarValues, invalidateConversationVarValues]) + }, [isRunAfterSingleRun, runningStatus, appId, id, store, appendNodeInspectVars, invalidLastRun, isStartNode, invalidateSysVarValues, invalidateConversationVarValues]) const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useNodeDataUpdate() const [canShowSingleRun, setCanShowSingleRun] = useState(false) @@ -239,7 +248,6 @@ const useOneStepRun = ({ }, }) } - const runningStatus = data._singleRunningStatus || NodeRunningStatus.NotStart const isCompleted = runningStatus === NodeRunningStatus.Succeeded || runningStatus === NodeRunningStatus.Failed const handleRun = async (submitData: Record) => { diff --git a/web/app/components/workflow/nodes/loop/panel.tsx b/web/app/components/workflow/nodes/loop/panel.tsx index 757ba6b51d..d3f06482c2 100644 --- a/web/app/components/workflow/nodes/loop/panel.tsx +++ b/web/app/components/workflow/nodes/loop/panel.tsx @@ -1,5 +1,5 @@ import type { FC } from 'react' -import React, { useMemo } from 'react' +import React from 'react' import { useTranslation } from 'react-i18next' import { RiAddLine } from '@remixicon/react' import Split from '../_base/components/split' @@ -10,9 +10,7 @@ import ConditionWrap from './components/condition-wrap' import LoopVariable from './components/loop-variables' import type { NodePanelProps } from '@/app/components/workflow/types' import Field from '@/app/components/workflow/nodes/_base/components/field' -import formatTracing from '@/app/components/workflow/run/utils/format-log' -import { useLogs } from '@/app/components/workflow/run/hooks' import { LOOP_NODE_MAX_COUNT } from '@/config' const i18nPrefix = 'workflow.nodes.loop' @@ -28,8 +26,6 @@ const Panel: FC> = ({ inputs, childrenNodeVars, loopChildrenNodes, - runResult, - loopRunResult, handleAddCondition, handleUpdateCondition, handleRemoveCondition, @@ -44,23 +40,6 @@ const Panel: FC> = ({ handleUpdateLoopVariable, } = useConfig(id, data) - const nodeInfo = useMemo(() => { - const formattedNodeInfo = formatTracing(loopRunResult, t)[0] - - if (runResult && formattedNodeInfo) { - return { - ...formattedNodeInfo, - execution_metadata: { - ...runResult.execution_metadata, - ...formattedNodeInfo.execution_metadata, - }, - } - } - - return formattedNodeInfo - }, [runResult, loopRunResult, t]) - const logsParams = useLogs() - return (
diff --git a/web/app/components/workflow/nodes/loop/use-config.ts b/web/app/components/workflow/nodes/loop/use-config.ts index 6858674a47..965fe2b395 100644 --- a/web/app/components/workflow/nodes/loop/use-config.ts +++ b/web/app/components/workflow/nodes/loop/use-config.ts @@ -3,7 +3,6 @@ import { useRef, } from 'react' import produce from 'immer' -import { useBoolean } from 'ahooks' import { v4 as uuid4 } from 'uuid' import { useIsChatMode, @@ -12,10 +11,9 @@ import { useWorkflow, } from '../../hooks' import { ValueType, VarType } from '../../types' -import type { ErrorHandleMode, ValueSelector, Var } from '../../types' +import type { ErrorHandleMode, Var } from '../../types' import useNodeCrud from '../_base/hooks/use-node-crud' -import { getNodeInfoById, getNodeUsedVarPassToServerKey, getNodeUsedVars, isSystemVar, toNodeOutputVars } from '../_base/components/variable/utils' -import useOneStepRun from '../_base/hooks/use-one-step-run' +import { toNodeOutputVars } from '../_base/components/variable/utils' import { getOperators } from './utils' import { LogicalOperator } from './types' import type { HandleAddCondition, HandleAddSubVariableCondition, HandleRemoveCondition, HandleToggleConditionLogicalOperator, HandleToggleSubVariableConditionLogicalOperator, HandleUpdateCondition, HandleUpdateSubVariableCondition, LoopNodeType } from './types' @@ -47,137 +45,12 @@ const useConfig = (id: string, payload: LoopNodeType) => { const canChooseVarNodes = [...beforeNodes, ...loopChildrenNodes] const childrenNodeVars = toNodeOutputVars(loopChildrenNodes, isChatMode, undefined, [], conversationVariables) - // single run - const loopInputKey = `${id}.input_selector` - const { - showSingleRun, - hideSingleRun, - toVarInputs, - handleRun: doHandleRun, - runInputData, - setRunInputData, - runResult, - loopRunResult, - } = useOneStepRun({ - id, - data: inputs, - loopInputKey, - defaultRunInputData: { - [loopInputKey]: [''], - }, - }) - - const [isShowLoopDetail, { - setTrue: doShowLoopDetail, - setFalse: doHideLoopDetail, - }] = useBoolean(false) - - const hideLoopDetail = useCallback(() => { - hideSingleRun() - doHideLoopDetail() - }, [doHideLoopDetail, hideSingleRun]) - - const showLoopDetail = useCallback(() => { - doShowLoopDetail() - }, [doShowLoopDetail]) - - const backToSingleRun = useCallback(() => { - hideLoopDetail() - showSingleRun() - }, [hideLoopDetail, showSingleRun]) - const { getIsVarFileAttribute, } = useIsVarFileAttribute({ nodeId: id, }) - const { usedOutVars, allVarObject } = (() => { - const vars: ValueSelector[] = [] - const varObjs: Record = {} - const allVarObject: Record = {} - loopChildrenNodes.forEach((node) => { - const nodeVars = getNodeUsedVars(node).filter(item => item && item.length > 0) - nodeVars.forEach((varSelector) => { - if (varSelector[0] === id) { // skip Loop node itself variable: item, index - return - } - const isInLoop = isNodeInLoop(varSelector[0]) - if (isInLoop) // not pass loop inner variable - return - - const varSectorStr = varSelector.join('.') - if (!varObjs[varSectorStr]) { - varObjs[varSectorStr] = true - vars.push(varSelector) - } - let passToServerKeys = getNodeUsedVarPassToServerKey(node, varSelector) - if (typeof passToServerKeys === 'string') - passToServerKeys = [passToServerKeys] - - passToServerKeys.forEach((key: string, index: number) => { - allVarObject[[varSectorStr, node.id, index].join(DELIMITER)] = { - inSingleRunPassedKey: key, - } - }) - }) - }) - const res = toVarInputs(vars.map((item) => { - const varInfo = getNodeInfoById(canChooseVarNodes, item[0]) - return { - label: { - nodeType: varInfo?.data.type, - nodeName: varInfo?.data.title || canChooseVarNodes[0]?.data.title, // default start node title - variable: isSystemVar(item) ? item.join('.') : item[item.length - 1], - }, - variable: `${item.join('.')}`, - value_selector: item, - } - })) - return { - usedOutVars: res, - allVarObject, - } - })() - - const handleRun = useCallback((data: Record) => { - const formattedData: Record = {} - Object.keys(allVarObject).forEach((key) => { - const [varSectorStr, nodeId] = key.split(DELIMITER) - formattedData[`${nodeId}.${allVarObject[key].inSingleRunPassedKey}`] = data[varSectorStr] - }) - formattedData[loopInputKey] = data[loopInputKey] - doHandleRun(formattedData) - }, [allVarObject, doHandleRun, loopInputKey]) - - const inputVarValues = (() => { - const vars: Record = {} - Object.keys(runInputData) - .filter(key => ![loopInputKey].includes(key)) - .forEach((key) => { - vars[key] = runInputData[key] - }) - return vars - })() - - const setInputVarValues = useCallback((newPayload: Record) => { - const newVars = { - ...newPayload, - [loopInputKey]: runInputData[loopInputKey], - } - setRunInputData(newVars) - }, [loopInputKey, runInputData, setRunInputData]) - - const loop = runInputData[loopInputKey] - const setLoop = useCallback((newLoop: string[]) => { - setRunInputData({ - ...runInputData, - [loopInputKey]: newLoop, - }) - }, [loopInputKey, runInputData, setRunInputData]) - const changeErrorResponseMode = useCallback((item: { value: unknown }) => { const newInputs = produce(inputs, (draft) => { draft.error_handle_mode = item.value as ErrorHandleMode @@ -339,19 +212,6 @@ const useConfig = (id: string, payload: LoopNodeType) => { filterInputVar, childrenNodeVars, loopChildrenNodes, - showSingleRun, - isShowLoopDetail, - showLoopDetail, - hideLoopDetail, - backToSingleRun, - runResult, - inputVarValues, - setInputVarValues, - usedOutVars, - loop, - setLoop, - loopInputKey, - loopRunResult, handleAddCondition, handleRemoveCondition, handleUpdateCondition,