feat(plugin): enhance trigger events list with dynamic tool integration

- Refactor TriggerEventsList component to utilize provider information for dynamic tool rendering.
- Implement locale-aware text handling for trigger descriptions and labels.
- Introduce utility functions for better management of tool parameters and trigger descriptions.
- Improve user experience by ensuring consistent display of trigger events based on available provider data.

This update enhances the functionality and maintainability of the trigger events list, aligning with the project's metadata-driven approach.
This commit is contained in:
zhsama 2025-09-26 23:27:27 +08:00
parent a9a118aaf9
commit bcfdd07f85
1 changed files with 141 additions and 17 deletions

View File

@ -1,39 +1,163 @@
import React from 'react'
import React, { useContext, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import I18n from '@/context/i18n'
import { getLanguage } from '@/i18n-config/language'
import ToolItem from '@/app/components/tools/provider/tool-item'
import { usePluginStore } from './store'
import { useTriggerProviderInfo } from '@/service/use-triggers'
import type { Tool, ToolParameter } from '@/app/components/tools/types'
import { CollectionType } from '@/app/components/tools/types'
import type { ToolWithProvider } from '@/app/components/workflow/types'
import type { TypeWithI18N } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { Trigger } from '@/app/components/plugins/types'
type TriggerOption = {
value: string
label: TypeWithI18N
icon?: string | null
}
const pickLocaleText = (value?: TypeWithI18N | string, fallback = '', language = 'en_US'): string => {
if (!value)
return fallback
if (typeof value === 'string')
return value
const typedValue = value as Record<string, string>
return typedValue[language] ?? typedValue.en_US ?? Object.values(typedValue)[0] ?? fallback
}
const getTriggerDescription = (description: TypeWithI18N | { human?: TypeWithI18N | string } | string | undefined, language = 'en_US'): string => {
if (!description)
return ''
if (typeof description === 'string')
return description
if (typeof description === 'object' && 'human' in description) {
const human = (description as { human?: TypeWithI18N | string }).human
return pickLocaleText(human, '', language)
}
return pickLocaleText(description as TypeWithI18N, '', language)
}
const toToolParameter = (parameter: any): ToolParameter => {
const paramLabel = parameter.label as TypeWithI18N
const paramDescription = parameter.description as TypeWithI18N | undefined
return {
name: parameter.name,
label: paramLabel,
human_description: paramDescription || paramLabel,
type: parameter.type,
form: 'setting',
llm_description: typeof paramDescription === 'object' ? (paramDescription.en_US || '') : (paramDescription || ''),
required: parameter.required ?? false,
multiple: parameter.multiple ?? false,
default: parameter.default ?? '',
options: parameter.options?.map((option: TriggerOption) => ({
label: option.label,
value: option.value,
})) || [],
}
}
const toTool = (trigger: Trigger, fallbackAuthor: string): Tool => {
const name = trigger.identity?.name || ''
const label = trigger.identity?.label || { en_US: name }
const description = trigger.description?.human || trigger.description || { en_US: '' }
return {
name,
author: trigger.identity?.author || fallbackAuthor,
label: label as TypeWithI18N,
description: description as TypeWithI18N,
parameters: (trigger.parameters || []).map((param: any) => toToolParameter(param)),
labels: [],
output_schema: trigger.output_schema || {},
}
}
export const TriggerEventsList = () => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const language = getLanguage(locale)
const detail = usePluginStore(state => state.detail)
const triggers = detail?.declaration.trigger?.triggers || []
const providerKey = useMemo(() => {
if (!detail?.plugin_id || !detail?.declaration?.name)
return ''
return `${detail.plugin_id}/${detail.declaration.name}`
}, [detail?.plugin_id, detail?.declaration?.name])
const { data: providerInfo } = useTriggerProviderInfo(providerKey, !!providerKey)
const collection = useMemo<ToolWithProvider | undefined>(() => {
if (!detail || !providerInfo)
return undefined
const tools = (providerInfo.triggers || []).map((trigger: any) => toTool(trigger, providerInfo.author))
const metaVersion = detail.declaration.meta?.version || detail.version || '1.0'
return {
id: providerInfo.plugin_id || providerInfo.name,
name: providerInfo.name,
author: providerInfo.author,
description: providerInfo.description,
icon: providerInfo.icon || providerInfo.icon_dark || '',
label: providerInfo.label,
type: CollectionType.builtIn,
team_credentials: {},
is_team_authorization: false,
allow_delete: false,
labels: providerInfo.tags || [],
plugin_id: providerInfo.plugin_id || detail.plugin_id,
tools,
meta: { version: metaVersion },
}
}, [detail, providerInfo])
if (!triggers.length)
return null
// todo: add collection & update ToolItem
return (
<div className='px-4 pb-4 pt-2'>
<div className='mb-1 py-1'>
<div className='system-sm-semibold-uppercase mb-1 flex h-6 items-center justify-between text-text-secondary'>
{t('pluginTrigger.events.actionNum', { num: triggers.length, event: triggers.length > 1 ? 'events' : 'event' })}
{t('pluginTrigger.events.actionNum', { num: triggers.length, event: t(`pluginTrigger.events.${triggers.length > 1 ? 'events' : 'event'}`) })}
</div>
</div>
<div className='flex flex-col gap-2'>
{triggers.map(triggerEvent => (
<ToolItem
key={`${detail?.plugin_id}${triggerEvent.identity.name}`}
disabled={false}
// collection={provider}
// @ts-expect-error triggerEvent.identity.label is Record<Locale, string>
tool={{
label: triggerEvent.identity.label as any,
description: triggerEvent.description.human,
}}
isBuiltIn={false}
isModel={false}
/>
))}
{collection
? triggers.map((triggerEvent: Trigger) => {
const triggerName = triggerEvent.identity?.name || ''
const tool = collection.tools.find(item => item.name === triggerName)
|| toTool(triggerEvent, collection.author)
return (
<ToolItem
key={`${detail?.plugin_id}${triggerEvent.identity?.name || ''}`}
disabled={false}
collection={collection}
tool={tool}
isBuiltIn={false}
isModel={false}
/>
)
})
: triggers.map((triggerEvent: Trigger) => (
<div
key={`${detail?.plugin_id}${triggerEvent.identity?.name || ''}`}
className='bg-components-panel-item-bg rounded-xl border-[0.5px] border-components-panel-border-subtle px-4 py-3 shadow-xs'
>
<div className='system-md-semibold pb-0.5 text-text-secondary'>
{pickLocaleText(triggerEvent.identity?.label as TypeWithI18N, triggerEvent.identity?.name || '', language)}
</div>
<div className='system-xs-regular line-clamp-2 text-text-tertiary'>
{getTriggerDescription(triggerEvent.description, language)}
</div>
</div>
))}
</div>
</div>
)