diff --git a/web/app/components/workflow-app/components/workflow-main.tsx b/web/app/components/workflow-app/components/workflow-main.tsx index f0b9bab2c..d425e6f59 100644 --- a/web/app/components/workflow-app/components/workflow-main.tsx +++ b/web/app/components/workflow-app/components/workflow-main.tsx @@ -15,7 +15,7 @@ import { useWorkflowRun, useWorkflowStartRun, } from '../hooks' -import { useWorkflowStore } from '@/app/components/workflow/store' +import { useStore, useWorkflowStore } from '@/app/components/workflow/store' type WorkflowMainProps = Pick const WorkflowMain = ({ @@ -64,7 +64,11 @@ const WorkflowMain = ({ handleWorkflowStartRunInChatflow, handleWorkflowStartRunInWorkflow, } = useWorkflowStartRun() - const { fetchInspectVars } = useSetWorkflowVarsWithValue() + const appId = useStore(s => s.appId) + const { fetchInspectVars } = useSetWorkflowVarsWithValue({ + flowId: appId, + ...useConfigsMap(), + }) const { hasNodeInspectVars, hasSetInspectVar, diff --git a/web/app/components/workflow-app/hooks/index.ts b/web/app/components/workflow-app/hooks/index.ts index 1ee7c030b..9e4f94965 100644 --- a/web/app/components/workflow-app/hooks/index.ts +++ b/web/app/components/workflow-app/hooks/index.ts @@ -5,6 +5,6 @@ export * from './use-workflow-run' export * from './use-workflow-start-run' export * from './use-is-chat-mode' export * from './use-workflow-refresh-draft' -export * from './use-fetch-workflow-inspect-vars' +export * from '../../workflow/hooks/use-fetch-workflow-inspect-vars' export * from './use-inspect-vars-crud' export * from './use-configs-map' diff --git a/web/app/components/workflow-app/hooks/use-inspect-vars-crud.ts b/web/app/components/workflow-app/hooks/use-inspect-vars-crud.ts index ce052b7ed..109ee85f9 100644 --- a/web/app/components/workflow-app/hooks/use-inspect-vars-crud.ts +++ b/web/app/components/workflow-app/hooks/use-inspect-vars-crud.ts @@ -1,234 +1,16 @@ -import { fetchNodeInspectVars } from '@/service/workflow' -import { useStore, useWorkflowStore } from '@/app/components/workflow/store' -import type { ValueSelector } from '@/app/components/workflow/types' -import type { VarInInspect } from '@/types/workflow' -import { VarInInspectType } from '@/types/workflow' -import { - useDeleteAllInspectorVars, - useDeleteInspectVar, - useDeleteNodeInspectorVars, - useEditInspectorVar, - useInvalidateConversationVarValues, - useInvalidateSysVarValues, - useResetConversationVar, - useResetToLastRunValue, -} from '@/service/use-workflow' -import { useCallback } from 'react' -import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' -import produce from 'immer' -import type { Node } from '@/app/components/workflow/types' -import { useNodesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-nodes-interactions-without-sync' -import { useEdgesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-edges-interactions-without-sync' +import { useStore } from '@/app/components/workflow/store' +import { useInspectVarsCrudCommon } from '../../workflow/hooks/use-inspect-vars-crud-common' import { useConfigsMap } from './use-configs-map' export const useInspectVarsCrud = () => { - const workflowStore = useWorkflowStore() const appId = useStore(s => s.appId) - const { conversationVarsUrl, systemVarsUrl } = useConfigsMap() - const invalidateConversationVarValues = useInvalidateConversationVarValues(conversationVarsUrl) - const { mutateAsync: doResetConversationVar } = useResetConversationVar(appId) - const { mutateAsync: doResetToLastRunValue } = useResetToLastRunValue(appId) - const invalidateSysVarValues = useInvalidateSysVarValues(systemVarsUrl) - - const { mutateAsync: doDeleteAllInspectorVars } = useDeleteAllInspectorVars(appId) - const { mutate: doDeleteNodeInspectorVars } = useDeleteNodeInspectorVars(appId) - const { mutate: doDeleteInspectVar } = useDeleteInspectVar(appId) - - const { mutateAsync: doEditInspectorVar } = useEditInspectorVar(appId) - const { handleCancelNodeSuccessStatus } = useNodesInteractionsWithoutSync() - const { handleEdgeCancelRunningStatus } = useEdgesInteractionsWithoutSync() - const getNodeInspectVars = useCallback((nodeId: string) => { - const { nodesWithInspectVars } = workflowStore.getState() - const node = nodesWithInspectVars.find(node => node.nodeId === nodeId) - return node - }, [workflowStore]) - - const getVarId = useCallback((nodeId: string, varName: string) => { - const node = getNodeInspectVars(nodeId) - if (!node) - return undefined - const varId = node.vars.find((varItem) => { - return varItem.selector[1] === varName - })?.id - return varId - }, [getNodeInspectVars]) - - const getInspectVar = useCallback((nodeId: string, name: string): VarInInspect | undefined => { - const node = getNodeInspectVars(nodeId) - if (!node) - return undefined - - const variable = node.vars.find((varItem) => { - return varItem.name === name - }) - return variable - }, [getNodeInspectVars]) - - const hasSetInspectVar = useCallback((nodeId: string, name: string, sysVars: VarInInspect[], conversationVars: VarInInspect[]) => { - const isEnv = isENV([nodeId]) - if (isEnv) // always have value - return true - const isSys = isSystemVar([nodeId]) - if (isSys) - return sysVars.some(varItem => varItem.selector?.[1]?.replace('sys.', '') === name) - const isChatVar = isConversationVar([nodeId]) - if (isChatVar) - return conversationVars.some(varItem => varItem.selector?.[1] === name) - return getInspectVar(nodeId, name) !== undefined - }, [getInspectVar]) - - const hasNodeInspectVars = useCallback((nodeId: string) => { - return !!getNodeInspectVars(nodeId) - }, [getNodeInspectVars]) - - const fetchInspectVarValue = useCallback(async (selector: ValueSelector) => { - const { - appId, - setNodeInspectVars, - } = workflowStore.getState() - const nodeId = selector[0] - const isSystemVar = nodeId === 'sys' - const isConversationVar = nodeId === 'conversation' - if (isSystemVar) { - invalidateSysVarValues() - return - } - if (isConversationVar) { - invalidateConversationVarValues() - return - } - const vars = await fetchNodeInspectVars(appId, nodeId) - setNodeInspectVars(nodeId, vars) - }, [workflowStore, invalidateSysVarValues, invalidateConversationVarValues]) - - // after last run would call this - const appendNodeInspectVars = useCallback((nodeId: string, payload: VarInInspect[], allNodes: Node[]) => { - const { - nodesWithInspectVars, - setNodesWithInspectVars, - } = workflowStore.getState() - const nodes = produce(nodesWithInspectVars, (draft) => { - const nodeInfo = allNodes.find(node => node.id === nodeId) - if (nodeInfo) { - const index = draft.findIndex(node => node.nodeId === nodeId) - if (index === -1) { - draft.unshift({ - nodeId, - nodeType: nodeInfo.data.type, - title: nodeInfo.data.title, - vars: payload, - nodePayload: nodeInfo.data, - }) - } - else { - draft[index].vars = payload - // put the node to the topAdd commentMore actions - draft.unshift(draft.splice(index, 1)[0]) - } - } - }) - setNodesWithInspectVars(nodes) - handleCancelNodeSuccessStatus(nodeId) - }, [workflowStore, handleCancelNodeSuccessStatus]) - - const hasNodeInspectVar = useCallback((nodeId: string, varId: string) => { - const { nodesWithInspectVars } = workflowStore.getState() - const targetNode = nodesWithInspectVars.find(item => item.nodeId === nodeId) - if(!targetNode || !targetNode.vars) - return false - return targetNode.vars.some(item => item.id === varId) - }, [workflowStore]) - - const deleteInspectVar = useCallback(async (nodeId: string, varId: string) => { - const { deleteInspectVar } = workflowStore.getState() - if(hasNodeInspectVar(nodeId, varId)) { - await doDeleteInspectVar(varId) - deleteInspectVar(nodeId, varId) - } - }, [doDeleteInspectVar, workflowStore, hasNodeInspectVar]) - - const resetConversationVar = useCallback(async (varId: string) => { - await doResetConversationVar(varId) - invalidateConversationVarValues() - }, [doResetConversationVar, invalidateConversationVarValues]) - - const deleteNodeInspectorVars = useCallback(async (nodeId: string) => { - const { deleteNodeInspectVars } = workflowStore.getState() - if (hasNodeInspectVars(nodeId)) { - await doDeleteNodeInspectorVars(nodeId) - deleteNodeInspectVars(nodeId) - } - }, [doDeleteNodeInspectorVars, workflowStore, hasNodeInspectVars]) - - const deleteAllInspectorVars = useCallback(async () => { - const { deleteAllInspectVars } = workflowStore.getState() - await doDeleteAllInspectorVars() - await invalidateConversationVarValues() - await invalidateSysVarValues() - deleteAllInspectVars() - handleEdgeCancelRunningStatus() - }, [doDeleteAllInspectorVars, invalidateConversationVarValues, invalidateSysVarValues, workflowStore, handleEdgeCancelRunningStatus]) - - const editInspectVarValue = useCallback(async (nodeId: string, varId: string, value: any) => { - const { setInspectVarValue } = workflowStore.getState() - await doEditInspectorVar({ - varId, - value, - }) - setInspectVarValue(nodeId, varId, value) - if (nodeId === VarInInspectType.conversation) - invalidateConversationVarValues() - if (nodeId === VarInInspectType.system) - invalidateSysVarValues() - }, [doEditInspectorVar, invalidateConversationVarValues, invalidateSysVarValues, workflowStore]) - - const renameInspectVarName = useCallback(async (nodeId: string, oldName: string, newName: string) => { - const { renameInspectVarName } = workflowStore.getState() - const varId = getVarId(nodeId, oldName) - if (!varId) - return - - const newSelector = [nodeId, newName] - await doEditInspectorVar({ - varId, - name: newName, - }) - renameInspectVarName(nodeId, varId, newSelector) - }, [doEditInspectorVar, getVarId, workflowStore]) - - const isInspectVarEdited = useCallback((nodeId: string, name: string) => { - const inspectVar = getInspectVar(nodeId, name) - if (!inspectVar) - return false - - return inspectVar.edited - }, [getInspectVar]) - - const resetToLastRunVar = useCallback(async (nodeId: string, varId: string) => { - const { resetToLastRunVar } = workflowStore.getState() - const isSysVar = nodeId === 'sys' - const data = await doResetToLastRunValue(varId) - - if(isSysVar) - invalidateSysVarValues() - else - resetToLastRunVar(nodeId, varId, data.value) - }, [doResetToLastRunValue, invalidateSysVarValues, workflowStore]) + const configsMap = useConfigsMap() + const apis = useInspectVarsCrudCommon({ + flowId: appId, + ...configsMap, + }) return { - hasNodeInspectVars, - hasSetInspectVar, - fetchInspectVarValue, - editInspectVarValue, - renameInspectVarName, - appendNodeInspectVars, - deleteInspectVar, - deleteNodeInspectorVars, - deleteAllInspectorVars, - isInspectVarEdited, - resetToLastRunVar, - invalidateSysVarValues, - resetConversationVar, - invalidateConversationVarValues, + ...apis, } } diff --git a/web/app/components/workflow-app/hooks/use-workflow-run.ts b/web/app/components/workflow-app/hooks/use-workflow-run.ts index 4c34d2ffb..c30321171 100644 --- a/web/app/components/workflow-app/hooks/use-workflow-run.ts +++ b/web/app/components/workflow-app/hooks/use-workflow-run.ts @@ -20,7 +20,8 @@ import type { VersionHistory } from '@/types/workflow' import { noop } from 'lodash-es' import { useNodesSyncDraft } from './use-nodes-sync-draft' import { useInvalidAllLastRun } from '@/service/use-workflow' -import { useSetWorkflowVarsWithValue } from './use-fetch-workflow-inspect-vars' +import { useSetWorkflowVarsWithValue } from '../../workflow/hooks/use-fetch-workflow-inspect-vars' +import { useConfigsMap } from './use-configs-map' export const useWorkflowRun = () => { const store = useStoreApi() @@ -32,7 +33,11 @@ export const useWorkflowRun = () => { const pathname = usePathname() const appId = useAppStore.getState().appDetail?.id const invalidAllLastRun = useInvalidAllLastRun(appId as string) - const { fetchInspectVars } = useSetWorkflowVarsWithValue() + const configsMap = useConfigsMap() + const { fetchInspectVars } = useSetWorkflowVarsWithValue({ + flowId: appId as string, + ...configsMap, + }) const { handleWorkflowStarted, diff --git a/web/app/components/workflow-app/hooks/use-fetch-workflow-inspect-vars.ts b/web/app/components/workflow/hooks/use-fetch-workflow-inspect-vars.ts similarity index 85% rename from web/app/components/workflow-app/hooks/use-fetch-workflow-inspect-vars.ts rename to web/app/components/workflow/hooks/use-fetch-workflow-inspect-vars.ts index 07580c097..27a9ea9d2 100644 --- a/web/app/components/workflow-app/hooks/use-fetch-workflow-inspect-vars.ts +++ b/web/app/components/workflow/hooks/use-fetch-workflow-inspect-vars.ts @@ -6,12 +6,20 @@ import type { Node } from '@/app/components/workflow/types' import { fetchAllInspectVars } from '@/service/workflow' import { useInvalidateConversationVarValues, useInvalidateSysVarValues } from '@/service/use-workflow' import { useNodesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-nodes-interactions-without-sync' -import { useConfigsMap } from './use-configs-map' -export const useSetWorkflowVarsWithValue = () => { +type Params = { + flowId: string + conversationVarsUrl: string + systemVarsUrl: string +} + +export const useSetWorkflowVarsWithValue = ({ + flowId, + conversationVarsUrl, + systemVarsUrl, +}: Params) => { const workflowStore = useWorkflowStore() const store = useStoreApi() - const { conversationVarsUrl, systemVarsUrl } = useConfigsMap() const invalidateConversationVarValues = useInvalidateConversationVarValues(conversationVarsUrl) const invalidateSysVarValues = useInvalidateSysVarValues(systemVarsUrl) const { handleCancelAllNodeSuccessStatus } = useNodesInteractionsWithoutSync() @@ -58,13 +66,12 @@ export const useSetWorkflowVarsWithValue = () => { }, [workflowStore, store]) const fetchInspectVars = useCallback(async () => { - const { appId } = workflowStore.getState() invalidateConversationVarValues() invalidateSysVarValues() - const data = await fetchAllInspectVars(appId) + const data = await fetchAllInspectVars(flowId) setInspectVarsToStore(data) handleCancelAllNodeSuccessStatus() // to make sure clear node output show the unset status - }, [workflowStore, invalidateConversationVarValues, invalidateSysVarValues, setInspectVarsToStore, handleCancelAllNodeSuccessStatus]) + }, [invalidateConversationVarValues, invalidateSysVarValues, flowId, setInspectVarsToStore, handleCancelAllNodeSuccessStatus]) return { fetchInspectVars, } diff --git a/web/app/components/workflow/hooks/use-inspect-vars-crud-common.ts b/web/app/components/workflow/hooks/use-inspect-vars-crud-common.ts new file mode 100644 index 000000000..ffcfd8166 --- /dev/null +++ b/web/app/components/workflow/hooks/use-inspect-vars-crud-common.ts @@ -0,0 +1,240 @@ +import { fetchNodeInspectVars } from '@/service/workflow' +import { useWorkflowStore } from '@/app/components/workflow/store' +import type { ValueSelector } from '@/app/components/workflow/types' +import type { VarInInspect } from '@/types/workflow' +import { VarInInspectType } from '@/types/workflow' +import { + useDeleteAllInspectorVars, + useDeleteInspectVar, + useDeleteNodeInspectorVars, + useEditInspectorVar, + useInvalidateConversationVarValues, + useInvalidateSysVarValues, + useResetConversationVar, + useResetToLastRunValue, +} from '@/service/use-workflow' +import { useCallback } from 'react' +import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' +import produce from 'immer' +import type { Node } from '@/app/components/workflow/types' +import { useNodesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-nodes-interactions-without-sync' +import { useEdgesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-edges-interactions-without-sync' + +type Params = { + flowId: string + conversationVarsUrl: string + systemVarsUrl: string +} +export const useInspectVarsCrudCommon = ({ + flowId, + conversationVarsUrl, + systemVarsUrl, +}: Params) => { + const workflowStore = useWorkflowStore() + const invalidateConversationVarValues = useInvalidateConversationVarValues(conversationVarsUrl!) + const { mutateAsync: doResetConversationVar } = useResetConversationVar(flowId) + const { mutateAsync: doResetToLastRunValue } = useResetToLastRunValue(flowId) + const invalidateSysVarValues = useInvalidateSysVarValues(systemVarsUrl!) + + const { mutateAsync: doDeleteAllInspectorVars } = useDeleteAllInspectorVars(flowId) + const { mutate: doDeleteNodeInspectorVars } = useDeleteNodeInspectorVars(flowId) + const { mutate: doDeleteInspectVar } = useDeleteInspectVar(flowId) + + const { mutateAsync: doEditInspectorVar } = useEditInspectorVar(flowId) + const { handleCancelNodeSuccessStatus } = useNodesInteractionsWithoutSync() + const { handleEdgeCancelRunningStatus } = useEdgesInteractionsWithoutSync() + const getNodeInspectVars = useCallback((nodeId: string) => { + const { nodesWithInspectVars } = workflowStore.getState() + const node = nodesWithInspectVars.find(node => node.nodeId === nodeId) + return node + }, [workflowStore]) + + const getVarId = useCallback((nodeId: string, varName: string) => { + const node = getNodeInspectVars(nodeId) + if (!node) + return undefined + const varId = node.vars.find((varItem) => { + return varItem.selector[1] === varName + })?.id + return varId + }, [getNodeInspectVars]) + + const getInspectVar = useCallback((nodeId: string, name: string): VarInInspect | undefined => { + const node = getNodeInspectVars(nodeId) + if (!node) + return undefined + + const variable = node.vars.find((varItem) => { + return varItem.name === name + }) + return variable + }, [getNodeInspectVars]) + + const hasSetInspectVar = useCallback((nodeId: string, name: string, sysVars: VarInInspect[], conversationVars: VarInInspect[]) => { + const isEnv = isENV([nodeId]) + if (isEnv) // always have value + return true + const isSys = isSystemVar([nodeId]) + if (isSys) + return sysVars.some(varItem => varItem.selector?.[1]?.replace('sys.', '') === name) + const isChatVar = isConversationVar([nodeId]) + if (isChatVar) + return conversationVars.some(varItem => varItem.selector?.[1] === name) + return getInspectVar(nodeId, name) !== undefined + }, [getInspectVar]) + + const hasNodeInspectVars = useCallback((nodeId: string) => { + return !!getNodeInspectVars(nodeId) + }, [getNodeInspectVars]) + + const fetchInspectVarValue = useCallback(async (selector: ValueSelector) => { + const { + appId, + setNodeInspectVars, + } = workflowStore.getState() + const nodeId = selector[0] + const isSystemVar = nodeId === 'sys' + const isConversationVar = nodeId === 'conversation' + if (isSystemVar) { + invalidateSysVarValues() + return + } + if (isConversationVar) { + invalidateConversationVarValues() + return + } + const vars = await fetchNodeInspectVars(appId, nodeId) + setNodeInspectVars(nodeId, vars) + }, [workflowStore, invalidateSysVarValues, invalidateConversationVarValues]) + + // after last run would call this + const appendNodeInspectVars = useCallback((nodeId: string, payload: VarInInspect[], allNodes: Node[]) => { + const { + nodesWithInspectVars, + setNodesWithInspectVars, + } = workflowStore.getState() + const nodes = produce(nodesWithInspectVars, (draft) => { + const nodeInfo = allNodes.find(node => node.id === nodeId) + if (nodeInfo) { + const index = draft.findIndex(node => node.nodeId === nodeId) + if (index === -1) { + draft.unshift({ + nodeId, + nodeType: nodeInfo.data.type, + title: nodeInfo.data.title, + vars: payload, + nodePayload: nodeInfo.data, + }) + } + else { + draft[index].vars = payload + // put the node to the topAdd commentMore actions + draft.unshift(draft.splice(index, 1)[0]) + } + } + }) + setNodesWithInspectVars(nodes) + handleCancelNodeSuccessStatus(nodeId) + }, [workflowStore, handleCancelNodeSuccessStatus]) + + const hasNodeInspectVar = useCallback((nodeId: string, varId: string) => { + const { nodesWithInspectVars } = workflowStore.getState() + const targetNode = nodesWithInspectVars.find(item => item.nodeId === nodeId) + if(!targetNode || !targetNode.vars) + return false + return targetNode.vars.some(item => item.id === varId) + }, [workflowStore]) + + const deleteInspectVar = useCallback(async (nodeId: string, varId: string) => { + const { deleteInspectVar } = workflowStore.getState() + if(hasNodeInspectVar(nodeId, varId)) { + await doDeleteInspectVar(varId) + deleteInspectVar(nodeId, varId) + } + }, [doDeleteInspectVar, workflowStore, hasNodeInspectVar]) + + const resetConversationVar = useCallback(async (varId: string) => { + await doResetConversationVar(varId) + invalidateConversationVarValues() + }, [doResetConversationVar, invalidateConversationVarValues]) + + const deleteNodeInspectorVars = useCallback(async (nodeId: string) => { + const { deleteNodeInspectVars } = workflowStore.getState() + if (hasNodeInspectVars(nodeId)) { + await doDeleteNodeInspectorVars(nodeId) + deleteNodeInspectVars(nodeId) + } + }, [doDeleteNodeInspectorVars, workflowStore, hasNodeInspectVars]) + + const deleteAllInspectorVars = useCallback(async () => { + const { deleteAllInspectVars } = workflowStore.getState() + await doDeleteAllInspectorVars() + await invalidateConversationVarValues() + await invalidateSysVarValues() + deleteAllInspectVars() + handleEdgeCancelRunningStatus() + }, [doDeleteAllInspectorVars, invalidateConversationVarValues, invalidateSysVarValues, workflowStore, handleEdgeCancelRunningStatus]) + + const editInspectVarValue = useCallback(async (nodeId: string, varId: string, value: any) => { + const { setInspectVarValue } = workflowStore.getState() + await doEditInspectorVar({ + varId, + value, + }) + setInspectVarValue(nodeId, varId, value) + if (nodeId === VarInInspectType.conversation) + invalidateConversationVarValues() + if (nodeId === VarInInspectType.system) + invalidateSysVarValues() + }, [doEditInspectorVar, invalidateConversationVarValues, invalidateSysVarValues, workflowStore]) + + const renameInspectVarName = useCallback(async (nodeId: string, oldName: string, newName: string) => { + const { renameInspectVarName } = workflowStore.getState() + const varId = getVarId(nodeId, oldName) + if (!varId) + return + + const newSelector = [nodeId, newName] + await doEditInspectorVar({ + varId, + name: newName, + }) + renameInspectVarName(nodeId, varId, newSelector) + }, [doEditInspectorVar, getVarId, workflowStore]) + + const isInspectVarEdited = useCallback((nodeId: string, name: string) => { + const inspectVar = getInspectVar(nodeId, name) + if (!inspectVar) + return false + + return inspectVar.edited + }, [getInspectVar]) + + const resetToLastRunVar = useCallback(async (nodeId: string, varId: string) => { + const { resetToLastRunVar } = workflowStore.getState() + const isSysVar = nodeId === 'sys' + const data = await doResetToLastRunValue(varId) + + if(isSysVar) + invalidateSysVarValues() + else + resetToLastRunVar(nodeId, varId, data.value) + }, [doResetToLastRunValue, invalidateSysVarValues, workflowStore]) + + return { + hasNodeInspectVars, + hasSetInspectVar, + fetchInspectVarValue, + editInspectVarValue, + renameInspectVarName, + appendNodeInspectVars, + deleteInspectVar, + deleteNodeInspectorVars, + deleteAllInspectorVars, + isInspectVarEdited, + resetToLastRunVar, + invalidateSysVarValues, + resetConversationVar, + invalidateConversationVarValues, + } +}