import { fetchNodeInspectVars } from '@/service/workflow' import { useStore, useWorkflowStore } from '../store' import type { ValueSelector } from '../types' import type { VarInInspect } from '@/types/workflow' import { VarInInspectType } from '@/types/workflow' import { useConversationVarValues, useDeleteAllInspectorVars, useDeleteInspectVar, useDeleteNodeInspectorVars, useEditInspectorVar, useInvalidateConversationVarValues, useInvalidateSysVarValues, useLastRun, useResetConversationVar, useResetToLastRunValue, useSysVarValues, } from '@/service/use-workflow' import { useCallback, useEffect, useState } from 'react' import { isConversationVar, isENV, isSystemVar } from '../nodes/_base/components/variable/utils' import produce from 'immer' import type { Node } from '@/app/components/workflow/types' import { useNodesInteractionsWithoutSync } from './use-nodes-interactions-without-sync' import { useEdgesInteractionsWithoutSync } from './use-edges-interactions-without-sync' const useInspectVarsCrud = () => { const workflowStore = useWorkflowStore() const nodesWithInspectVars = useStore(s => s.nodesWithInspectVars) const { appId, setNodeInspectVars, setInspectVarValue, renameInspectVarName: renameInspectVarNameInStore, deleteAllInspectVars: deleteAllInspectVarsInStore, deleteNodeInspectVars: deleteNodeInspectVarsInStore, deleteInspectVar: deleteInspectVarInStore, setNodesWithInspectVars, resetToLastRunVar: resetToLastRunVarInStore, } = workflowStore.getState() const { data: conversationVars } = useConversationVarValues(appId) const invalidateConversationVarValues = useInvalidateConversationVarValues(appId) const { mutateAsync: doResetConversationVar } = useResetConversationVar(appId) const { mutateAsync: doResetToLastRunValue } = useResetToLastRunValue(appId) const { data: systemVars } = useSysVarValues(appId) const invalidateSysVarValues = useInvalidateSysVarValues(appId) 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 node = nodesWithInspectVars.find(node => node.nodeId === nodeId) return node }, [nodesWithInspectVars]) 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 = async (selector: ValueSelector) => { 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) } // after last run would call this const appendNodeInspectVars = (nodeId: string, payload: VarInInspect[], allNodes: Node[]) => { 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.push({ nodeId, nodeType: nodeInfo.data.type, title: nodeInfo.data.title, vars: payload, }) } else { draft[index].vars = payload } } }) setNodesWithInspectVars(nodes) handleCancelNodeSuccessStatus(nodeId) } const hasNodeInspectVar = (nodeId: string, varId: string) => { const targetNode = nodesWithInspectVars.find(item => item.nodeId === nodeId) if(!targetNode || !targetNode.vars) return false return targetNode.vars.some(item => item.id === varId) } const deleteInspectVar = async (nodeId: string, varId: string) => { if(hasNodeInspectVar(nodeId, varId)) { await doDeleteInspectVar(varId) deleteInspectVarInStore(nodeId, varId) } } const resetConversationVar = async (varId: string) => { await doResetConversationVar(varId) invalidateConversationVarValues() } const deleteNodeInspectorVars = async (nodeId: string) => { if (hasNodeInspectVars(nodeId)) { await doDeleteNodeInspectorVars(nodeId) deleteNodeInspectVarsInStore(nodeId) } } const deleteAllInspectorVars = async () => { await doDeleteAllInspectorVars() await invalidateConversationVarValues() await invalidateSysVarValues() deleteAllInspectVarsInStore() handleEdgeCancelRunningStatus() } const editInspectVarValue = useCallback(async (nodeId: string, varId: string, value: any) => { await doEditInspectorVar({ varId, value, }) setInspectVarValue(nodeId, varId, value) if (nodeId === VarInInspectType.conversation) invalidateConversationVarValues() if (nodeId === VarInInspectType.system) invalidateSysVarValues() }, [doEditInspectorVar, invalidateConversationVarValues, invalidateSysVarValues, setInspectVarValue]) const [currNodeId, setCurrNodeId] = useState(null) const [currEditVarId, setCurrEditVarId] = useState(null) const { data } = useLastRun(appId, currNodeId || '', !!currNodeId) useEffect(() => { if (data && currNodeId && currEditVarId) { const inspectVar = getNodeInspectVars(currNodeId)?.vars?.find(item => item.id === currEditVarId) resetToLastRunVarInStore(currNodeId, currEditVarId, data.outputs?.[inspectVar?.selector?.[1] || '']) } }, [data, currNodeId, currEditVarId, getNodeInspectVars, editInspectVarValue, resetToLastRunVarInStore]) const renameInspectVarName = async (nodeId: string, oldName: string, newName: string) => { const varId = getVarId(nodeId, oldName) if (!varId) return const newSelector = [nodeId, newName] await doEditInspectorVar({ varId, name: newName, }) renameInspectVarNameInStore(nodeId, varId, newSelector) } const isInspectVarEdited = useCallback((nodeId: string, name: string) => { const inspectVar = getInspectVar(nodeId, name) if (!inspectVar) return false return inspectVar.edited }, [getInspectVar]) const resetToLastRunVar = async (nodeId: string, varId: string) => { await doResetToLastRunValue(varId) setCurrNodeId(nodeId) setCurrEditVarId(varId) } return { conversationVars: conversationVars || [], systemVars: systemVars || [], nodesWithInspectVars, hasNodeInspectVars, hasSetInspectVar, fetchInspectVarValue, editInspectVarValue, renameInspectVarName, appendNodeInspectVars, deleteInspectVar, deleteNodeInspectorVars, deleteAllInspectorVars, isInspectVarEdited, resetToLastRunVar, invalidateSysVarValues, resetConversationVar, invalidateConversationVarValues, } } export default useInspectVarsCrud