feat(trigger): implement trigger plugin block selector following tools pattern (#25204)

This commit is contained in:
lyzno1 2025-09-05 10:20:47 +08:00 committed by GitHub
parent d8f6f9ce19
commit 9f8c159583
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 123 additions and 23 deletions

View File

@ -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<Props> = ({
if (disabled) return
const params: Record<string, string> = {}
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,

View File

@ -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<Props> = ({
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<Props> = ({
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,
})

View File

@ -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

View File

@ -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<string, any>
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<string, any>
}
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
}

View File

@ -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<ToolWithProvider[]>({
return useQuery<TriggerWithProvider[]>({
queryKey: [NAME_SPACE, 'all'],
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/triggers/plugins'),
queryFn: async () => {
const response = await get<TriggerProviderApiEntity[]>('/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<ToolWithProvider[]>({
return useQuery<TriggerWithProvider[]>({
queryKey: [NAME_SPACE, 'byType', triggerType],
queryFn: () => get<ToolWithProvider[]>(`/workspaces/current/triggers/plugins?type=${triggerType}`),
queryFn: async () => {
const response = await get<TriggerProviderApiEntity[]>(`/workspaces/current/triggers?type=${triggerType}`)
return response.map(convertToTriggerWithProvider)
},
enabled: enabled && !!triggerType,
})
}