feat(trigger): add API endpoint to retrieve trigger plugin icons and enhance workflow response handling

- Introduced `TriggerProviderIconApi` to fetch icons for trigger plugins based on tenant and provider ID.
- Updated `WorkflowResponseConverter` to include trigger plugin icons in the response.
- Implemented `get_trigger_plugin_icon` method in `TriggerManager` for icon retrieval logic.
- Adjusted `Node` class to correctly set provider information for trigger plugins.
- Modified TypeScript types to accommodate new provider ID field in workflow nodes.
This commit is contained in:
Harry 2025-10-13 16:50:12 +08:00
parent cce729916a
commit b283a2b3d9
7 changed files with 55 additions and 7 deletions

View File

@ -25,6 +25,18 @@ from services.trigger.workflow_plugin_trigger_service import WorkflowPluginTrigg
logger = logging.getLogger(__name__)
class TriggerProviderIconApi(Resource):
@setup_required
@login_required
@account_initialization_required
def get(self, provider):
user = current_user
assert isinstance(user, Account)
assert user.current_tenant_id is not None
return TriggerManager.get_trigger_plugin_icon(tenant_id=user.current_tenant_id, provider_id=provider)
class TriggerProviderListApi(Resource):
@setup_required
@login_required
@ -534,6 +546,7 @@ class TriggerOAuthClientManageApi(Resource):
# Trigger Subscription
api.add_resource(TriggerProviderIconApi, "/workspaces/current/trigger-provider/<path:provider>/icon")
api.add_resource(TriggerProviderListApi, "/workspaces/current/triggers")
api.add_resource(TriggerProviderInfoApi, "/workspaces/current/trigger-provider/<path:provider>/info")
api.add_resource(TriggerSubscriptionListApi, "/workspaces/current/trigger-provider/<path:provider>/subscriptions/list")

View File

@ -38,6 +38,7 @@ from core.file import FILE_MODEL_IDENTITY, File
from core.plugin.impl.datasource import PluginDatasourceManager
from core.tools.entities.tool_entities import ToolProviderType
from core.tools.tool_manager import ToolManager
from core.trigger.trigger_manager import TriggerManager
from core.variables.segments import ArrayFileSegment, FileSegment, Segment
from core.workflow.entities import WorkflowExecution, WorkflowNodeExecution
from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus
@ -181,6 +182,11 @@ class WorkflowResponseConverter:
response.data.extras["icon"] = provider_entity.declaration.identity.generate_datasource_icon_url(
self._application_generate_entity.app_config.tenant_id
)
elif event.node_type == NodeType.TRIGGER_PLUGIN:
response.data.extras["icon"] = TriggerManager.get_trigger_plugin_icon(
self._application_generate_entity.app_config.tenant_id,
event.provider_id,
)
return response

View File

@ -155,7 +155,8 @@ class TriggerProviderEntity(BaseModel):
default_factory=list,
description="The configuration schema stored in the subscription entity",
)
subscription_constructor: SubscriptionConstructor = Field(
subscription_constructor: SubscriptionConstructor | None = Field(
default=None,
description="The subscription constructor of the trigger provider",
)
events: list[EventEntity] = Field(default=[], description="The events of the trigger provider")

View File

@ -8,9 +8,11 @@ from threading import Lock
from typing import Any
from flask import Request
from yarl import URL
import contexts
from core.plugin.entities.plugin_daemon import CredentialType
from configs import dify_config
from core.plugin.entities.plugin_daemon import CredentialType, PluginTriggerProviderEntity
from core.plugin.entities.request import TriggerInvokeEventResponse
from core.plugin.impl.exc import PluginInvokeError
from core.plugin.impl.trigger import PluginTriggerManager
@ -30,6 +32,26 @@ class TriggerManager:
Manager for trigger providers and triggers
"""
@classmethod
def get_trigger_plugin_icon(cls, tenant_id: str, provider_id: str) -> str:
"""
Get the icon of a trigger plugin
"""
manager = PluginTriggerManager()
provider: PluginTriggerProviderEntity = manager.fetch_trigger_provider(
tenant_id=tenant_id, provider_id=TriggerProviderID(provider_id)
)
return str(
URL(dify_config.CONSOLE_API_URL or "/")
/ "console"
/ "api"
/ "workspaces"
/ "current"
/ "plugin"
/ "icon"
% {"tenant_id": tenant_id, "filename": provider.declaration.identity.icon}
)
@classmethod
def list_plugin_trigger_providers(cls, tenant_id: str) -> list[PluginTriggerProviderController]:
"""

View File

@ -122,6 +122,12 @@ class Node:
start_event.provider_id = f"{plugin_id}/{provider_name}"
start_event.provider_type = getattr(self.get_base_node_data(), "provider_type", "")
from core.workflow.nodes.trigger_plugin.trigger_plugin_node import TriggerPluginNode
if isinstance(self, TriggerPluginNode):
start_event.provider_id = getattr(self.get_base_node_data(), "provider_id", "")
start_event.provider_type = getattr(self.get_base_node_data(), "provider_type", "")
from typing import cast

View File

@ -7,7 +7,6 @@ import type { TestRunOptions, TriggerOption } from '../header/test-run-menu'
import { TriggerAll } from '@/app/components/base/icons/src/vender/workflow'
import BlockIcon from '../block-icon'
import { useStore } from '../store'
import { canFindTool } from '@/utils'
import { useAllTriggerPlugins } from '@/service/use-triggers'
export const useDynamicTestRunOptions = (): TestRunOptions => {
@ -74,18 +73,18 @@ export const useDynamicTestRunOptions = (): TestRunOptions => {
})
}
else if (nodeData.type === BlockEnum.TriggerPlugin) {
let toolIcon: string | any
let triggerIcon: string | any
if (nodeData.provider_id) {
const targetTools = triggerPlugins || []
toolIcon = targetTools.find(toolWithProvider => canFindTool(toolWithProvider.id, nodeData.provider_id!))?.icon
const targetTriggers = triggerPlugins || []
triggerIcon = targetTriggers.find(toolWithProvider => toolWithProvider.name === nodeData.provider_id)?.icon
}
const icon = (
<BlockIcon
type={BlockEnum.TriggerPlugin}
size='md'
toolIcon={toolIcon}
toolIcon={triggerIcon}
/>
)

View File

@ -104,6 +104,7 @@ export type CommonNodeType<T = {}> = {
default_value?: DefaultValueForm[]
credential_id?: string
subscription_id?: string
provider_id?: string
_dimmed?: boolean
} & T & Partial<PluginDefaultValue>