diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts index 5d9160faf0..f7ad638ee7 100644 --- a/web/app/components/workflow/hooks/use-checklist.ts +++ b/web/app/components/workflow/hooks/use-checklist.ts @@ -22,6 +22,7 @@ import { getToolCheckParams, getValidTreeNodes, } from '../utils' +import { getTriggerCheckParams } from '../utils/trigger' import { CUSTOM_NODE, } from '../constants' @@ -31,10 +32,12 @@ import { } from '../hooks' import type { ToolNodeType } from '../nodes/tool/types' import type { DataSourceNodeType } from '../nodes/data-source/types' +import type { PluginTriggerNodeType } from '../nodes/trigger-plugin/types' import { useToastContext } from '@/app/components/base/toast' import { useGetLanguage } from '@/context/i18n' import type { AgentNodeType } from '../nodes/agent/types' import { useStrategyProviders } from '@/service/use-strategy' +import { useAllTriggerPlugins } from '@/service/use-triggers' import { useDatasetsDetailStore } from '../datasets-detail-store/store' import type { KnowledgeRetrievalNodeType } from '../nodes/knowledge-retrieval/types' import type { DataSet } from '@/models/datasets' @@ -70,6 +73,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { const workflowTools = useStore(s => s.workflowTools) const dataSourceList = useStore(s => s.dataSourceList) const { data: strategyProviders } = useStrategyProviders() + const { data: triggerPlugins } = useAllTriggerPlugins() const datasetsDetail = useDatasetsDetailStore(s => s.datasetsDetail) const getToolIcon = useGetToolIcon() @@ -108,6 +112,9 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { if (node.data.type === BlockEnum.DataSource) moreDataForCheckValid = getDataSourceCheckParams(node.data as DataSourceNodeType, dataSourceList || [], language) + if (node.data.type === BlockEnum.TriggerPlugin) + moreDataForCheckValid = getTriggerCheckParams(node.data as PluginTriggerNodeType, triggerPlugins, language) + const toolIcon = getToolIcon(node.data) if (node.data.type === BlockEnum.Agent) { const data = node.data as AgentNodeType diff --git a/web/app/components/workflow/nodes/trigger-plugin/default.ts b/web/app/components/workflow/nodes/trigger-plugin/default.ts index 217c5aaee2..f0d8fe1ec4 100644 --- a/web/app/components/workflow/nodes/trigger-plugin/default.ts +++ b/web/app/components/workflow/nodes/trigger-plugin/default.ts @@ -5,6 +5,7 @@ import type { PluginTriggerNodeType } from './types' import { getMatchedSchemaType } from '../_base/components/variable/use-match-schema-type' import type { SchemaTypeDefinition } from '@/service/use-common' import { type Field, type StructuredOutput, Type } from '../llm/types' +import { VarKindType } from '../_base/types' const normalizeJsonSchemaType = (schema: any): string | undefined => { if (!schema) return undefined @@ -222,12 +223,52 @@ const nodeDefault: NodeDefault = { // event_type: '', config: {}, }, - checkValid(payload: PluginTriggerNodeType, t: any) { + checkValid(payload: PluginTriggerNodeType, t: any, moreDataForCheckValid: { + triggerInputsSchema?: Array<{ + variable: string + label: string + required?: boolean + }> + isReadyForCheckValid?: boolean + } = {}) { let errorMessage = '' if (!payload.subscription_id) errorMessage = t('workflow.nodes.triggerPlugin.subscriptionRequired') + const { + triggerInputsSchema = [], + isReadyForCheckValid = true, + } = moreDataForCheckValid || {} + + if (!errorMessage && isReadyForCheckValid) { + triggerInputsSchema.filter(field => field.required).forEach((field) => { + if (errorMessage) + return + + const rawParam = payload.event_parameters?.[field.variable] + ?? (payload.config as Record | undefined)?.[field.variable] + if (!rawParam) { + errorMessage = t('workflow.errorMsg.fieldRequired', { field: field.label }) + return + } + + const targetParam = typeof rawParam === 'object' && rawParam !== null && 'type' in rawParam + ? rawParam as { type: VarKindType; value: any } + : { type: VarKindType.constant, value: rawParam } + + const { type, value } = targetParam + if (type === VarKindType.variable) { + if (!value || (Array.isArray(value) && value.length === 0)) + errorMessage = t('workflow.errorMsg.fieldRequired', { field: field.label }) + } + else { + if (value === undefined || value === null || value === '') + errorMessage = t('workflow.errorMsg.fieldRequired', { field: field.label }) + } + }) + } + return { isValid: !errorMessage, errorMessage, diff --git a/web/app/components/workflow/utils/trigger.ts b/web/app/components/workflow/utils/trigger.ts new file mode 100644 index 0000000000..f6d197c69c --- /dev/null +++ b/web/app/components/workflow/utils/trigger.ts @@ -0,0 +1,52 @@ +import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types' +import type { PluginTriggerNodeType } from '@/app/components/workflow/nodes/trigger-plugin/types' + +export type TriggerCheckParams = { + triggerInputsSchema: Array<{ + variable: string + label: string + required?: boolean + }> + isReadyForCheckValid: boolean +} + +export const getTriggerCheckParams = ( + triggerData: PluginTriggerNodeType, + triggerProviders: TriggerWithProvider[] | undefined, + language: string, +): TriggerCheckParams => { + if (!triggerProviders) { + return { + triggerInputsSchema: [], + isReadyForCheckValid: false, + } + } + + const { + provider_id, + provider_name, + event_name, + } = triggerData + + const provider = triggerProviders.find(item => + item.name === provider_name + || item.id === provider_id + || (provider_id && item.plugin_id === provider_id), + ) + + const currentEvent = provider?.events.find(event => event.name === event_name) + + const triggerInputsSchema = (currentEvent?.parameters || []).map((parameter) => { + const label = parameter.label?.[language] || parameter.label?.en_US || parameter.name + return { + variable: parameter.name, + label, + required: parameter.required, + } + }) + + return { + triggerInputsSchema, + isReadyForCheckValid: true, + } +}