diff --git a/web/app/components/workflow-app/components/workflow-children.tsx b/web/app/components/workflow-app/components/workflow-children.tsx index c7dcfb09f0..6321706347 100644 --- a/web/app/components/workflow-app/components/workflow-children.tsx +++ b/web/app/components/workflow-app/components/workflow-children.tsx @@ -11,6 +11,7 @@ import { useStore } from '@/app/components/workflow/store' import { useStoreApi } from 'reactflow' import PluginDependency from '../../workflow/plugin-dependency' import { + useAutoGenerateWebhookUrl, useDSL, usePanelInteractions, } from '@/app/components/workflow/hooks' @@ -91,6 +92,8 @@ const WorkflowChildren = () => { setSecretEnvList(v.payload.data as EnvironmentVariable[]) }) + const autoGenerateWebhookUrl = useAutoGenerateWebhookUrl() + const handleCloseOnboarding = useCallback(() => { handleOnboardingClose() }, [handleOnboardingClose]) @@ -142,6 +145,7 @@ const WorkflowChildren = () => { handleSyncWorkflowDraft(true, false, { onSuccess: () => { + autoGenerateWebhookUrl(newNode.id) console.log('Node successfully saved to draft') }, onError: () => { diff --git a/web/app/components/workflow/candidate-node.tsx b/web/app/components/workflow/candidate-node.tsx index 6eb96fbc09..4b38000810 100644 --- a/web/app/components/workflow/candidate-node.tsx +++ b/web/app/components/workflow/candidate-node.tsx @@ -1,7 +1,4 @@ -import { - memo, - useCallback, -} from 'react' +import { memo } from 'react' import produce from 'immer' import { useReactFlow, @@ -13,15 +10,13 @@ import { useStore, useWorkflowStore, } from './store' -import { WorkflowHistoryEvent, useNodesInteractions, useNodesSyncDraft, useWorkflowHistory } from './hooks' +import { WorkflowHistoryEvent, useAutoGenerateWebhookUrl, useNodesInteractions, useNodesSyncDraft, useWorkflowHistory } from './hooks' import { CUSTOM_NODE } from './constants' import { getIterationStartNode, getLoopStartNode } from './utils' import CustomNode from './nodes' import CustomNoteNode from './note-node' import { CUSTOM_NOTE_NODE } from './note-node/constants' import { BlockEnum } from './types' -import { useStore as useAppStore } from '@/app/components/app/store' -import { fetchWebhookUrl } from '@/service/apps' const CandidateNode = () => { const store = useStoreApi() @@ -33,34 +28,7 @@ const CandidateNode = () => { const { handleNodeSelect } = useNodesInteractions() const { saveStateToHistory } = useWorkflowHistory() const { handleSyncWorkflowDraft } = useNodesSyncDraft() - - const autoGenerateWebhookUrl = useCallback((nodeId: string) => { - const appId = useAppStore.getState().appDetail?.id - if (!appId) - return - - fetchWebhookUrl({ appId, nodeId }).then((response) => { - const { getNodes, setNodes } = store.getState() - let hasUpdated = false - const updatedNodes = produce(getNodes(), (draft) => { - const targetNode = draft.find(n => n.id === nodeId) - if (!targetNode || targetNode.data.type !== BlockEnum.TriggerWebhook) - return - - targetNode.data = { - ...targetNode.data, - webhook_url: response.webhook_url, - webhook_debug_url: response.webhook_debug_url, - } - hasUpdated = true - }) - if (hasUpdated) - setNodes(updatedNodes) - }) - .catch((error: unknown) => { - console.error('Failed to auto-generate webhook URL from candidate placement:', error) - }) - }, [store]) + const autoGenerateWebhookUrl = useAutoGenerateWebhookUrl() useEventListener('click', (e) => { const { candidateNode, mousePosition } = workflowStore.getState() diff --git a/web/app/components/workflow/hooks/index.ts b/web/app/components/workflow/hooks/index.ts index 1dbba6b0e2..933b328227 100644 --- a/web/app/components/workflow/hooks/index.ts +++ b/web/app/components/workflow/hooks/index.ts @@ -22,3 +22,4 @@ export * from './use-DSL' export * from './use-inspect-vars-crud' export * from './use-set-workflow-vars-with-value' export * from './use-workflow-search' +export * from './use-auto-generate-webhook-url' diff --git a/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts b/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts new file mode 100644 index 0000000000..65fbfaafc3 --- /dev/null +++ b/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts @@ -0,0 +1,48 @@ +import { useCallback } from 'react' +import produce from 'immer' +import { useStoreApi } from 'reactflow' +import { useStore as useAppStore } from '@/app/components/app/store' +import { BlockEnum } from '@/app/components/workflow/types' +import { fetchWebhookUrl } from '@/service/apps' + +export const useAutoGenerateWebhookUrl = () => { + const reactFlowStore = useStoreApi() + + return useCallback(async (nodeId: string) => { + const appId = useAppStore.getState().appDetail?.id + if (!appId) + return + + const { getNodes } = reactFlowStore.getState() + const node = getNodes().find(n => n.id === nodeId) + if (!node || node.data.type !== BlockEnum.TriggerWebhook) + return + + if (node.data.webhook_url && node.data.webhook_url.length > 0) + return + + try { + const response = await fetchWebhookUrl({ appId, nodeId }) + const { getNodes: getLatestNodes, setNodes } = reactFlowStore.getState() + let hasUpdated = false + const updatedNodes = produce(getLatestNodes(), (draft) => { + const targetNode = draft.find(n => n.id === nodeId) + if (!targetNode || targetNode.data.type !== BlockEnum.TriggerWebhook) + return + + targetNode.data = { + ...targetNode.data, + webhook_url: response.webhook_url, + webhook_debug_url: response.webhook_debug_url, + } + hasUpdated = true + }) + + if (hasUpdated) + setNodes(updatedNodes) + } + catch (error: unknown) { + console.error('Failed to auto-generate webhook URL:', error) + } + }, [reactFlowStore]) +}