mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 12:37:20 +08:00
feat: when add/delete webhook trigger call the API (#24755)
This commit is contained in:
parent
a58df35ead
commit
19c0fc85e2
@ -63,6 +63,8 @@ import {
|
|||||||
import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
|
import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
|
||||||
import useInspectVarsCrud from './use-inspect-vars-crud'
|
import useInspectVarsCrud from './use-inspect-vars-crud'
|
||||||
import { getNodeUsedVars } from '../nodes/_base/components/variable/utils'
|
import { getNodeUsedVars } from '../nodes/_base/components/variable/utils'
|
||||||
|
import { deleteWebhookUrl } from '@/service/apps'
|
||||||
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
// Entry node deletion restriction has been removed to allow empty workflows
|
// Entry node deletion restriction has been removed to allow empty workflows
|
||||||
|
|
||||||
@ -74,6 +76,7 @@ export const useNodesInteractions = () => {
|
|||||||
const reactflow = useReactFlow()
|
const reactflow = useReactFlow()
|
||||||
const { store: workflowHistoryStore } = useWorkflowHistoryStore()
|
const { store: workflowHistoryStore } = useWorkflowHistoryStore()
|
||||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
const appId = useAppStore.getState().appDetail?.id
|
||||||
const {
|
const {
|
||||||
checkNestedParallelLimit,
|
checkNestedParallelLimit,
|
||||||
getAfterNodesInSameBranch,
|
getAfterNodesInSameBranch,
|
||||||
@ -588,6 +591,18 @@ export const useNodesInteractions = () => {
|
|||||||
return
|
return
|
||||||
|
|
||||||
deleteNodeInspectorVars(nodeId)
|
deleteNodeInspectorVars(nodeId)
|
||||||
|
|
||||||
|
if (currentNode.data.type === BlockEnum.TriggerWebhook) {
|
||||||
|
if (appId) {
|
||||||
|
try {
|
||||||
|
deleteWebhookUrl({ appId, nodeId })
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Failed to delete webhook URL:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (currentNode.data.type === BlockEnum.Iteration) {
|
if (currentNode.data.type === BlockEnum.Iteration) {
|
||||||
const iterationChildren = nodes.filter(node => node.parentId === currentNode.id)
|
const iterationChildren = nodes.filter(node => node.parentId === currentNode.id)
|
||||||
|
|
||||||
|
|||||||
@ -94,6 +94,7 @@ const Panel: FC<NodePanelProps<WebhookTriggerNodeType>> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
|
<span>{inputs.webhook_debug_url || ''}</span>
|
||||||
|
|
||||||
<Split />
|
<Split />
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export type WebhookHeader = {
|
|||||||
|
|
||||||
export type WebhookTriggerNodeType = CommonNodeType & {
|
export type WebhookTriggerNodeType = CommonNodeType & {
|
||||||
'webhook_url'?: string
|
'webhook_url'?: string
|
||||||
|
'webhook_debug_url'?: string
|
||||||
'method': HttpMethod
|
'method': HttpMethod
|
||||||
'content-type': string
|
'content-type': string
|
||||||
'headers': WebhookHeader[]
|
'headers': WebhookHeader[]
|
||||||
|
|||||||
@ -76,43 +76,29 @@ const useConfig = (id: string, payload: WebhookTriggerNodeType) => {
|
|||||||
const generateWebhookUrl = useCallback(async () => {
|
const generateWebhookUrl = useCallback(async () => {
|
||||||
// Idempotency: if we already have a URL, just return it.
|
// Idempotency: if we already have a URL, just return it.
|
||||||
if (inputs.webhook_url && inputs.webhook_url.length > 0)
|
if (inputs.webhook_url && inputs.webhook_url.length > 0)
|
||||||
return inputs.webhook_url
|
return
|
||||||
|
|
||||||
// Helper to build a deterministic mock URL for local/dev usage.
|
if (!appId)
|
||||||
const buildMockUrl = () => `https://mock.dify.local/webhook/${appId ?? 'app'}/${id}`
|
return
|
||||||
|
|
||||||
if (!appId) {
|
|
||||||
// No appId available yet (e.g. during creation): use mock URL.
|
|
||||||
const mockUrl = buildMockUrl()
|
|
||||||
const newInputs = produce(inputs, (draft) => {
|
|
||||||
draft.webhook_url = mockUrl
|
|
||||||
})
|
|
||||||
setInputs(newInputs)
|
|
||||||
return mockUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Call backend to generate or fetch webhook url for this node
|
// Call backend to generate or fetch webhook url for this node
|
||||||
const response = await fetchWebhookUrl({ appId, nodeId: id })
|
const response = await fetchWebhookUrl({ appId, nodeId: id })
|
||||||
const url = response.serverUrl
|
|
||||||
|
|
||||||
const newInputs = produce(inputs, (draft) => {
|
const newInputs = produce(inputs, (draft) => {
|
||||||
draft.webhook_url = url
|
draft.webhook_url = response.webhook_url
|
||||||
|
draft.webhook_debug_url = response.webhook_debug_url
|
||||||
})
|
})
|
||||||
setInputs(newInputs)
|
setInputs(newInputs)
|
||||||
|
|
||||||
return url
|
|
||||||
}
|
}
|
||||||
catch (error: unknown) {
|
catch (error: unknown) {
|
||||||
// Fallback to mock URL when API is not ready or request fails
|
// Fallback to mock URL when API is not ready or request fails
|
||||||
// Keep the UI unblocked and allow users to proceed in local/dev environments.
|
// Keep the UI unblocked and allow users to proceed in local/dev environments.
|
||||||
console.error('Failed to generate webhook URL:', error)
|
console.error('Failed to generate webhook URL:', error)
|
||||||
const mockUrl = buildMockUrl()
|
|
||||||
const newInputs = produce(inputs, (draft) => {
|
const newInputs = produce(inputs, (draft) => {
|
||||||
draft.webhook_url = mockUrl
|
draft.webhook_url = ''
|
||||||
})
|
})
|
||||||
setInputs(newInputs)
|
setInputs(newInputs)
|
||||||
return mockUrl
|
|
||||||
}
|
}
|
||||||
}, [appId, id, inputs, setInputs])
|
}, [appId, id, inputs, setInputs])
|
||||||
|
|
||||||
|
|||||||
@ -168,3 +168,12 @@ export type TracingConfig = {
|
|||||||
tracing_provider: TracingProvider
|
tracing_provider: TracingProvider
|
||||||
tracing_config: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig
|
tracing_config: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type WebhookTriggerResponse = {
|
||||||
|
id: string
|
||||||
|
webhook_id: string
|
||||||
|
webhook_url: string
|
||||||
|
webhook_debug_url: string
|
||||||
|
node_id: string
|
||||||
|
created_at: string
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { Fetcher } from 'swr'
|
import type { Fetcher } from 'swr'
|
||||||
import { del, get, patch, post, put } from './base'
|
import { del, get, patch, post, put } from './base'
|
||||||
import type { ApiKeysListResponse, AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDailyMessagesResponse, AppDetailResponse, AppListResponse, AppStatisticsResponse, AppTemplatesResponse, AppTokenCostsResponse, AppVoicesListResponse, CreateApiKeyResponse, DSLImportMode, DSLImportResponse, GenerationIntroductionResponse, TracingConfig, TracingStatus, UpdateAppModelConfigResponse, UpdateAppSiteCodeResponse, UpdateOpenAIKeyResponse, ValidateOpenAIKeyResponse, WorkflowDailyConversationsResponse } from '@/models/app'
|
import type { ApiKeysListResponse, AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDailyMessagesResponse, AppDetailResponse, AppListResponse, AppStatisticsResponse, AppTemplatesResponse, AppTokenCostsResponse, AppVoicesListResponse, CreateApiKeyResponse, DSLImportMode, DSLImportResponse, GenerationIntroductionResponse, TracingConfig, TracingStatus, UpdateAppModelConfigResponse, UpdateAppSiteCodeResponse, UpdateOpenAIKeyResponse, ValidateOpenAIKeyResponse, WebhookTriggerResponse, WorkflowDailyConversationsResponse } from '@/models/app'
|
||||||
import type { CommonResponse } from '@/models/common'
|
import type { CommonResponse } from '@/models/common'
|
||||||
import type { AppIconType, AppMode, ModelConfig } from '@/types/app'
|
import type { AppIconType, AppMode, ModelConfig } from '@/types/app'
|
||||||
import type { TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type'
|
import type { TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type'
|
||||||
@ -158,8 +158,12 @@ export const updateTracingStatus: Fetcher<CommonResponse, { appId: string; body:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Webhook Trigger
|
// Webhook Trigger
|
||||||
export const fetchWebhookUrl: Fetcher<{ serverUrl: string }, { appId: string; nodeId: string }> = ({ appId, nodeId }) => {
|
export const fetchWebhookUrl: Fetcher<WebhookTriggerResponse, { appId: string; nodeId: string }> = ({ appId, nodeId }) => {
|
||||||
return get<{ serverUrl: string }>(`apps/${appId}/webhook-url`, { params: { node: nodeId } })
|
return post<WebhookTriggerResponse>(`apps/${appId}/workflows/triggers/webhook`, { params: { node_id: nodeId } })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deleteWebhookUrl: Fetcher<CommonResponse, { appId: string; nodeId: string }> = ({ appId, nodeId }) => {
|
||||||
|
return del<CommonResponse>(`apps/${appId}/workflows/triggers/webhook`, { params: { node_id: nodeId } })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchTracingConfig: Fetcher<TracingConfig & { has_not_configured: true }, { appId: string; provider: TracingProvider }> = ({ appId, provider }) => {
|
export const fetchTracingConfig: Fetcher<TracingConfig & { has_not_configured: true }, { appId: string; provider: TracingProvider }> = ({ appId, provider }) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user