feat(trigger): add run all triggers test-run and implement TriggerType enum

This commit is contained in:
zhsama 2025-10-17 14:55:46 +08:00
parent bc0d5f4e41
commit 5b884d750f
8 changed files with 119 additions and 35 deletions

View File

@ -69,6 +69,7 @@ const WorkflowMain = ({
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
} = useWorkflowStartRun()
const availableNodesMetaData = useAvailableNodesMetaData()
const { getWorkflowRunAndTraceUrl } = useGetRunAndTraceUrl()
@ -114,6 +115,7 @@ const WorkflowMain = ({
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
availableNodesMetaData,
getWorkflowRunAndTraceUrl,
exportCheck,
@ -150,6 +152,7 @@ const WorkflowMain = ({
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
availableNodesMetaData,
getWorkflowRunAndTraceUrl,
exportCheck,

View File

@ -25,13 +25,15 @@ import { useSetWorkflowVarsWithValue } from '../../workflow/hooks/use-fetch-work
import { useConfigsMap } from './use-configs-map'
import { API_PREFIX } from '@/config'
import { ContentType, getAccessToken, getBaseOptions } from '@/service/fetch'
import { TriggerType } from '@/app/components/workflow/header/test-run-menu'
type HandleRunMode = 'default' | 'schedule' | 'webhook' | 'plugin'
type HandleRunMode = TriggerType
type HandleRunOptions = {
mode?: HandleRunMode
scheduleNodeId?: string
webhookNodeId?: string
pluginNodeId?: string
allNodeIds?: string[]
}
export const useWorkflowRun = () => {
@ -126,7 +128,7 @@ export const useWorkflowRun = () => {
callback?: IOtherOptions,
options?: HandleRunOptions,
) => {
const runMode: HandleRunMode = options?.mode ?? 'default'
const runMode: HandleRunMode = options?.mode ?? TriggerType.UserInput
const resolvedParams = params ?? {}
const {
getNodes,
@ -170,13 +172,20 @@ export const useWorkflowRun = () => {
const isInWorkflowDebug = appDetail?.mode === 'workflow'
let url = ''
if (runMode === 'plugin' || runMode === 'webhook' || runMode === 'schedule') {
if (runMode === TriggerType.Plugin || runMode === TriggerType.Webhook || runMode === TriggerType.Schedule) {
if (!appDetail?.id) {
console.error('handleRun: missing app id for trigger plugin run')
return
}
url = `/apps/${appDetail.id}/workflows/draft/trigger/run`
}
else if (runMode === TriggerType.All) {
if (!appDetail?.id) {
console.error('handleRun: missing app id for trigger run all')
return
}
url = `/apps/${appDetail.id}/workflows/draft/trigger/run-all`
}
else if (appDetail?.mode === 'advanced-chat') {
url = `/apps/${appDetail.id}/advanced-chat/workflows/draft/run`
}
@ -186,36 +195,44 @@ export const useWorkflowRun = () => {
let requestBody = {}
if (runMode === 'schedule')
if (runMode === TriggerType.Schedule)
requestBody = { node_id: options?.scheduleNodeId }
else if (runMode === 'webhook')
else if (runMode === TriggerType.Webhook)
requestBody = { node_id: options?.webhookNodeId }
else if (runMode === 'plugin')
else if (runMode === TriggerType.Plugin)
requestBody = { node_id: options?.pluginNodeId }
else if (runMode === TriggerType.All)
requestBody = { node_ids: options?.allNodeIds }
else
requestBody = resolvedParams
if (!url)
return
if (runMode === 'schedule' && !options?.scheduleNodeId) {
if (runMode === TriggerType.Schedule && !options?.scheduleNodeId) {
console.error('handleRun: schedule trigger run requires node id')
return
}
if (runMode === 'webhook' && !options?.webhookNodeId) {
if (runMode === TriggerType.Webhook && !options?.webhookNodeId) {
console.error('handleRun: webhook trigger run requires node id')
return
}
if (runMode === 'plugin' && !options?.pluginNodeId) {
if (runMode === TriggerType.Plugin && !options?.pluginNodeId) {
console.error('handleRun: plugin trigger run requires node id')
return
}
if (runMode === TriggerType.All && !options?.allNodeIds && options?.allNodeIds?.length === 0) {
console.error('handleRun: all trigger run requires node ids')
return
}
abortControllerRef.current?.abort()
abortControllerRef.current = null
@ -227,7 +244,7 @@ export const useWorkflowRun = () => {
setListeningTriggerNodeId,
} = workflowStore.getState()
if (runMode === 'webhook' || runMode === 'plugin') {
if (runMode === TriggerType.Webhook || runMode === TriggerType.Plugin || runMode === TriggerType.All) {
setIsListening(true)
setShowVariableInspectPanel(true)
setWorkflowRunningData({
@ -430,7 +447,7 @@ export const useWorkflowRun = () => {
}, { once: true })
})
const runTriggerDebug = async (debugType: 'webhook' | 'plugin') => {
const runTriggerDebug = async (debugType: TriggerType.Webhook | TriggerType.Plugin | TriggerType.All) => {
const urlWithPrefix = (url.startsWith('http://') || url.startsWith('https://'))
? url
: `${API_PREFIX}${url.startsWith('/') ? url : `/${url}`}`
@ -438,13 +455,13 @@ export const useWorkflowRun = () => {
const controller = new AbortController()
abortControllerRef.current = controller
const controllerKey = debugType === 'webhook'
const controllerKey = debugType === TriggerType.Webhook
? '__webhookDebugAbortController'
: '__pluginDebugAbortController'
;(window as any)[controllerKey] = controller
const debugLabel = debugType === 'webhook' ? 'Webhook' : 'Plugin'
const debugLabel = debugType === TriggerType.Webhook ? 'Webhook' : debugType === TriggerType.Plugin ? 'Plugin' : 'All'
const poll = async (): Promise<void> => {
try {
@ -559,13 +576,18 @@ export const useWorkflowRun = () => {
await poll()
}
if (runMode === 'webhook') {
await runTriggerDebug('webhook')
if (runMode === TriggerType.Webhook) {
await runTriggerDebug(TriggerType.Webhook)
return
}
if (runMode === 'plugin') {
await runTriggerDebug('plugin')
if (runMode === TriggerType.Plugin) {
await runTriggerDebug(TriggerType.Plugin)
return
}
if (runMode === TriggerType.All) {
await runTriggerDebug(TriggerType.All)
return
}

View File

@ -12,6 +12,7 @@ import {
useNodesSyncDraft,
useWorkflowRun,
} from '.'
import { TriggerType } from '@/app/components/workflow/header/test-run-menu'
export const useWorkflowStartRun = () => {
const store = useStoreApi()
@ -102,7 +103,7 @@ export const useWorkflowStartRun = () => {
{},
undefined,
{
mode: 'schedule',
mode: TriggerType.Schedule,
scheduleNodeId: nodeId,
},
)
@ -150,7 +151,7 @@ export const useWorkflowStartRun = () => {
{ node_id: nodeId },
undefined,
{
mode: 'webhook',
mode: TriggerType.Webhook,
webhookNodeId: nodeId,
},
)
@ -195,12 +196,43 @@ export const useWorkflowStartRun = () => {
{ node_id: nodeId },
undefined,
{
mode: 'plugin',
mode: TriggerType.Plugin,
pluginNodeId: nodeId,
},
)
}, [store, workflowStore, handleRun, doSyncWorkflowDraft])
const handleWorkflowRunAllTriggersInWorkflow = useCallback(async (nodeIds: string[]) => {
if (!nodeIds.length)
return
const {
workflowRunningData,
showDebugAndPreviewPanel,
setShowDebugAndPreviewPanel,
setShowInputsPanel,
setShowEnvPanel,
} = workflowStore.getState()
if (workflowRunningData?.result.status === WorkflowRunningStatus.Running)
return
setShowEnvPanel(false)
setShowInputsPanel(false)
if (!showDebugAndPreviewPanel)
setShowDebugAndPreviewPanel(true)
await doSyncWorkflowDraft()
handleRun(
{ node_ids: nodeIds },
undefined,
{
mode: TriggerType.All,
allNodeIds: nodeIds,
},
)
}, [store, workflowStore, handleRun, doSyncWorkflowDraft])
const handleWorkflowStartRunInChatflow = useCallback(async () => {
const {
showDebugAndPreviewPanel,
@ -235,5 +267,6 @@ export const useWorkflowStartRun = () => {
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
}
}

View File

@ -10,7 +10,7 @@ import cn from '@/utils/classnames'
import { RiLoader2Line, RiPlayLargeLine } from '@remixicon/react'
import { StopCircle } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import { useDynamicTestRunOptions } from '../hooks/use-dynamic-test-run-options'
import TestRunMenu, { type TestRunMenuRef, type TriggerOption } from './test-run-menu'
import TestRunMenu, { type TestRunMenuRef, type TriggerOption, TriggerType } from './test-run-menu'
type RunModeProps = {
text?: string
@ -25,6 +25,7 @@ const RunMode = ({
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
} = useWorkflowStartRun()
const { handleStopRun } = useWorkflowRun()
const { validateBeforeRun } = useWorkflowRunValidation()
@ -57,20 +58,25 @@ const RunMode = ({
if (!validateBeforeRun())
return
if (option.type === 'user_input') {
if (option.type === TriggerType.UserInput) {
handleWorkflowStartRunInWorkflow()
}
else if (option.type === 'schedule') {
else if (option.type === TriggerType.Schedule) {
handleWorkflowTriggerScheduleRunInWorkflow(option.nodeId)
}
else if (option.type === 'webhook') {
else if (option.type === TriggerType.Webhook) {
if (option.nodeId)
handleWorkflowTriggerWebhookRunInWorkflow({ nodeId: option.nodeId })
}
else if (option.type === 'plugin') {
else if (option.type === TriggerType.Plugin) {
if (option.nodeId)
handleWorkflowTriggerPluginRunInWorkflow(option.nodeId)
}
else if (option.type === TriggerType.All) {
const targetNodeIds = option.relatedNodeIds?.filter(Boolean)
if (targetNodeIds && targetNodeIds.length > 0)
handleWorkflowRunAllTriggersInWorkflow(targetNodeIds)
}
else {
// Placeholder for trigger-specific execution logic for schedule, webhook, plugin types
console.log('TODO: Handle trigger execution for type:', option.type, 'nodeId:', option.nodeId)
@ -80,6 +86,8 @@ const RunMode = ({
handleWorkflowStartRunInWorkflow,
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
])
const { eventEmitter } = useEventEmitterContextContext()

View File

@ -19,12 +19,21 @@ import {
} from '@/app/components/base/portal-to-follow-elem'
import ShortcutsName from '../shortcuts-name'
export enum TriggerType {
UserInput = 'user_input',
Schedule = 'schedule',
Webhook = 'webhook',
Plugin = 'plugin',
All = 'all',
}
export type TriggerOption = {
id: string
type: 'user_input' | 'schedule' | 'webhook' | 'plugin' | 'all'
type: TriggerType
name: string
icon: React.ReactNode
nodeId?: string
relatedNodeIds?: string[]
enabled: boolean
}

View File

@ -48,6 +48,7 @@ export type CommonHooksFnMap = {
handleWorkflowTriggerScheduleRunInWorkflow: (nodeId?: string) => void
handleWorkflowTriggerWebhookRunInWorkflow: (params: { nodeId: string }) => void
handleWorkflowTriggerPluginRunInWorkflow: (nodeId?: string) => void
handleWorkflowRunAllTriggersInWorkflow: (nodeIds: string[]) => void
availableNodesMetaData?: AvailableNodesMetaData
getWorkflowRunAndTraceUrl: (runId?: string) => { runUrl: string; traceUrl: string }
exportCheck?: () => Promise<void>
@ -93,6 +94,7 @@ export const createHooksStore = ({
handleWorkflowTriggerScheduleRunInWorkflow = noop,
handleWorkflowTriggerWebhookRunInWorkflow = noop,
handleWorkflowTriggerPluginRunInWorkflow = noop,
handleWorkflowRunAllTriggersInWorkflow = noop,
availableNodesMetaData = {
nodes: [],
},
@ -134,6 +136,7 @@ export const createHooksStore = ({
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
availableNodesMetaData,
getWorkflowRunAndTraceUrl,
exportCheck,

View File

@ -3,7 +3,7 @@ import { useNodes } from 'reactflow'
import { useTranslation } from 'react-i18next'
import { BlockEnum, type CommonNodeType } from '../types'
import { getWorkflowEntryNode } from '../utils/workflow-entry'
import type { TestRunOptions, TriggerOption } from '../header/test-run-menu'
import { type TestRunOptions, type TriggerOption, TriggerType } from '../header/test-run-menu'
import { TriggerAll } from '@/app/components/base/icons/src/vender/workflow'
import BlockIcon from '../block-icon'
import { useStore } from '../store'
@ -30,7 +30,7 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
if (nodeData.type === BlockEnum.Start) {
userInput = {
id: node.id,
type: 'user_input',
type: TriggerType.UserInput,
name: nodeData.title || t('workflow.blocks.start'),
icon: (
<BlockIcon
@ -45,7 +45,7 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
else if (nodeData.type === BlockEnum.TriggerSchedule) {
allTriggers.push({
id: node.id,
type: 'schedule',
type: TriggerType.Schedule,
name: nodeData.title || t('workflow.blocks.trigger-schedule'),
icon: (
<BlockIcon
@ -60,7 +60,7 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
else if (nodeData.type === BlockEnum.TriggerWebhook) {
allTriggers.push({
id: node.id,
type: 'webhook',
type: TriggerType.Webhook,
name: nodeData.title || t('workflow.blocks.trigger-webhook'),
icon: (
<BlockIcon
@ -90,7 +90,7 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
allTriggers.push({
id: node.id,
type: 'plugin',
type: TriggerType.Plugin,
name: nodeData.title || (nodeData as any).plugin_name || t('workflow.blocks.trigger-plugin'),
icon,
nodeId: node.id,
@ -104,7 +104,7 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
if (startNode && startNode.data?.type === BlockEnum.Start) {
userInput = {
id: startNode.id,
type: 'user_input',
type: TriggerType.UserInput,
name: (startNode.data as CommonNodeType)?.title || t('workflow.blocks.start'),
icon: (
<BlockIcon
@ -118,15 +118,20 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
}
}
const runAll: TriggerOption | undefined = allTriggers.length > 1 ? {
const triggerNodeIds = allTriggers
.map(trigger => trigger.nodeId)
.filter((nodeId): nodeId is string => Boolean(nodeId))
const runAll: TriggerOption | undefined = triggerNodeIds.length > 1 ? {
id: 'run-all',
type: 'all',
type: TriggerType.All,
name: t('workflow.common.runAllTriggers'),
icon: (
<div className="flex h-6 w-6 items-center justify-center rounded-lg border-[0.5px] border-white/2 bg-util-colors-purple-purple-500 text-white shadow-md">
<TriggerAll className="h-4.5 w-4.5" />
</div>
),
relatedNodeIds: triggerNodeIds,
enabled: true,
} : undefined

View File

@ -7,7 +7,7 @@ export const useWorkflowStartRun = () => {
const handleWorkflowTriggerScheduleRunInWorkflow = useHooksStore(s => s.handleWorkflowTriggerScheduleRunInWorkflow)
const handleWorkflowTriggerWebhookRunInWorkflow = useHooksStore(s => s.handleWorkflowTriggerWebhookRunInWorkflow)
const handleWorkflowTriggerPluginRunInWorkflow = useHooksStore(s => s.handleWorkflowTriggerPluginRunInWorkflow)
const handleWorkflowRunAllTriggersInWorkflow = useHooksStore(s => s.handleWorkflowRunAllTriggersInWorkflow)
return {
handleStartWorkflowRun,
handleWorkflowStartRunInWorkflow,
@ -15,5 +15,6 @@ export const useWorkflowStartRun = () => {
handleWorkflowTriggerScheduleRunInWorkflow,
handleWorkflowTriggerWebhookRunInWorkflow,
handleWorkflowTriggerPluginRunInWorkflow,
handleWorkflowRunAllTriggersInWorkflow,
}
}