chore: change var inspect slice

This commit is contained in:
Joel 2025-04-23 17:57:05 +08:00
parent 1593ef0640
commit 8cd8da99d6
8 changed files with 188 additions and 110 deletions

View File

@ -2,11 +2,11 @@ import { useWorkflowStore } from '../store'
const useCurrentVars = () => {
const workflowStore = useWorkflowStore()
const {
currentNodes,
getCurrentVar,
setCurrentVar,
clearCurrentVars,
clearCurrentNodeVars,
nodes: currentNodes,
getInspectVar: getCurrentVar,
setInspectVar: setCurrentVar,
clearInspectVars: clearCurrentVars,
clearNodeInspectVars: clearCurrentNodeVars,
getLastRunVar,
getLastRunInfos,
} = workflowStore.getState()

View File

@ -5,13 +5,19 @@ import { NodeRunningStatus } from '@/app/components/workflow/types'
import type { FC } from 'react'
import React, { useEffect, useState } from 'react'
import NoData from './no-data'
import { useLastRun } from '@/service/use-workflow'
import Loading from '@/app/components/base/loading'
type Props = {
isDataFromHistory: boolean
appId: string
nodeId: string
runningStatus: NodeRunningStatus
runningStatus?: NodeRunningStatus
}
const LastRun: FC<Props> = ({
isDataFromHistory,
appId,
nodeId,
runningStatus,
}) => {
@ -20,22 +26,31 @@ const LastRun: FC<Props> = ({
const {
getLastRunNodeInfo,
} = workflowStore.getState()
const [runResult, setRunResult] = useState(getLastRunNodeInfo(nodeId))
const { data: runResultFromHistory, isFetching } = useLastRun(appId, nodeId, isDataFromHistory)
const [runResultFromSingleRun, setRunResult] = useState(isDataFromHistory ? getLastRunNodeInfo(nodeId) : null)
const runResult = isDataFromHistory ? runResultFromHistory : runResultFromSingleRun
const isRunning = runningStatus === NodeRunningStatus.Running
// get data from current running result
useEffect(() => {
if (isDataFromHistory)
return
setRunResult(getLastRunNodeInfo(nodeId))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [runningStatus])
}, [runningStatus, isDataFromHistory])
const handleSingleRun = () => {
console.log('run')
}
if (isDataFromHistory && isFetching)
return <Loading />
if (isRunning)
return <ResultPanel status='running' showSteps={false} />
if (!runResult) {
if (!runResultFromSingleRun) {
return (
<NoData onSingleRun={handleSingleRun} />
)

View File

@ -156,7 +156,7 @@ const useOneStepRun = <T>({
const workflowStore = useWorkflowStore()
const {
setLastRunNodeInfo,
setCurrentNodeVars,
setNodeInspectVars: setCurrentNodeVars,
setShowSingleRunPanel,
} = workflowStore.getState()
const [runResult, doSetRunResult] = useState<NodeRunResult | null>(null)

View File

@ -1,96 +0,0 @@
import type { StateCreator } from 'zustand'
import produce from 'immer'
import type { NodeTracing } from '@/types/workflow'
// TODO: Missing var type
type NodeVars = NodeTracing
type CurrentVarsState = {
currentNodes: NodeVars[]
}
type CurrentVarsActions = {
setCurrentVars: (vars: NodeVars[]) => void
getCurrentVars: () => NodeVars[]
clearCurrentVars: () => void
setCurrentNodeVars: (nodeId: string, payload: NodeVars) => void
clearCurrentNodeVars: (nodeId: string) => void
getCurrentNodeVars: (nodeId: string) => NodeVars | undefined
hasCurrentNodeVars: (nodeId: string) => boolean
setCurrentVar: (nodeId: string, key: string, value: any) => void
getCurrentVar: (nodeId: string, key: string) => any
}
export type CurrentVarsSliceShape = CurrentVarsState & CurrentVarsActions
export const createCurrentVarsSlice: StateCreator<CurrentVarsSliceShape> = (set, get) => {
return ({
currentNodes: [],
setCurrentVars: (vars) => {
set(() => ({
currentNodes: vars,
}))
},
getCurrentVars: () => {
return get().currentNodes
},
clearCurrentVars: () => {
set(() => ({
currentNodes: [],
}))
},
setCurrentNodeVars: (nodeId, payload) => {
set((state) => {
const prevNodes = state.currentNodes
const nodes = produce(prevNodes, (draft) => {
const index = prevNodes.findIndex(node => node.id === nodeId)
if (index === -1)
draft.push(payload)
else
draft[index] = payload
})
return {
currentNodes: nodes,
}
})
},
clearCurrentNodeVars: (nodeId) => {
set(produce((state: CurrentVarsSliceShape) => {
const nodes = state.currentNodes.filter(node => node.node_id !== nodeId)
state.currentNodes = nodes
},
))
},
getCurrentNodeVars: (nodeId) => {
const nodes = get().currentNodes
return nodes.find(node => node.node_id === nodeId)
},
hasCurrentNodeVars: (nodeId) => {
return !!get().getCurrentNodeVars(nodeId)
},
setCurrentVar: (nodeId, key, value) => {
set(produce((state: CurrentVarsSliceShape) => {
const nodes = state.currentNodes.map((node) => {
if (node.id === nodeId) {
return produce(node, (draft) => {
if (!draft.outputs)
draft.outputs = {}
draft.outputs[key] = value
})
}
return node
})
state.currentNodes = nodes
}))
},
getCurrentVar(nodeId, key) {
const node = get().getCurrentNodeVars(nodeId)
if (!node)
return undefined
const variable = node.outputs?.[key]
return variable
},
})
}

View File

@ -30,8 +30,8 @@ import type { WorkflowSliceShape } from './workflow-slice'
import { createWorkflowSlice } from './workflow-slice'
import type { LastRunSliceShape } from './last-run-slice'
import { createLastRunSlice } from './last-run-slice'
import type { CurrentVarsSliceShape } from './current-vars-slice'
import { createCurrentVarsSlice } from './current-vars-slice'
import type { CurrentVarsSliceShape } from './var-inspect-slice'
import { createInspectVarsSlice } from './var-inspect-slice'
import { WorkflowContext } from '@/app/components/workflow/context'
import type { LayoutSliceShape } from './layout-slice'
@ -75,7 +75,7 @@ export const createWorkflowStore = (params: CreateWorkflowStoreParams) => {
...createWorkflowDraftSlice(...args),
...createWorkflowSlice(...args),
...createLastRunSlice(...args),
...createCurrentVarsSlice(...args),
...createInspectVarsSlice(...args),
...createLayoutSlice(...args),
...(injectWorkflowStoreSliceFn?.(...args) || {} as WorkflowAppSliceShape),
}))

View File

@ -0,0 +1,96 @@
import type { StateCreator } from 'zustand'
import produce from 'immer'
import type { NodeWithVar, VarInInspect } from '@/types/workflow'
import type { ValueSelector } from '../../types'
type InspectVarsState = {
currentFocusNodeId: string | null
nodes: NodeWithVar[] // the nodes have data
conversationVars: VarInInspect[]
}
type InspectVarsActions = {
getAllInspectVars: () => NodeWithVar[]
clearInspectVars: () => void
setNodeInspectVars: (nodeId: string, payload: NodeWithVar) => void
clearNodeInspectVars: (nodeId: string) => void
getNodeInspectVars: (nodeId: string) => NodeWithVar | undefined
hasNodeInspectVars: (nodeId: string) => boolean
setInspectVar: (nodeId: string, selector: ValueSelector, value: any) => void
getInspectVar: (nodeId: string, selector: ValueSelector) => any
}
export type CurrentVarsSliceShape = InspectVarsState & InspectVarsActions
export const createInspectVarsSlice: StateCreator<CurrentVarsSliceShape> = (set, get) => {
return ({
currentFocusNodeId: null,
nodes: [],
conversationVars: [],
getAllInspectVars: () => {
return get().nodes
},
clearInspectVars: () => {
set(() => ({
nodes: [],
}))
},
setNodeInspectVars: (nodeId, payload) => {
set((state) => {
const prevNodes = state.nodes
const nodes = produce(prevNodes, (draft) => {
const index = prevNodes.findIndex(node => node.nodeId === nodeId)
if (index === -1)
draft.push(payload)
else
draft[index] = payload
})
return {
nodes,
}
})
},
clearNodeInspectVars: (nodeId) => {
set(produce((state: CurrentVarsSliceShape) => {
const nodes = state.nodes.filter(node => node.nodeId !== nodeId)
state.nodes = nodes
},
))
},
getNodeInspectVars: (nodeId) => {
const nodes = get().nodes
return nodes.find(node => node.nodeId === nodeId)
},
hasNodeInspectVars: (nodeId) => {
return !!get().getNodeInspectVars(nodeId)
},
setInspectVar: (nodeId, selector, value) => {
set(produce((state: CurrentVarsSliceShape) => {
const nodes = state.nodes.map((node) => {
if (node.nodeId === nodeId) {
return produce(node, (draft) => {
const needChangeVarIndex = draft.vars.findIndex((varItem) => {
return varItem.selector.join('.') === selector.join('.')
})
if (needChangeVarIndex !== -1)
draft.vars[needChangeVarIndex].value = value
})
}
return node
})
state.nodes = nodes
}))
},
getInspectVar(nodeId, key) {
const node = get().getNodeInspectVars(nodeId)
if (!node)
return undefined
const variable = node.vars.find((varItem) => {
return varItem.selector.join('.') === key.join('.')
})?.value
return variable
},
})
}

View File

@ -4,12 +4,14 @@ import type {
FetchWorkflowDraftPageParams,
FetchWorkflowDraftPageResponse,
FetchWorkflowDraftResponse,
NodeTracing,
PublishWorkflowParams,
UpdateWorkflowParams,
WorkflowConfigResponse,
} from '@/types/workflow'
import type { CommonResponse } from '@/models/common'
import { useReset } from './use-base'
import { sleep } from '@/utils'
const NAME_SPACE = 'workflow'
@ -85,3 +87,39 @@ export const usePublishWorkflow = (appId: string) => {
}),
})
}
export const useLastRun = (appID: string, nodeId: string, enabled: boolean) => {
return useQuery<NodeTracing>({
enabled,
queryKey: [NAME_SPACE, 'last-run', appID, nodeId],
queryFn: async () => {
// TODO: mock data
await sleep(1000)
return Promise.resolve({
node_id: nodeId,
status: 'success',
node_type: 'llm',
title: 'LLM',
inputs: null,
outputs: {
text: '"abc" is a simple sequence of three letters. Is there anything specific you\'d like to know about it, or are you just testing the system? \n\nLet me know if you have any other questions or tasks! 😊 \n',
usage: {
prompt_tokens: 3,
prompt_unit_price: '0',
prompt_price_unit: '0.000001',
prompt_price: '0',
completion_tokens: 48,
completion_unit_price: '0',
completion_price_unit: '0.000001',
completion_price: '0',
total_tokens: 51,
total_price: '0',
currency: 'USD',
latency: 0.7095853444188833,
},
finish_reason: '1',
},
} as any)
},
})
}

View File

@ -1,5 +1,5 @@
import type { Viewport } from 'reactflow'
import type { BlockEnum, ConversationVariable, Edge, EnvironmentVariable, InputVar, Node, Variable } from '@/app/components/workflow/types'
import type { BlockEnum, ConversationVariable, Edge, EnvironmentVariable, InputVar, Node, ValueSelector, VarType, Variable } from '@/app/components/workflow/types'
import type { TransferMethod } from '@/types/app'
import type { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types'
import type { BeforeRunFormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form'
@ -370,3 +370,28 @@ export type PanelProps = {
}
export type NodeRunResult = NodeTracing
// Var Inspect
export enum VarInInspectType {
conversation = 'conversation',
environment = 'environment',
node = 'node',
}
export type VarInInspect = {
id: string
type: VarInInspectType
name: string
description: string
selector: ValueSelector
value_type: VarType
value: any
edited: boolean
}
export type NodeWithVar = {
nodeId: string
nodeType: BlockEnum
title: string
vars: VarInInspect[]
}