mirror of https://github.com/langgenius/dify.git
feat(trigger): enhance plugin and trigger integration with updated naming conventions
- Refactored `PluginFetchDynamicSelectOptionsApi` to replace the `extra` argument with `credential_id`, improving clarity in dynamic option fetching. - Updated `ProviderConfigEncrypter` to rename `mask_tool_credentials` to `mask_credentials` for consistency, and added a new method to maintain backward compatibility. - Enhanced `PluginParameterService` to utilize `credential_id` for fetching subscriptions, improving the handling of trigger credentials. - Adjusted various components and types in the frontend to replace `tool_name` with `trigger_name`, ensuring consistency across the application. - Introduced `multiple` property in `TriggerParameter` to support multi-select functionality. These changes improve the integration of triggers and plugins, enhance code clarity, and align naming conventions across the codebase.
This commit is contained in:
parent
01b2f9cff6
commit
2a3ce6baa9
|
|
@ -516,20 +516,20 @@ class PluginFetchDynamicSelectOptionsApi(Resource):
|
|||
parser.add_argument("provider", type=str, required=True, location="args")
|
||||
parser.add_argument("action", type=str, required=True, location="args")
|
||||
parser.add_argument("parameter", type=str, required=True, location="args")
|
||||
parser.add_argument("extra", type=dict, required=False, location="args")
|
||||
parser.add_argument("credential_id", type=str, required=False, location="args")
|
||||
parser.add_argument("provider_type", type=str, required=True, location="args")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
options = PluginParameterService.get_dynamic_select_options(
|
||||
tenant_id,
|
||||
user_id,
|
||||
args["plugin_id"],
|
||||
args["provider"],
|
||||
args["action"],
|
||||
args["parameter"],
|
||||
args["extra"],
|
||||
args["provider_type"],
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
plugin_id=args["plugin_id"],
|
||||
provider=args["provider"],
|
||||
action=args["action"],
|
||||
parameter=args["parameter"],
|
||||
credential_id=args["credential_id"],
|
||||
provider_type=args["provider_type"],
|
||||
)
|
||||
except PluginDaemonClientSideError as e:
|
||||
raise ValueError(e)
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ class ProviderConfigEncrypter:
|
|||
|
||||
return data
|
||||
|
||||
def mask_tool_credentials(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
def mask_credentials(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
mask tool credentials
|
||||
mask credentials
|
||||
|
||||
return a deep copy of credentials with masked values
|
||||
"""
|
||||
|
|
@ -91,6 +91,10 @@ class ProviderConfigEncrypter:
|
|||
|
||||
return data
|
||||
|
||||
|
||||
def mask_tool_credentials(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
return self.mask_credentials(data)
|
||||
|
||||
def decrypt(self, data: dict[str, str]) -> dict[str, Any]:
|
||||
"""
|
||||
decrypt tool credentials with tenant id
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ class PluginTriggerManager(BasePluginClient):
|
|||
def transformer(json_response: dict[str, Any]) -> dict:
|
||||
for provider in json_response.get("data", []):
|
||||
declaration = provider.get("declaration", {}) or {}
|
||||
provider_name = declaration.get("identity", {}).get("name")
|
||||
provider_id = provider.get("plugin_id") + "/" + provider.get("provider")
|
||||
for trigger in declaration.get("triggers", []):
|
||||
trigger["identity"]["provider"] = provider_name
|
||||
trigger["identity"]["provider"] = provider_id
|
||||
|
||||
return json_response
|
||||
|
||||
|
|
@ -42,10 +42,11 @@ class PluginTriggerManager(BasePluginClient):
|
|||
)
|
||||
|
||||
for provider in response:
|
||||
provider.declaration.identity.name = str(provider.provider)
|
||||
provider.declaration.identity.name = f"{provider.plugin_id}/{provider.declaration.identity.name}"
|
||||
|
||||
# override the provider name for each trigger to plugin_id/provider_name
|
||||
for trigger in provider.declaration.triggers:
|
||||
trigger.identity.provider = str(provider.provider)
|
||||
trigger.identity.provider = provider.declaration.identity.name
|
||||
|
||||
return response
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ class TriggerParameter(BaseModel):
|
|||
template: Optional[PluginParameterTemplate] = Field(default=None, description="The template of the parameter")
|
||||
scope: Optional[str] = None
|
||||
required: Optional[bool] = False
|
||||
multiple: bool | None = Field(
|
||||
default=False,
|
||||
description="Whether the parameter is multiple select, only valid for select or dynamic-select type",
|
||||
)
|
||||
default: Union[int, float, str, list, None] = None
|
||||
min: Union[float, int, None] = None
|
||||
max: Union[float, int, None] = None
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@ from core.plugin.entities.plugin_daemon import CredentialType
|
|||
from core.plugin.impl.dynamic_select import DynamicSelectClient
|
||||
from core.tools.tool_manager import ToolManager
|
||||
from core.tools.utils.encryption import create_tool_provider_encrypter
|
||||
from core.trigger.entities.api_entities import TriggerProviderSubscriptionApiEntity
|
||||
from core.trigger.entities.entities import SubscriptionBuilder
|
||||
from core.trigger.trigger_manager import TriggerManager
|
||||
from extensions.ext_database import db
|
||||
from models.tools import BuiltinToolProvider
|
||||
from services.trigger.trigger_provider_service import TriggerProviderService
|
||||
from services.trigger.trigger_subscription_builder_service import TriggerSubscriptionBuilderService
|
||||
|
||||
|
||||
class PluginParameterService:
|
||||
|
|
@ -23,7 +27,7 @@ class PluginParameterService:
|
|||
provider: str,
|
||||
action: str,
|
||||
parameter: str,
|
||||
extra: dict | None,
|
||||
credential_id: str | None,
|
||||
provider_type: Literal["tool", "trigger"],
|
||||
) -> Sequence[PluginParameterOption]:
|
||||
"""
|
||||
|
|
@ -37,7 +41,7 @@ class PluginParameterService:
|
|||
parameter: The parameter name.
|
||||
"""
|
||||
credentials: Mapping[str, Any] = {}
|
||||
credential_type: str = CredentialType.API_KEY.value
|
||||
credential_type: str = CredentialType.UNAUTHORIZED.value
|
||||
match provider_type:
|
||||
case "tool":
|
||||
provider_controller = ToolManager.get_builtin_provider(provider, tenant_id)
|
||||
|
|
@ -53,8 +57,7 @@ class PluginParameterService:
|
|||
else:
|
||||
# fetch credentials from db
|
||||
with Session(db.engine) as session:
|
||||
if extra and "credential_id" in extra:
|
||||
credential_id = extra["credential_id"]
|
||||
if credential_id:
|
||||
db_record = (
|
||||
session.query(BuiltinToolProvider)
|
||||
.where(
|
||||
|
|
@ -82,7 +85,21 @@ class PluginParameterService:
|
|||
credential_type = db_record.credential_type
|
||||
case "trigger":
|
||||
provider_controller = TriggerManager.get_trigger_provider(tenant_id, TriggerProviderID(provider))
|
||||
if credential_id:
|
||||
subscription: TriggerProviderSubscriptionApiEntity | SubscriptionBuilder | None = (
|
||||
TriggerSubscriptionBuilderService.get_subscription_builder(credential_id)
|
||||
or TriggerProviderService.get_subscription_by_id(tenant_id, credential_id)
|
||||
)
|
||||
else:
|
||||
subscription: TriggerProviderSubscriptionApiEntity | SubscriptionBuilder | None = (
|
||||
TriggerProviderService.get_subscription_by_id(tenant_id)
|
||||
)
|
||||
|
||||
if subscription is None:
|
||||
raise ValueError(f"Subscription {credential_id} not found")
|
||||
|
||||
credentials = subscription.credentials
|
||||
credential_type = subscription.credential_type or CredentialType.UNAUTHORIZED
|
||||
case _:
|
||||
raise ValueError(f"Invalid provider type: {provider_type}")
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class TriggerProviderService:
|
|||
controller=provider_controller,
|
||||
subscription=subscription,
|
||||
)
|
||||
subscription.credentials = encrypter.decrypt(subscription.credentials)
|
||||
subscription.credentials = encrypter.mask_credentials(subscription.credentials)
|
||||
return subscriptions
|
||||
|
||||
@classmethod
|
||||
|
|
@ -165,6 +165,34 @@ class TriggerProviderService:
|
|||
logger.exception("Failed to add trigger provider")
|
||||
raise ValueError(str(e))
|
||||
|
||||
@classmethod
|
||||
def get_subscription_by_id(
|
||||
cls, tenant_id: str, subscription_id: str | None = None
|
||||
) -> TriggerProviderSubscriptionApiEntity | None:
|
||||
"""
|
||||
Get a trigger subscription by the ID.
|
||||
"""
|
||||
with Session(db.engine, expire_on_commit=False) as session:
|
||||
subscription: TriggerSubscription | None = None
|
||||
if subscription_id:
|
||||
subscription = (
|
||||
session.query(TriggerSubscription).filter_by(tenant_id=tenant_id, id=subscription_id).first()
|
||||
)
|
||||
else:
|
||||
subscription = session.query(TriggerSubscription).filter_by(tenant_id=tenant_id).first()
|
||||
if subscription:
|
||||
provider_controller = TriggerManager.get_trigger_provider(
|
||||
tenant_id, TriggerProviderID(subscription.provider_id)
|
||||
)
|
||||
encrypter, _ = create_trigger_provider_encrypter_for_subscription(
|
||||
tenant_id=tenant_id,
|
||||
controller=provider_controller,
|
||||
subscription=subscription,
|
||||
)
|
||||
subscription.credentials = encrypter.decrypt(subscription.credentials)
|
||||
return subscription.to_api_entity()
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def delete_trigger_provider(cls, session: Session, tenant_id: str, subscription_id: str):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ const AgentTools: FC = () => {
|
|||
provider_id: tool.provider_id,
|
||||
provider_type: tool.provider_type as CollectionType,
|
||||
provider_name: tool.provider_name,
|
||||
tool_name: tool.tool_name,
|
||||
tool_name: tool.trigger_name,
|
||||
tool_label: tool.tool_label,
|
||||
tool_parameters: tool.params,
|
||||
notAuthor: !tool.is_team_authorization,
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ const ToolSelector: FC<Props> = ({
|
|||
provider_name: tool.provider_id,
|
||||
provider_show_name: tool.provider_name,
|
||||
type: tool.provider_type,
|
||||
tool_name: tool.tool_name,
|
||||
tool_name: tool.trigger_name,
|
||||
tool_label: tool.tool_label,
|
||||
tool_description: tool.tool_description,
|
||||
settings: settingValues,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export type ToolParameter = {
|
|||
form: string
|
||||
llm_description: string
|
||||
required: boolean
|
||||
multiple: boolean
|
||||
default: string
|
||||
options?: {
|
||||
label: TypeWithI18N
|
||||
|
|
@ -78,7 +79,33 @@ export type ToolParameter = {
|
|||
max?: number
|
||||
}
|
||||
|
||||
export type TriggerParameter = {
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
human_description: TypeWithI18N
|
||||
type: string
|
||||
form: string
|
||||
llm_description: string
|
||||
required: boolean
|
||||
multiple: boolean
|
||||
default: string
|
||||
options?: {
|
||||
label: TypeWithI18N
|
||||
value: string
|
||||
}[]
|
||||
}
|
||||
|
||||
// Action
|
||||
export type Trigger = {
|
||||
name: string
|
||||
author: string
|
||||
label: TypeWithI18N
|
||||
description: any
|
||||
parameters: TriggerParameter[]
|
||||
labels: string[]
|
||||
output_schema: Record<string, any>
|
||||
}
|
||||
|
||||
export type Tool = {
|
||||
name: string
|
||||
author: string
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
'use client'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { BlockEnum } from '../types'
|
||||
import type { ToolDefaultValue } from './types'
|
||||
import type { BlockEnum, OnSelectBlock } from '../types'
|
||||
import type { TriggerDefaultValue } from './types'
|
||||
import StartBlocks from './start-blocks'
|
||||
import TriggerPluginSelector from './trigger-plugin-selector'
|
||||
import { ENTRY_NODE_TYPES } from './constants'
|
||||
|
|
@ -16,7 +16,7 @@ import { SearchMenu } from '@/app/components/base/icons/src/vender/line/general'
|
|||
type AllStartBlocksProps = {
|
||||
className?: string
|
||||
searchText: string
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
onSelect: (type: BlockEnum, trigger?: TriggerDefaultValue) => void
|
||||
availableBlocksTypes?: BlockEnum[]
|
||||
tags?: string[]
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ const AllStartBlocks = ({
|
|||
<>
|
||||
<StartBlocks
|
||||
searchText={searchText}
|
||||
onSelect={onSelect}
|
||||
onSelect={onSelect as OnSelectBlock}
|
||||
availableBlocksTypes={ENTRY_NODE_TYPES as unknown as BlockEnum[]}
|
||||
onContentStateChange={handleStartBlocksContentChange}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -86,9 +86,9 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
|||
e.stopPropagation()
|
||||
handleOpenChange(!open)
|
||||
}, [handleOpenChange, open, disabled])
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, pluginDefaultValue) => {
|
||||
handleOpenChange(false)
|
||||
onSelect(type, toolDefaultValue)
|
||||
onSelect(type, pluginDefaultValue)
|
||||
}, [handleOpenChange, onSelect])
|
||||
|
||||
const [activeTab, setActiveTab] = useState(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { memo } from 'react'
|
|||
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools } from '@/service/use-tools'
|
||||
import type { BlockEnum } from '../types'
|
||||
import { useTabs } from './hooks'
|
||||
import type { ToolDefaultValue } from './types'
|
||||
import type { PluginDefaultValue } from './types'
|
||||
import { TabsEnum } from './types'
|
||||
import Blocks from './blocks'
|
||||
import AllStartBlocks from './all-start-blocks'
|
||||
|
|
@ -15,7 +15,7 @@ export type TabsProps = {
|
|||
onActiveTabChange: (activeTab: TabsEnum) => void
|
||||
searchText: string
|
||||
tags: string[]
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
onSelect: (type: BlockEnum, plugin?: PluginDefaultValue) => void
|
||||
availableBlocksTypes?: BlockEnum[]
|
||||
filterElem: React.ReactNode
|
||||
noBlocks?: boolean
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ const ToolItem: FC<Props> = ({
|
|||
provider_id: provider.id,
|
||||
provider_type: provider.type,
|
||||
provider_name: provider.name,
|
||||
tool_name: payload.name,
|
||||
trigger_name: payload.name,
|
||||
tool_label: payload.label[language],
|
||||
tool_description: payload.description[language],
|
||||
title: payload.label[language],
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ const Tool: FC<Props> = ({
|
|||
provider_id: payload.id,
|
||||
provider_type: payload.type,
|
||||
provider_name: payload.name,
|
||||
tool_name: tool.name,
|
||||
trigger_name: tool.name,
|
||||
tool_label: tool.label[language],
|
||||
tool_description: tool.description[language],
|
||||
title: tool.label[language],
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
import { memo } from 'react'
|
||||
import TriggerPluginList from './trigger-plugin/list'
|
||||
import type { BlockEnum } from '../types'
|
||||
import type { ToolDefaultValue } from './types'
|
||||
import type { TriggerDefaultValue } from './types'
|
||||
|
||||
type TriggerPluginSelectorProps = {
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
onSelect: (type: BlockEnum, trigger?: TriggerDefaultValue) => void
|
||||
searchText: string
|
||||
onContentStateChange?: (hasContent: boolean) => void
|
||||
tags?: string[]
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import type { TriggerWithProvider } from '../types'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import type { Trigger } from '@/app/components/tools/types'
|
||||
import { BlockEnum } from '../../types'
|
||||
import type { ToolDefaultValue } from '../types'
|
||||
import type { TriggerDefaultValue } from '../types'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import BlockIcon from '../../block-icon'
|
||||
|
|
@ -13,10 +13,10 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
type Props = {
|
||||
provider: TriggerWithProvider
|
||||
payload: Tool
|
||||
payload: Trigger
|
||||
disabled?: boolean
|
||||
isAdded?: boolean
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
onSelect: (type: BlockEnum, trigger?: TriggerDefaultValue) => void
|
||||
}
|
||||
|
||||
const TriggerPluginActionItem: FC<Props> = ({
|
||||
|
|
@ -63,9 +63,9 @@ const TriggerPluginActionItem: FC<Props> = ({
|
|||
provider_id: provider.id,
|
||||
provider_type: provider.type as string,
|
||||
provider_name: provider.name,
|
||||
tool_name: payload.name,
|
||||
tool_label: payload.label[language],
|
||||
tool_description: payload.description[language],
|
||||
trigger_name: payload.name,
|
||||
trigger_label: payload.label[language],
|
||||
trigger_description: payload.description[language],
|
||||
title: payload.label[language],
|
||||
is_team_authorization: provider.is_team_authorization,
|
||||
output_schema: payload.output_schema || {},
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import cn from '@/utils/classnames'
|
||||
import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import { CollectionType } from '../../../tools/types'
|
||||
import type { TriggerWithProvider } from '../types'
|
||||
import { BlockEnum } from '../../types'
|
||||
import type { ToolDefaultValue } from '../types'
|
||||
import TriggerPluginActionItem from './action-item'
|
||||
import BlockIcon from '../../block-icon'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { CollectionType } from '../../../tools/types'
|
||||
import BlockIcon from '../../block-icon'
|
||||
import { BlockEnum } from '../../types'
|
||||
import type { TriggerDefaultValue, TriggerWithProvider } from '../types'
|
||||
import TriggerPluginActionItem from './action-item'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
payload: TriggerWithProvider
|
||||
hasSearchText: boolean
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
onSelect: (type: BlockEnum, trigger?: TriggerDefaultValue) => void
|
||||
}
|
||||
|
||||
const TriggerPluginItem: FC<Props> = ({
|
||||
|
|
@ -28,7 +27,7 @@ const TriggerPluginItem: FC<Props> = ({
|
|||
const { t } = useTranslation()
|
||||
const language = useGetLanguage()
|
||||
const notShowProvider = payload.type === CollectionType.workflow
|
||||
const actions = payload.tools
|
||||
const actions = payload.triggers
|
||||
const hasAction = !notShowProvider
|
||||
const [isFold, setFold] = React.useState<boolean>(true)
|
||||
const ref = useRef(null)
|
||||
|
|
@ -72,10 +71,10 @@ const TriggerPluginItem: FC<Props> = ({
|
|||
return
|
||||
}
|
||||
|
||||
const tool = actions[0]
|
||||
const trigger = actions[0]
|
||||
const params: Record<string, string> = {}
|
||||
if (tool.parameters) {
|
||||
tool.parameters.forEach((item) => {
|
||||
if (trigger.parameters) {
|
||||
trigger.parameters.forEach((item) => {
|
||||
params[item.name] = ''
|
||||
})
|
||||
}
|
||||
|
|
@ -83,13 +82,13 @@ const TriggerPluginItem: FC<Props> = ({
|
|||
provider_id: payload.id,
|
||||
provider_type: payload.type,
|
||||
provider_name: payload.name,
|
||||
tool_name: tool.name,
|
||||
tool_label: tool.label[language],
|
||||
tool_description: tool.description[language],
|
||||
title: tool.label[language],
|
||||
trigger_name: trigger.name,
|
||||
trigger_label: trigger.label[language],
|
||||
trigger_description: trigger.description[language],
|
||||
title: trigger.label[language],
|
||||
is_team_authorization: payload.is_team_authorization,
|
||||
output_schema: tool.output_schema || {},
|
||||
paramSchemas: tool.parameters,
|
||||
output_schema: trigger.output_schema || {},
|
||||
paramSchemas: trigger.parameters,
|
||||
params,
|
||||
})
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import { memo, useEffect, useMemo } from 'react'
|
|||
import { useAllTriggerPlugins } from '@/service/use-triggers'
|
||||
import TriggerPluginItem from './item'
|
||||
import type { BlockEnum } from '../../types'
|
||||
import type { ToolDefaultValue } from '../types'
|
||||
import type { TriggerDefaultValue } from '../types'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
|
||||
type TriggerPluginListProps = {
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
onSelect: (type: BlockEnum, trigger?: TriggerDefaultValue) => void
|
||||
searchText: string
|
||||
onContentStateChange?: (hasContent: boolean) => void
|
||||
tags?: string[]
|
||||
|
|
@ -24,13 +24,13 @@ const TriggerPluginList = ({
|
|||
|
||||
const triggerPlugins = useMemo(() => {
|
||||
// Follow exact same pattern as tools
|
||||
return (triggerPluginsData || []).filter((toolWithProvider) => {
|
||||
if (toolWithProvider.tools.length === 0) return false
|
||||
return (triggerPluginsData || []).filter((triggerWithProvider) => {
|
||||
if (triggerWithProvider.triggers.length === 0) return false
|
||||
|
||||
// Filter by search text
|
||||
if (searchText) {
|
||||
const matchesSearch = toolWithProvider.name.toLowerCase().includes(searchText.toLowerCase())
|
||||
|| toolWithProvider.tools.some(tool =>
|
||||
const matchesSearch = triggerWithProvider.name.toLowerCase().includes(searchText.toLowerCase())
|
||||
|| triggerWithProvider.triggers.some(tool =>
|
||||
tool.label[language].toLowerCase().includes(searchText.toLowerCase()),
|
||||
)
|
||||
if (!matchesSearch) return false
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { PluginMeta } from '../../plugins/types'
|
||||
import type { Collection, Tool } from '../../tools/types'
|
||||
import type { Collection, Trigger } from '../../tools/types'
|
||||
import type { TypeWithI18N } from '../../base/form/types'
|
||||
|
||||
export enum TabsEnum {
|
||||
|
|
@ -24,11 +24,32 @@ export enum BlockClassificationEnum {
|
|||
Utilities = 'utilities',
|
||||
}
|
||||
|
||||
export type ToolDefaultValue = {
|
||||
export type PluginDefaultValue = {
|
||||
provider_id: string
|
||||
provider_type: string
|
||||
provider_name: string
|
||||
tool_name: string
|
||||
plugin_name: string
|
||||
plugin_label: string
|
||||
}
|
||||
|
||||
export type TriggerDefaultValue = PluginDefaultValue & {
|
||||
trigger_name: string
|
||||
trigger_label: string
|
||||
trigger_description: string
|
||||
title: string
|
||||
is_team_authorization: boolean
|
||||
params: Record<string, any>
|
||||
paramSchemas: Record<string, any>[]
|
||||
output_schema: Record<string, any>
|
||||
credential_id?: string
|
||||
meta?: PluginMeta
|
||||
}
|
||||
|
||||
export type ToolDefaultValue = PluginDefaultValue & {
|
||||
provider_id: string
|
||||
provider_type: string
|
||||
provider_name: string
|
||||
trigger_name: string
|
||||
tool_label: string
|
||||
tool_description: string
|
||||
title: string
|
||||
|
|
@ -55,6 +76,7 @@ export type ToolValue = {
|
|||
|
||||
// Backend API types - exact match with Python definitions
|
||||
export type TriggerParameter = {
|
||||
multiple: boolean
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
description?: TypeWithI18N
|
||||
|
|
@ -141,7 +163,7 @@ export type TriggerProviderApiEntity = {
|
|||
|
||||
// Frontend types - compatible with ToolWithProvider
|
||||
export type TriggerWithProvider = Collection & {
|
||||
tools: Tool[] // Use existing Tool type for compatibility
|
||||
triggers: Trigger[]
|
||||
meta: PluginMeta
|
||||
credentials_schema?: TriggerCredentialField[]
|
||||
oauth_client_schema?: TriggerCredentialField[]
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
|
|||
viewType={viewType}
|
||||
onSelect={(_, tool) => {
|
||||
onChange({
|
||||
agent_strategy_name: tool!.tool_name,
|
||||
agent_strategy_name: tool!.trigger_name,
|
||||
agent_strategy_provider_name: tool!.provider_name,
|
||||
agent_strategy_label: tool!.tool_label,
|
||||
agent_output_schema: tool!.output_schema,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import type { ToolVarInputs } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { type BaseResource, type BaseResourceProvider, type ResourceVarInputs, VarKindType } from '../types'
|
||||
import type { CredentialFormSchema, FormOption } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { useFetchDynamicOptions } from '@/service/use-plugins'
|
||||
|
||||
import type { ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import type { ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import FormInputTypeSwitch from './form-input-type-switch'
|
||||
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import MixedVariableTextInput from '@/app/components/workflow/nodes/tool/components/mixed-variable-text-input'
|
||||
import MixedVariableTextInput from './mixed-variable-text-input'
|
||||
import FormInputBoolean from './form-input-boolean'
|
||||
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
|
||||
import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector'
|
||||
|
|
@ -22,19 +21,20 @@ import VarReferencePicker from '@/app/components/workflow/nodes/_base/components
|
|||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
|
||||
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { RiCheckLine } from '@remixicon/react'
|
||||
type Props = {
|
||||
readOnly: boolean
|
||||
nodeId: string
|
||||
schema: CredentialFormSchema
|
||||
value: ToolVarInputs
|
||||
value: ResourceVarInputs
|
||||
onChange: (value: any) => void
|
||||
inPanel?: boolean
|
||||
currentTool?: Tool
|
||||
currentProvider?: ToolWithProvider
|
||||
currentResource?: BaseResource
|
||||
currentProvider?: BaseResourceProvider
|
||||
extraParams?: Record<string, any>
|
||||
providerType?: 'tool' | 'trigger'
|
||||
providerType?: string
|
||||
}
|
||||
|
||||
const FormInputItem: FC<Props> = ({
|
||||
|
|
@ -44,10 +44,10 @@ const FormInputItem: FC<Props> = ({
|
|||
value,
|
||||
onChange,
|
||||
inPanel,
|
||||
currentTool,
|
||||
currentResource,
|
||||
currentProvider,
|
||||
extraParams,
|
||||
providerType = 'tool',
|
||||
providerType,
|
||||
}) => {
|
||||
const language = useLanguage()
|
||||
const [dynamicOptions, setDynamicOptions] = useState<FormOption[] | null>(null)
|
||||
|
|
@ -59,6 +59,7 @@ const FormInputItem: FC<Props> = ({
|
|||
type,
|
||||
default: defaultValue,
|
||||
options,
|
||||
multiple,
|
||||
scope,
|
||||
} = schema as any
|
||||
const varInput = value[variable]
|
||||
|
|
@ -76,6 +77,7 @@ const FormInputItem: FC<Props> = ({
|
|||
const showTypeSwitch = isNumber || isBoolean || isObject || isArray
|
||||
const isConstant = varInput?.type === VarKindType.constant || !varInput?.type
|
||||
const showVariableSelector = isFile || varInput?.type === VarKindType.variable
|
||||
const isMultipleSelect = multiple && (isSelect || isDynamicSelect)
|
||||
|
||||
const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, {
|
||||
onlyLeafNodeVar: false,
|
||||
|
|
@ -138,7 +140,7 @@ const FormInputItem: FC<Props> = ({
|
|||
const { mutateAsync: fetchDynamicOptions } = useFetchDynamicOptions(
|
||||
currentProvider?.plugin_id || '',
|
||||
currentProvider?.name || '',
|
||||
currentTool?.name || '',
|
||||
currentResource?.name || '',
|
||||
variable || '',
|
||||
providerType,
|
||||
extraParams,
|
||||
|
|
@ -147,7 +149,7 @@ const FormInputItem: FC<Props> = ({
|
|||
// Fetch dynamic options when component mounts or dependencies change
|
||||
useEffect(() => {
|
||||
const fetchOptions = async () => {
|
||||
if (isDynamicSelect && currentTool && currentProvider) {
|
||||
if (isDynamicSelect && currentResource && currentProvider) {
|
||||
setIsLoadingOptions(true)
|
||||
try {
|
||||
const data = await fetchDynamicOptions()
|
||||
|
|
@ -164,7 +166,7 @@ const FormInputItem: FC<Props> = ({
|
|||
}
|
||||
|
||||
fetchOptions()
|
||||
}, [isDynamicSelect, currentTool?.name, currentProvider?.name, variable, extraParams])
|
||||
}, [isDynamicSelect, currentResource?.name, currentProvider?.name, variable, extraParams])
|
||||
|
||||
const handleTypeChange = (newType: string) => {
|
||||
if (newType === VarKindType.variable) {
|
||||
|
|
@ -200,6 +202,24 @@ const FormInputItem: FC<Props> = ({
|
|||
})
|
||||
}
|
||||
|
||||
const getSelectedLabels = (selectedValues: any[]) => {
|
||||
if (!selectedValues || selectedValues.length === 0)
|
||||
return ''
|
||||
|
||||
const optionsList = isDynamicSelect ? (dynamicOptions || options || []) : (options || [])
|
||||
const selectedOptions = optionsList.filter((opt: any) =>
|
||||
selectedValues.includes(opt.value),
|
||||
)
|
||||
|
||||
if (selectedOptions.length <= 2) {
|
||||
return selectedOptions
|
||||
.map((opt: any) => opt.label?.[language] || opt.label?.en_US || opt.value)
|
||||
.join(', ')
|
||||
}
|
||||
|
||||
return `${selectedOptions.length} selected`
|
||||
}
|
||||
|
||||
const handleAppOrModelSelect = (newValue: any) => {
|
||||
onChange({
|
||||
...value,
|
||||
|
|
@ -250,7 +270,7 @@ const FormInputItem: FC<Props> = ({
|
|||
onChange={handleValueChange}
|
||||
/>
|
||||
)}
|
||||
{isSelect && (
|
||||
{isSelect && !isMultipleSelect && (
|
||||
<SimpleSelect
|
||||
wrapperClassName='h-8 grow'
|
||||
disabled={readOnly}
|
||||
|
|
@ -277,7 +297,64 @@ const FormInputItem: FC<Props> = ({
|
|||
) : undefined}
|
||||
/>
|
||||
)}
|
||||
{isDynamicSelect && (
|
||||
{isSelect && isMultipleSelect && (
|
||||
<Listbox
|
||||
multiple
|
||||
value={varInput?.value || []}
|
||||
onChange={handleValueChange}
|
||||
disabled={readOnly}
|
||||
>
|
||||
<div className="relative">
|
||||
<ListboxButton className="relative h-8 w-full cursor-pointer rounded-lg bg-components-input-bg-normal px-3 py-1.5 text-left text-sm focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300">
|
||||
<span className="block truncate text-components-input-text-filled">
|
||||
{getSelectedLabels(varInput?.value) || placeholder?.[language] || placeholder?.en_US || 'Select options'}
|
||||
</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronDownIcon
|
||||
className="h-4 w-4 text-text-tertiary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</ListboxButton>
|
||||
<ListboxOptions className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-components-panel-bg-blur py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
|
||||
{options.filter((option: { show_on: any[] }) => {
|
||||
if (option.show_on?.length)
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
|
||||
return true
|
||||
}).map((option: { value: any; label: { [x: string]: any; en_US: any }; icon?: string }) => (
|
||||
<ListboxOption
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className={({ focus }) =>
|
||||
`relative cursor-pointer select-none py-2 pl-10 pr-4 ${
|
||||
focus ? 'bg-state-base-hover text-text-secondary' : 'text-text-primary'
|
||||
}`
|
||||
}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
{option.icon && (
|
||||
<img src={option.icon} alt="" className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
<span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}>
|
||||
{option.label[language] || option.label.en_US}
|
||||
</span>
|
||||
</div>
|
||||
{selected && (
|
||||
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-primary-600">
|
||||
<RiCheckLine className="h-4 w-4" aria-hidden="true" />
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ListboxOption>
|
||||
))}
|
||||
</ListboxOptions>
|
||||
</div>
|
||||
</Listbox>
|
||||
)}
|
||||
{isDynamicSelect && !isMultipleSelect && (
|
||||
<SimpleSelect
|
||||
wrapperClassName='h-8 grow'
|
||||
disabled={readOnly || isLoadingOptions}
|
||||
|
|
@ -304,6 +381,65 @@ const FormInputItem: FC<Props> = ({
|
|||
)}
|
||||
/>
|
||||
)}
|
||||
{isDynamicSelect && isMultipleSelect && (
|
||||
<Listbox
|
||||
multiple
|
||||
value={varInput?.value || []}
|
||||
onChange={handleValueChange}
|
||||
disabled={readOnly || isLoadingOptions}
|
||||
>
|
||||
<div className="relative">
|
||||
<ListboxButton className="relative h-8 w-full cursor-pointer rounded-lg bg-components-input-bg-normal px-3 py-1.5 text-left text-sm focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300">
|
||||
<span className="block truncate text-components-input-text-filled">
|
||||
{isLoadingOptions
|
||||
? 'Loading...'
|
||||
: getSelectedLabels(varInput?.value) || placeholder?.[language] || placeholder?.en_US || 'Select options'}
|
||||
</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronDownIcon
|
||||
className="h-4 w-4 text-text-tertiary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</ListboxButton>
|
||||
<ListboxOptions className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-components-panel-bg-blur py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
|
||||
{(dynamicOptions || options || []).filter((option: { show_on?: any[] }) => {
|
||||
if (option.show_on?.length)
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
|
||||
return true
|
||||
}).map((option: { value: any; label: { [x: string]: any; en_US: any }; icon?: string }) => (
|
||||
<ListboxOption
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className={({ focus }) =>
|
||||
`relative cursor-pointer select-none py-2 pl-10 pr-4 ${
|
||||
focus ? 'bg-state-base-hover text-text-secondary' : 'text-text-primary'
|
||||
}`
|
||||
}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
{option.icon && (
|
||||
<img src={option.icon} alt="" className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
<span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}>
|
||||
{option.label[language] || option.label.en_US}
|
||||
</span>
|
||||
</div>
|
||||
{selected && (
|
||||
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-primary-600">
|
||||
<RiCheckLine className="h-4 w-4" aria-hidden="true" />
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ListboxOption>
|
||||
))}
|
||||
</ListboxOptions>
|
||||
</div>
|
||||
</Listbox>
|
||||
)}
|
||||
{isShowJSONEditor && isConstant && (
|
||||
<div className='mt-1 w-full'>
|
||||
<CodeEditor
|
||||
|
|
@ -349,7 +485,7 @@ const FormInputItem: FC<Props> = ({
|
|||
filterVar={getFilterVar()}
|
||||
schema={schema}
|
||||
valueTypePlaceHolder={targetVarType()}
|
||||
currentTool={currentTool}
|
||||
currentResource={currentResource}
|
||||
currentProvider={currentProvider}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
import {
|
||||
memo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import Placeholder from './placeholder'
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type MixedVariableTextInputProps = {
|
||||
readOnly?: boolean
|
||||
nodesOutputVars?: NodeOutPutVar[]
|
||||
availableNodes?: Node[]
|
||||
value?: string
|
||||
onChange?: (text: string) => void
|
||||
}
|
||||
const MixedVariableTextInput = ({
|
||||
readOnly = false,
|
||||
nodesOutputVars,
|
||||
availableNodes = [],
|
||||
value = '',
|
||||
onChange,
|
||||
}: MixedVariableTextInputProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<PromptEditor
|
||||
wrapperClassName={cn(
|
||||
'w-full rounded-lg border border-transparent bg-components-input-bg-normal px-2 py-1',
|
||||
'hover:border-components-input-border-hover hover:bg-components-input-bg-hover',
|
||||
'focus-within:border-components-input-border-active focus-within:bg-components-input-bg-active focus-within:shadow-xs',
|
||||
)}
|
||||
className='caret:text-text-accent'
|
||||
editable={!readOnly}
|
||||
value={value}
|
||||
workflowVariableBlock={{
|
||||
show: true,
|
||||
variables: nodesOutputVars || [],
|
||||
workflowNodesMap: availableNodes.reduce((acc, node) => {
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
type: BlockEnum.Start,
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {} as any),
|
||||
}}
|
||||
placeholder={<Placeholder />}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(MixedVariableTextInput)
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { FOCUS_COMMAND } from 'lexical'
|
||||
import { $insertNodes } from 'lexical'
|
||||
import { CustomTextNode } from '@/app/components/base/prompt-editor/plugins/custom-text/node'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
|
||||
const Placeholder = () => {
|
||||
const { t } = useTranslation()
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
const handleInsert = useCallback((text: string) => {
|
||||
editor.update(() => {
|
||||
const textNode = new CustomTextNode(text)
|
||||
$insertNodes([textNode])
|
||||
})
|
||||
editor.dispatchCommand(FOCUS_COMMAND, undefined as any)
|
||||
}, [editor])
|
||||
|
||||
return (
|
||||
<div
|
||||
className='pointer-events-auto flex h-full w-full cursor-text items-center px-2'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
handleInsert('')
|
||||
}}
|
||||
>
|
||||
<div className='flex grow items-center'>
|
||||
{t('workflow.nodes.tool.insertPlaceholder1')}
|
||||
<div className='system-kbd mx-0.5 flex h-4 w-4 items-center justify-center rounded bg-components-kbd-bg-gray text-text-placeholder'>/</div>
|
||||
<div
|
||||
className='system-sm-regular cursor-pointer text-components-input-text-placeholder underline decoration-dotted decoration-auto underline-offset-auto hover:text-text-tertiary'
|
||||
onMouseDown={((e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
handleInsert('/')
|
||||
})}
|
||||
>
|
||||
{t('workflow.nodes.tool.insertPlaceholder2')}
|
||||
</div>
|
||||
</div>
|
||||
<Badge
|
||||
className='shrink-0'
|
||||
text='String'
|
||||
uppercase={false}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Placeholder
|
||||
|
|
@ -17,7 +17,7 @@ import VarReferencePopup from './var-reference-popup'
|
|||
import { getNodeInfoById, isConversationVar, isENV, isSystemVar, varTypeToStructType } from './utils'
|
||||
import ConstantField from './constant-field'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { Node, NodeOutPutVar, ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import type { Node, NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import type { CredentialFormSchemaSelect } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { type CredentialFormSchema, type FormOption, FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -34,6 +34,7 @@ import {
|
|||
useWorkflowVariables,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import type { BaseResource, BaseResourceProvider } from '@/app/components/workflow/nodes/_base/types'
|
||||
import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
|
||||
import AddButton from '@/app/components/base/button/add-button'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
|
|
@ -42,7 +43,6 @@ import { isExceptionVariable } from '@/app/components/workflow/utils'
|
|||
import VarFullPathPanel from './var-full-path-panel'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useFetchDynamicOptions } from '@/service/use-plugins'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
|
||||
const TRIGGER_DEFAULT_WIDTH = 227
|
||||
|
|
@ -72,8 +72,8 @@ type Props = {
|
|||
minWidth?: number
|
||||
popupFor?: 'assigned' | 'toAssigned'
|
||||
zIndex?: number
|
||||
currentTool?: Tool
|
||||
currentProvider?: ToolWithProvider
|
||||
currentResource?: BaseResource
|
||||
currentProvider?: BaseResourceProvider
|
||||
}
|
||||
|
||||
const DEFAULT_VALUE_SELECTOR: Props['value'] = []
|
||||
|
|
@ -103,7 +103,7 @@ const VarReferencePicker: FC<Props> = ({
|
|||
minWidth,
|
||||
popupFor,
|
||||
zIndex,
|
||||
currentTool,
|
||||
currentResource,
|
||||
currentProvider,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -328,11 +328,11 @@ const VarReferencePicker: FC<Props> = ({
|
|||
const [dynamicOptions, setDynamicOptions] = useState<FormOption[] | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { mutateAsync: fetchDynamicOptions } = useFetchDynamicOptions(
|
||||
currentProvider?.plugin_id || '', currentProvider?.name || '', currentTool?.name || '', (schema as CredentialFormSchemaSelect)?.variable || '',
|
||||
currentProvider?.plugin_id || '', currentProvider?.name || '', currentResource?.name || '', (schema as CredentialFormSchemaSelect)?.variable || '',
|
||||
'tool',
|
||||
)
|
||||
const handleFetchDynamicOptions = async () => {
|
||||
if (schema?.type !== FormTypeEnum.dynamicSelect || !currentTool || !currentProvider)
|
||||
if (schema?.type !== FormTypeEnum.dynamicSelect || !currentResource || !currentProvider)
|
||||
return
|
||||
setIsLoading(true)
|
||||
try {
|
||||
|
|
@ -345,7 +345,7 @@ const VarReferencePicker: FC<Props> = ({
|
|||
}
|
||||
useEffect(() => {
|
||||
handleFetchDynamicOptions()
|
||||
}, [currentTool, currentProvider, schema])
|
||||
}, [currentResource, currentProvider, schema])
|
||||
|
||||
const schemaWithDynamicSelect = useMemo(() => {
|
||||
if (schema?.type !== FormTypeEnum.dynamicSelect)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import type { ValueSelector } from '@/app/components/workflow/types'
|
||||
|
||||
// Generic variable types for all resource forms
|
||||
export enum VarKindType {
|
||||
variable = 'variable',
|
||||
constant = 'constant',
|
||||
mixed = 'mixed',
|
||||
}
|
||||
|
||||
// Generic resource variable inputs
|
||||
export type ResourceVarInputs = Record<string, {
|
||||
type: VarKindType
|
||||
value?: string | ValueSelector | any
|
||||
}>
|
||||
|
||||
// Base resource interface
|
||||
export type BaseResource = {
|
||||
name: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// Base resource provider interface
|
||||
export type BaseResourceProvider = {
|
||||
plugin_id?: string
|
||||
name: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ const ImportFromTool: FC<Props> = ({
|
|||
const workflowTools = useStore(s => s.workflowTools)
|
||||
|
||||
const handleSelectTool = useCallback((_type: BlockEnum, toolInfo?: ToolDefaultValue) => {
|
||||
const { provider_id, provider_type, tool_name } = toolInfo!
|
||||
const { provider_id, provider_type, trigger_name: tool_name } = toolInfo!
|
||||
const currentTools = (() => {
|
||||
switch (provider_type) {
|
||||
case CollectionType.builtIn:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ type Props = {
|
|||
currentTool?: Tool
|
||||
currentProvider?: ToolWithProvider
|
||||
extraParams?: Record<string, any>
|
||||
providerType?: 'tool' | 'trigger'
|
||||
}
|
||||
|
||||
const ToolForm: FC<Props> = ({
|
||||
|
|
@ -30,7 +29,6 @@ const ToolForm: FC<Props> = ({
|
|||
currentTool,
|
||||
currentProvider,
|
||||
extraParams,
|
||||
providerType = 'tool',
|
||||
}) => {
|
||||
return (
|
||||
<div className='space-y-1'>
|
||||
|
|
@ -47,7 +45,7 @@ const ToolForm: FC<Props> = ({
|
|||
currentTool={currentTool}
|
||||
currentProvider={currentProvider}
|
||||
extraParams={extraParams}
|
||||
providerType={providerType}
|
||||
providerType='tool'
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ const ToolFormItem: FC<Props> = ({
|
|||
value={value}
|
||||
onChange={onChange}
|
||||
inPanel={inPanel}
|
||||
currentTool={currentTool}
|
||||
currentResource={currentTool}
|
||||
currentProvider={currentProvider}
|
||||
extraParams={extraParams}
|
||||
providerType={providerType}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
import type { CollectionType } from '@/app/components/tools/types'
|
||||
import type { CommonNodeType, ValueSelector } from '@/app/components/workflow/types'
|
||||
import type { CommonNodeType } from '@/app/components/workflow/types'
|
||||
import type { ResourceVarInputs } from '../_base/types'
|
||||
|
||||
export enum VarType {
|
||||
variable = 'variable',
|
||||
constant = 'constant',
|
||||
mixed = 'mixed',
|
||||
}
|
||||
|
||||
export type ToolVarInputs = Record<string, {
|
||||
type: VarType
|
||||
value?: string | ValueSelector | any
|
||||
}>
|
||||
// Use base types directly
|
||||
export { VarKindType as VarType } from '../_base/types'
|
||||
export type ToolVarInputs = ResourceVarInputs
|
||||
|
||||
export type ToolNodeType = CommonNodeType & {
|
||||
provider_id: string
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ const useConfig = (id: string, payload: ToolNodeType) => {
|
|||
* tool_parameters: tool dynamic setting(form type = llm)
|
||||
* output_schema: tool dynamic output
|
||||
*/
|
||||
const { provider_id, provider_type, tool_name, tool_configurations, output_schema, tool_parameters } = inputs
|
||||
const { provider_id, provider_type, trigger_name: tool_name, tool_configurations, output_schema, tool_parameters } = inputs
|
||||
const isBuiltIn = provider_type === CollectionType.builtIn
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/block
|
|||
const nodeDefault: NodeDefault<PluginTriggerNodeType> = {
|
||||
defaultValue: {
|
||||
plugin_id: '',
|
||||
tool_name: '',
|
||||
trigger_name: '',
|
||||
event_type: '',
|
||||
config: {},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Split from '@/app/components/workflow/nodes/_base/components/split'
|
|||
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
|
||||
import type { NodePanelProps } from '@/app/components/workflow/types'
|
||||
import useConfig from './use-config'
|
||||
import ToolForm from '@/app/components/workflow/nodes/tool/components/tool-form'
|
||||
import TriggerForm from './trigger-form'
|
||||
import StructureOutputItem from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show'
|
||||
import { Type } from '../llm/types'
|
||||
|
||||
|
|
@ -21,6 +21,8 @@ const Panel: FC<NodePanelProps<PluginTriggerNodeType>> = ({
|
|||
outputSchema,
|
||||
hasObjectOutput,
|
||||
isAuthenticated,
|
||||
currentProvider,
|
||||
currentTrigger,
|
||||
} = useConfig(id, data)
|
||||
|
||||
// Convert output schema to VarItem format
|
||||
|
|
@ -36,13 +38,14 @@ const Panel: FC<NodePanelProps<PluginTriggerNodeType>> = ({
|
|||
{isAuthenticated && triggerParameterSchema.length > 0 && (
|
||||
<>
|
||||
<div className='px-4 pb-4'>
|
||||
<ToolForm
|
||||
<TriggerForm
|
||||
readOnly={readOnly}
|
||||
nodeId={id}
|
||||
schema={triggerParameterSchema as any}
|
||||
value={triggerParameterValue}
|
||||
onChange={setTriggerParameterValue}
|
||||
providerType="trigger"
|
||||
currentProvider={currentProvider}
|
||||
currentTrigger={currentTrigger}
|
||||
/>
|
||||
</div>
|
||||
<Split />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
'use client'
|
||||
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { Trigger } from '@/app/components/tools/types'
|
||||
import type { FC } from 'react'
|
||||
import type { PluginTriggerVarInputs } from '../types'
|
||||
import TriggerFormItem from './item'
|
||||
import type { TriggerWithProvider } from '../../../block-selector/types'
|
||||
|
||||
type Props = {
|
||||
readOnly: boolean
|
||||
nodeId: string
|
||||
schema: CredentialFormSchema[]
|
||||
value: PluginTriggerVarInputs
|
||||
onChange: (value: PluginTriggerVarInputs) => void
|
||||
onOpen?: (index: number) => void
|
||||
inPanel?: boolean
|
||||
currentTrigger?: Trigger
|
||||
currentProvider?: TriggerWithProvider
|
||||
extraParams?: Record<string, any>
|
||||
}
|
||||
|
||||
const TriggerForm: FC<Props> = ({
|
||||
readOnly,
|
||||
nodeId,
|
||||
schema,
|
||||
value,
|
||||
onChange,
|
||||
inPanel,
|
||||
currentTrigger,
|
||||
currentProvider,
|
||||
extraParams,
|
||||
}) => {
|
||||
return (
|
||||
<div className='space-y-1'>
|
||||
{
|
||||
schema.map((schema, index) => (
|
||||
<TriggerFormItem
|
||||
key={index}
|
||||
readOnly={readOnly}
|
||||
nodeId={nodeId}
|
||||
schema={schema}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
inPanel={inPanel}
|
||||
currentTrigger={currentTrigger}
|
||||
currentProvider={currentProvider}
|
||||
extraParams={extraParams}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default TriggerForm
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import {
|
||||
RiBracesLine,
|
||||
} from '@remixicon/react'
|
||||
import type { PluginTriggerVarInputs } from '../types'
|
||||
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import FormInputItem from '@/app/components/workflow/nodes/_base/components/form-input-item'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import SchemaModal from '@/app/components/plugins/plugin-detail-panel/tool-selector/schema-modal'
|
||||
import type { Trigger } from '@/app/components/tools/types'
|
||||
import type { TriggerWithProvider } from '../../../block-selector/types'
|
||||
|
||||
type Props = {
|
||||
readOnly: boolean
|
||||
nodeId: string
|
||||
schema: CredentialFormSchema
|
||||
value: PluginTriggerVarInputs
|
||||
onChange: (value: PluginTriggerVarInputs) => void
|
||||
inPanel?: boolean
|
||||
currentTrigger?: Trigger
|
||||
currentProvider?: TriggerWithProvider
|
||||
extraParams?: Record<string, any>
|
||||
}
|
||||
|
||||
const TriggerFormItem: FC<Props> = ({
|
||||
readOnly,
|
||||
nodeId,
|
||||
schema,
|
||||
value,
|
||||
onChange,
|
||||
inPanel,
|
||||
currentTrigger,
|
||||
currentProvider,
|
||||
extraParams,
|
||||
}) => {
|
||||
const language = useLanguage()
|
||||
const { name, label, type, required, tooltip, input_schema } = schema
|
||||
const showSchemaButton = type === FormTypeEnum.object || type === FormTypeEnum.array
|
||||
const showDescription = type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput
|
||||
const [isShowSchema, {
|
||||
setTrue: showSchema,
|
||||
setFalse: hideSchema,
|
||||
}] = useBoolean(false)
|
||||
return (
|
||||
<div className='space-y-0.5 py-1'>
|
||||
<div>
|
||||
<div className='flex h-6 items-center'>
|
||||
<div className='system-sm-medium text-text-secondary'>{label[language] || label.en_US}</div>
|
||||
{required && (
|
||||
<div className='system-xs-regular ml-1 text-text-destructive-secondary'>*</div>
|
||||
)}
|
||||
{!showDescription && tooltip && (
|
||||
<Tooltip
|
||||
popupContent={<div className='w-[200px]'>
|
||||
{tooltip[language] || tooltip.en_US}
|
||||
</div>}
|
||||
triggerClassName='ml-1 w-4 h-4'
|
||||
asChild={false}
|
||||
/>
|
||||
)}
|
||||
{showSchemaButton && (
|
||||
<>
|
||||
<div className='system-xs-regular ml-1 mr-0.5 text-text-quaternary'>·</div>
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='small'
|
||||
onClick={showSchema}
|
||||
className='system-xs-regular px-1 text-text-tertiary'
|
||||
>
|
||||
<RiBracesLine className='mr-1 size-3.5' />
|
||||
<span>JSON Schema</span>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{showDescription && tooltip && (
|
||||
<div className='body-xs-regular pb-0.5 text-text-tertiary'>{tooltip[language] || tooltip.en_US}</div>
|
||||
)}
|
||||
</div>
|
||||
<FormInputItem
|
||||
readOnly={readOnly}
|
||||
nodeId={nodeId}
|
||||
schema={schema}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
inPanel={inPanel}
|
||||
currentResource={currentTrigger}
|
||||
currentProvider={currentProvider}
|
||||
providerType='trigger'
|
||||
extraParams={extraParams}
|
||||
/>
|
||||
|
||||
{isShowSchema && (
|
||||
<SchemaModal
|
||||
isShow
|
||||
onClose={hideSchema}
|
||||
rootName={name}
|
||||
schema={input_schema!}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default TriggerFormItem
|
||||
|
|
@ -1,12 +1,23 @@
|
|||
import type { CommonNodeType } from '@/app/components/workflow/types'
|
||||
import type { CollectionType } from '@/app/components/tools/types'
|
||||
import type { ResourceVarInputs } from '../_base/types'
|
||||
|
||||
export type PluginTriggerNodeType = CommonNodeType & {
|
||||
provider_id: string
|
||||
provider_type: CollectionType
|
||||
provider_name: string
|
||||
trigger_name: string
|
||||
trigger_label: string
|
||||
trigger_parameters: PluginTriggerVarInputs
|
||||
trigger_configurations: Record<string, any>
|
||||
output_schema: Record<string, any>
|
||||
parameters_schema?: Record<string, any>[]
|
||||
version?: string
|
||||
trigger_node_version?: string
|
||||
plugin_id?: string
|
||||
tool_name?: string
|
||||
event_type?: string
|
||||
config?: Record<string, any>
|
||||
provider_id?: string
|
||||
provider_type?: CollectionType
|
||||
provider_name?: string
|
||||
}
|
||||
|
||||
// Use base types directly
|
||||
export { VarKindType as PluginTriggerVarType } from '../_base/types'
|
||||
export type PluginTriggerVarInputs = ResourceVarInputs
|
||||
|
|
|
|||
|
|
@ -3,27 +3,32 @@ import produce from 'immer'
|
|||
import type { PluginTriggerNodeType } from './types'
|
||||
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||
import { useNodesReadOnly } from '@/app/components/workflow/hooks'
|
||||
import { useAllTriggerPlugins, useTriggerSubscriptions } from '@/service/use-triggers'
|
||||
import {
|
||||
useAllTriggerPlugins,
|
||||
useTriggerSubscriptions,
|
||||
} from '@/service/use-triggers'
|
||||
import {
|
||||
addDefaultValue,
|
||||
toolParametersToFormSchemas,
|
||||
} from '@/app/components/tools/utils/to-form-schema'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import type { Trigger } from '@/app/components/tools/types'
|
||||
|
||||
const useConfig = (id: string, payload: PluginTriggerNodeType) => {
|
||||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
const { data: triggerPlugins = [] } = useAllTriggerPlugins()
|
||||
|
||||
const { inputs, setInputs: doSetInputs } = useNodeCrud<PluginTriggerNodeType>(id, payload)
|
||||
const { inputs, setInputs: doSetInputs } = useNodeCrud<PluginTriggerNodeType>(
|
||||
id,
|
||||
payload,
|
||||
)
|
||||
|
||||
const { provider_id, provider_name, tool_name, config } = inputs
|
||||
const { provider_id, provider_name, trigger_name, config } = inputs
|
||||
|
||||
// Construct provider for authentication check
|
||||
const authProvider = useMemo(() => {
|
||||
if (provider_id && provider_name)
|
||||
return `${provider_id}/${provider_name}`
|
||||
if (provider_id && provider_name) return `${provider_id}/${provider_name}`
|
||||
return provider_id || ''
|
||||
}, [provider_id, provider_name])
|
||||
|
||||
|
|
@ -33,21 +38,26 @@ const useConfig = (id: string, payload: PluginTriggerNodeType) => {
|
|||
)
|
||||
|
||||
const currentProvider = useMemo<TriggerWithProvider | undefined>(() => {
|
||||
return triggerPlugins.find(provider =>
|
||||
provider.name === provider_name
|
||||
|| provider.id === provider_id
|
||||
|| (provider_id && provider.plugin_id === provider_id),
|
||||
return triggerPlugins.find(
|
||||
provider =>
|
||||
provider.name === provider_name
|
||||
|| provider.id === provider_id
|
||||
|| (provider_id && provider.plugin_id === provider_id),
|
||||
)
|
||||
}, [triggerPlugins, provider_name, provider_id])
|
||||
|
||||
const currentTrigger = useMemo<Tool | undefined>(() => {
|
||||
return currentProvider?.tools.find(tool => tool.name === tool_name)
|
||||
}, [currentProvider, tool_name])
|
||||
const currentTrigger = useMemo<Trigger | undefined>(() => {
|
||||
return currentProvider?.triggers.find(
|
||||
trigger => trigger.name === trigger_name,
|
||||
)
|
||||
}, [currentProvider, trigger_name])
|
||||
|
||||
// Dynamic subscription parameters (from subscription_schema.parameters_schema)
|
||||
const subscriptionParameterSchema = useMemo(() => {
|
||||
if (!currentProvider?.subscription_schema?.parameters_schema) return []
|
||||
return toolParametersToFormSchemas(currentProvider.subscription_schema.parameters_schema as any)
|
||||
return toolParametersToFormSchemas(
|
||||
currentProvider.subscription_schema.parameters_schema as any,
|
||||
)
|
||||
}, [currentProvider])
|
||||
|
||||
// Dynamic trigger parameters (from specific trigger.parameters)
|
||||
|
|
@ -66,22 +76,28 @@ const useConfig = (id: string, payload: PluginTriggerNodeType) => {
|
|||
return addDefaultValue(config || {}, triggerParameterSchema)
|
||||
}, [triggerParameterSchema, config])
|
||||
|
||||
const setTriggerParameterValue = useCallback((value: Record<string, any>) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.config = value
|
||||
})
|
||||
doSetInputs(newInputs)
|
||||
}, [inputs, doSetInputs])
|
||||
const setTriggerParameterValue = useCallback(
|
||||
(value: Record<string, any>) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.config = value
|
||||
})
|
||||
doSetInputs(newInputs)
|
||||
},
|
||||
[inputs, doSetInputs],
|
||||
)
|
||||
|
||||
const setInputVar = useCallback((variable: InputVar, varDetail: InputVar) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.config = {
|
||||
...draft.config,
|
||||
[variable.variable]: varDetail.variable,
|
||||
}
|
||||
})
|
||||
doSetInputs(newInputs)
|
||||
}, [inputs, doSetInputs])
|
||||
const setInputVar = useCallback(
|
||||
(variable: InputVar, varDetail: InputVar) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.config = {
|
||||
...draft.config,
|
||||
[variable.variable]: varDetail.variable,
|
||||
}
|
||||
})
|
||||
doSetInputs(newInputs)
|
||||
},
|
||||
[inputs, doSetInputs],
|
||||
)
|
||||
|
||||
// Get output schema
|
||||
const outputSchema = useMemo(() => {
|
||||
|
|
@ -91,7 +107,9 @@ const useConfig = (id: string, payload: PluginTriggerNodeType) => {
|
|||
// Check if trigger has complex output structure
|
||||
const hasObjectOutput = useMemo(() => {
|
||||
const properties = outputSchema.properties || {}
|
||||
return Object.values(properties).some((prop: any) => prop.type === 'object')
|
||||
return Object.values(properties).some(
|
||||
(prop: any) => prop.type === 'object',
|
||||
)
|
||||
}, [outputSchema])
|
||||
|
||||
// Authentication status check
|
||||
|
|
@ -109,10 +127,16 @@ const useConfig = (id: string, payload: PluginTriggerNodeType) => {
|
|||
|
||||
const methods = []
|
||||
|
||||
if (currentProvider.oauth_client_schema && currentProvider.oauth_client_schema.length > 0)
|
||||
if (
|
||||
currentProvider.oauth_client_schema
|
||||
&& currentProvider.oauth_client_schema.length > 0
|
||||
)
|
||||
methods.push('oauth')
|
||||
|
||||
if (currentProvider.credentials_schema && currentProvider.credentials_schema.length > 0)
|
||||
if (
|
||||
currentProvider.credentials_schema
|
||||
&& currentProvider.credentials_schema.length > 0
|
||||
)
|
||||
methods.push('api_key')
|
||||
|
||||
return methods
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type {
|
|||
XYPosition,
|
||||
} from 'reactflow'
|
||||
import type { Resolution, TransferMethod } from '@/types/app'
|
||||
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||
import type { PluginDefaultValue, ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||
import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import type { FileResponse, NodeTracing, PanelProps } from '@/types/workflow'
|
||||
import type { Collection, Tool } from '@/app/components/tools/types'
|
||||
|
|
@ -321,7 +321,7 @@ export type NodeDefault<T> = {
|
|||
checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string }
|
||||
}
|
||||
|
||||
export type OnSelectBlock = (type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => void
|
||||
export type OnSelectBlock = (type: BlockEnum, pluginDefaultValue?: PluginDefaultValue) => void
|
||||
|
||||
export enum WorkflowRunningStatus {
|
||||
Waiting = 'waiting',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const getToolCheckParams = (
|
|||
workflowTools: ToolWithProvider[],
|
||||
language: string,
|
||||
) => {
|
||||
const { provider_id, provider_type, tool_name } = toolData
|
||||
const { provider_id, provider_type, trigger_name: tool_name } = toolData
|
||||
const isBuiltIn = provider_type === CollectionType.builtIn
|
||||
const currentTools = provider_type === CollectionType.builtIn ? buildInTools : provider_type === CollectionType.custom ? customTools : workflowTools
|
||||
const currCollection = currentTools.find(item => canFindTool(item.id, provider_id))
|
||||
|
|
|
|||
|
|
@ -613,7 +613,7 @@ export const usePluginInfo = (providerName?: string) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const useFetchDynamicOptions = (plugin_id: string, provider: string, action: string, parameter: string, provider_type: 'tool' | 'trigger', extra?: Record<string, any>) => {
|
||||
export const useFetchDynamicOptions = (plugin_id: string, provider: string, action: string, parameter: string, provider_type?: string, extra?: Record<string, any>) => {
|
||||
return useMutation({
|
||||
mutationFn: () => get<{ options: FormOption[] }>('/workspaces/current/plugin/parameters/dynamic-options', {
|
||||
params: {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ const convertToTriggerWithProvider = (provider: TriggerProviderApiEntity): Trigg
|
|||
allow_delete: false,
|
||||
labels: provider.tags || [],
|
||||
plugin_id: provider.plugin_id,
|
||||
|
||||
// ToolWithProvider fields - convert "triggers" to "tools"
|
||||
tools: provider.triggers.map(trigger => ({
|
||||
triggers: provider.triggers.map(trigger => ({
|
||||
name: trigger.name,
|
||||
author: provider.author,
|
||||
label: trigger.description.human, // Already TypeWithI18N format
|
||||
|
|
@ -51,6 +49,7 @@ const convertToTriggerWithProvider = (provider: TriggerProviderApiEntity): Trigg
|
|||
label: option.label,
|
||||
value: option.value,
|
||||
})) || [],
|
||||
multiple: param.multiple || false,
|
||||
})),
|
||||
labels: provider.tags || [],
|
||||
output_schema: trigger.output_schema || {},
|
||||
|
|
|
|||
Loading…
Reference in New Issue