diff --git a/web/app/components/workflow/block-selector/trigger-plugin/action-item.tsx b/web/app/components/workflow/block-selector/trigger-plugin/action-item.tsx index 75c954431b..7f9b8d87d9 100644 --- a/web/app/components/workflow/block-selector/trigger-plugin/action-item.tsx +++ b/web/app/components/workflow/block-selector/trigger-plugin/action-item.tsx @@ -1,18 +1,18 @@ 'use client' import type { FC } from 'react' import React from 'react' -import type { ToolWithProvider } from '../../types' +import type { TriggerWithProvider } from '../types' +import type { Tool } from '@/app/components/tools/types' import { BlockEnum } from '../../types' import type { ToolDefaultValue } from '../types' import Tooltip from '@/app/components/base/tooltip' -import type { Tool } from '@/app/components/tools/types' import { useGetLanguage } from '@/context/i18n' import BlockIcon from '../../block-icon' import cn from '@/utils/classnames' import { useTranslation } from 'react-i18next' type Props = { - provider: ToolWithProvider + provider: TriggerWithProvider payload: Tool disabled?: boolean isAdded?: boolean @@ -55,20 +55,20 @@ const TriggerPluginActionItem: FC = ({ if (disabled) return const params: Record = {} if (payload.parameters) { - payload.parameters.forEach((item) => { + payload.parameters.forEach((item: any) => { params[item.name] = '' }) } onSelect(BlockEnum.TriggerPlugin, { provider_id: provider.id, - provider_type: provider.type, + provider_type: provider.type as string, provider_name: provider.name, tool_name: payload.name, tool_label: payload.label[language], tool_description: payload.description[language], title: payload.label[language], is_team_authorization: provider.is_team_authorization, - output_schema: payload.output_schema, + output_schema: payload.output_schema || {}, paramSchemas: payload.parameters, params, meta: provider.meta, diff --git a/web/app/components/workflow/block-selector/trigger-plugin/item.tsx b/web/app/components/workflow/block-selector/trigger-plugin/item.tsx index 0a60a96773..eff1ee5e98 100644 --- a/web/app/components/workflow/block-selector/trigger-plugin/item.tsx +++ b/web/app/components/workflow/block-selector/trigger-plugin/item.tsx @@ -5,7 +5,7 @@ import cn from '@/utils/classnames' import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react' import { useGetLanguage } from '@/context/i18n' import { CollectionType } from '../../../tools/types' -import type { ToolWithProvider } from '../../types' +import type { TriggerWithProvider } from '../types' import { BlockEnum } from '../../types' import type { ToolDefaultValue } from '../types' import TriggerPluginActionItem from './action-item' @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next' type Props = { className?: string - payload: ToolWithProvider + payload: TriggerWithProvider hasSearchText: boolean onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void } @@ -54,7 +54,7 @@ const TriggerPluginItem: FC = ({ if (payload.type === CollectionType.workflow) return t('workflow.tabs.workflowTool') - return '' + return payload.author || '' }, [payload.author, payload.type, t]) return ( @@ -88,7 +88,7 @@ const TriggerPluginItem: FC = ({ tool_description: tool.description[language], title: tool.label[language], is_team_authorization: payload.is_team_authorization, - output_schema: tool.output_schema, + output_schema: tool.output_schema || {}, paramSchemas: tool.parameters, params, }) diff --git a/web/app/components/workflow/block-selector/trigger-plugin/list.tsx b/web/app/components/workflow/block-selector/trigger-plugin/list.tsx index 4bcb93a6aa..c99b0fbd3e 100644 --- a/web/app/components/workflow/block-selector/trigger-plugin/list.tsx +++ b/web/app/components/workflow/block-selector/trigger-plugin/list.tsx @@ -1,6 +1,6 @@ 'use client' import { memo, useEffect, useMemo } from 'react' -import { useAllBuiltInTools } from '@/service/use-tools' +import { useAllTriggerPlugins } from '@/service/use-triggers' import TriggerPluginItem from './item' import type { BlockEnum } from '../../types' import type { ToolDefaultValue } from '../types' @@ -19,11 +19,12 @@ const TriggerPluginList = ({ onContentStateChange, tags = [], }: TriggerPluginListProps) => { - const { data: buildInTools = [] } = useAllBuiltInTools() + const { data: triggerPluginsData } = useAllTriggerPlugins() const language = useGetLanguage() const triggerPlugins = useMemo(() => { - return buildInTools.filter((toolWithProvider) => { + // Follow exact same pattern as tools + return (triggerPluginsData || []).filter((toolWithProvider) => { if (toolWithProvider.tools.length === 0) return false // Filter by search text @@ -37,7 +38,7 @@ const TriggerPluginList = ({ return true }) - }, [buildInTools, searchText, language]) + }, [triggerPluginsData, searchText, language]) const hasContent = triggerPlugins.length > 0 diff --git a/web/app/components/workflow/block-selector/types.ts b/web/app/components/workflow/block-selector/types.ts index a4d358525e..17cf1ae04f 100644 --- a/web/app/components/workflow/block-selector/types.ts +++ b/web/app/components/workflow/block-selector/types.ts @@ -1,4 +1,6 @@ import type { PluginMeta } from '../../plugins/types' +import type { Collection, Tool } from '../../tools/types' +import type { TypeWithI18N } from '../../base/form/types' export enum TabsEnum { Start = 'start', @@ -50,3 +52,51 @@ export type ToolValue = { extra?: Record credential_id?: string } + +// Backend API types - exact match with Python definitions +export type TriggerParameter = { + name: string + label: TypeWithI18N + description?: TypeWithI18N + type: string + required?: boolean + default?: any +} + +export type TriggerIdentity = { + author: string + name: string + version: string +} + +export type TriggerDescription = { + human: TypeWithI18N + llm: TypeWithI18N +} + +export type TriggerApiEntity = { + name: string + identity: TriggerIdentity + description: TriggerDescription + parameters: TriggerParameter[] + output_schema?: Record +} + +export type TriggerProviderApiEntity = { + author: string + name: string + label: TypeWithI18N + description: TypeWithI18N + icon?: string + icon_dark?: string + tags: string[] + plugin_id?: string + plugin_unique_identifier?: string + triggers: TriggerApiEntity[] +} + +// Frontend types - compatible with ToolWithProvider +export type TriggerWithProvider = Collection & { + tools: Tool[] // Use existing Tool type for compatibility + meta: PluginMeta +} diff --git a/web/service/use-triggers.ts b/web/service/use-triggers.ts index c02f9ec053..1d1535ac18 100644 --- a/web/service/use-triggers.ts +++ b/web/service/use-triggers.ts @@ -1,25 +1,74 @@ import { useQuery } from '@tanstack/react-query' import { get } from './base' -import type { ToolWithProvider } from '@/app/components/workflow/types' +import type { TriggerProviderApiEntity, TriggerWithProvider } from '@/app/components/workflow/block-selector/types' +import { CollectionType } from '@/app/components/tools/types' const NAME_SPACE = 'triggers' -// Get all plugins that support trigger functionality -// TODO: Backend API not implemented yet - replace with actual triggers endpoint +// Convert backend API response to frontend ToolWithProvider format +const convertToTriggerWithProvider = (provider: TriggerProviderApiEntity): TriggerWithProvider => { + return { + // Collection fields + id: provider.plugin_id || provider.name, + name: provider.name, + author: provider.author, + description: provider.description, // Already TypeWithI18N format + icon: provider.icon || '', + label: provider.label, // Already TypeWithI18N format + type: CollectionType.builtIn, + team_credentials: {}, + is_team_authorization: false, + allow_delete: false, + labels: provider.tags || [], + plugin_id: provider.plugin_id, + + // ToolWithProvider fields - convert "triggers" to "tools" + tools: provider.triggers.map(trigger => ({ + name: trigger.name, + author: provider.author, + label: trigger.description.human, // Already TypeWithI18N format + description: trigger.description.llm, // Already TypeWithI18N format + parameters: trigger.parameters.map(param => ({ + name: param.name, + label: param.label, // Already TypeWithI18N format + human_description: param.description || param.label, + type: param.type, + form: param.type, + llm_description: JSON.stringify(param.description || {}), + required: param.required || false, + default: param.default || '', + options: [], + })), + labels: provider.tags || [], + output_schema: trigger.output_schema || {}, + })), + + meta: { + version: '1.0', + }, + } +} + +// Main hook - follows exact same pattern as tools export const useAllTriggerPlugins = (enabled = true) => { - return useQuery({ + return useQuery({ queryKey: [NAME_SPACE, 'all'], - queryFn: () => get('/workspaces/current/triggers/plugins'), + queryFn: async () => { + const response = await get('/workspaces/current/triggers') + return response.map(convertToTriggerWithProvider) + }, enabled, }) } -// Get trigger-capable plugins by type (schedule, webhook, etc.) -// TODO: Backend API not implemented yet - replace with actual triggers endpoint +// Additional hook for consistency with tools pattern export const useTriggerPluginsByType = (triggerType: string, enabled = true) => { - return useQuery({ + return useQuery({ queryKey: [NAME_SPACE, 'byType', triggerType], - queryFn: () => get(`/workspaces/current/triggers/plugins?type=${triggerType}`), + queryFn: async () => { + const response = await get(`/workspaces/current/triggers?type=${triggerType}`) + return response.map(convertToTriggerWithProvider) + }, enabled: enabled && !!triggerType, }) }