add _webhook_raw to downstreamed node

This commit is contained in:
hjlarry 2025-10-16 16:35:05 +08:00
parent 559cf6583f
commit 1089c5bf04
5 changed files with 55 additions and 2 deletions

View File

@ -38,11 +38,18 @@ describe('Webhook Trigger Node Default', () => {
expect(Array.isArray(defaultValue.headers)).toBe(true)
expect(Array.isArray(defaultValue.params)).toBe(true)
expect(Array.isArray(defaultValue.body)).toBe(true)
expect(Array.isArray(defaultValue.variables)).toBe(true)
// Initial arrays should be empty
expect(defaultValue.headers).toHaveLength(0)
expect(defaultValue.params).toHaveLength(0)
expect(defaultValue.body).toHaveLength(0)
expect(defaultValue.variables).toHaveLength(1)
const rawVariable = defaultValue.variables?.[0]
expect(rawVariable?.variable).toBe('_webhook_raw')
expect(rawVariable?.label).toBe('raw')
expect(rawVariable?.value_type).toBe('object')
})
it('should have correct metadata for trigger node', () => {

View File

@ -3,6 +3,7 @@ import type { NodeDefault } from '../../types'
import { genNodeMetaData } from '../../utils'
import type { WebhookTriggerNodeType } from './types'
import { isValidParameterType } from './utils/parameter-type-utils'
import { createWebhookRawVariable } from './utils/raw-variable'
const metaData = genNodeMetaData({
sort: 3,
@ -22,6 +23,7 @@ const nodeDefault: NodeDefault<WebhookTriggerNodeType> = {
async_mode: true,
status_code: 200,
response_body: '',
variables: [createWebhookRawVariable()],
},
checkValid(payload: WebhookTriggerNodeType, t: any) {
// Require webhook_url to be configured

View File

@ -1,4 +1,4 @@
import { useCallback } from 'react'
import { useCallback, useEffect } from 'react'
import produce from 'immer'
import { useTranslation } from 'react-i18next'
import type { HttpMethod, WebhookHeader, WebhookParameter, WebhookTriggerNodeType } from './types'
@ -11,6 +11,7 @@ import type { Variable } from '@/app/components/workflow/types'
import { VarType } from '@/app/components/workflow/types'
import Toast from '@/app/components/base/toast'
import { hasDuplicateStr } from '@/utils/var'
import { WEBHOOK_RAW_VARIABLE_NAME, ensureWebhookRawVariable } from './utils/raw-variable'
const useConfig = (id: string, payload: WebhookTriggerNodeType) => {
const { t } = useTranslation()
@ -18,15 +19,29 @@ const useConfig = (id: string, payload: WebhookTriggerNodeType) => {
const { inputs, setInputs } = useNodeCrud<WebhookTriggerNodeType>(id, payload)
const appId = useAppStore.getState().appDetail?.id
const { isVarUsedInNodes, removeUsedVarInNodes } = useWorkflow()
const hasWebhookRawVariable = inputs.variables?.some(variable => variable.variable === WEBHOOK_RAW_VARIABLE_NAME) ?? false
useEffect(() => {
if (readOnly)
return
if (!hasWebhookRawVariable) {
setInputs(produce(inputs, (draft) => {
ensureWebhookRawVariable(draft)
}))
}
}, [readOnly, hasWebhookRawVariable, inputs, setInputs])
const handleMethodChange = useCallback((method: HttpMethod) => {
setInputs(produce(inputs, (draft) => {
ensureWebhookRawVariable(draft)
draft.method = method
}))
}, [inputs, setInputs])
const handleContentTypeChange = useCallback((contentType: string) => {
setInputs(produce(inputs, (draft) => {
ensureWebhookRawVariable(draft)
const previousContentType = draft.content_type
draft.content_type = contentType
@ -107,6 +122,7 @@ const useConfig = (id: string, payload: WebhookTriggerNodeType) => {
draft.variables.push(newVar)
})
ensureWebhookRawVariable(draft)
return true
}, [t, id, isVarUsedInNodes, removeUsedVarInNodes])
@ -171,6 +187,7 @@ const useConfig = (id: string, payload: WebhookTriggerNodeType) => {
const response = await fetchWebhookUrl({ appId, nodeId: id })
const newInputs = produce(inputs, (draft) => {
ensureWebhookRawVariable(draft)
draft.webhook_url = response.webhook_url
draft.webhook_debug_url = response.webhook_debug_url
})
@ -181,6 +198,7 @@ const useConfig = (id: string, payload: WebhookTriggerNodeType) => {
// Keep the UI unblocked and allow users to proceed in local/dev environments.
console.error('Failed to generate webhook URL:', error)
const newInputs = produce(inputs, (draft) => {
ensureWebhookRawVariable(draft)
draft.webhook_url = ''
})
setInputs(newInputs)

View File

@ -0,0 +1,25 @@
import { VarType, type Variable } from '@/app/components/workflow/types'
export const WEBHOOK_RAW_VARIABLE_NAME = '_webhook_raw'
export const WEBHOOK_RAW_VARIABLE_LABEL = 'raw'
export const createWebhookRawVariable = (): Variable => ({
variable: WEBHOOK_RAW_VARIABLE_NAME,
label: WEBHOOK_RAW_VARIABLE_LABEL,
value_type: VarType.object,
value_selector: [],
required: true,
})
type WithVariables = {
variables?: Variable[]
}
export const ensureWebhookRawVariable = <T extends WithVariables>(payload: T): void => {
if (!payload.variables)
payload.variables = []
const hasRawVariable = payload.variables.some(variable => variable.variable === WEBHOOK_RAW_VARIABLE_NAME)
if (!hasRawVariable)
payload.variables.push(createWebhookRawVariable())
}

View File

@ -7,10 +7,11 @@ type OutputVariablesContentProps = {
}
// Define the display order for variable labels to match the table order in the UI
const LABEL_ORDER = { param: 1, header: 2, body: 3 } as const
const LABEL_ORDER = { raw: 0, param: 1, header: 2, body: 3 } as const
const getLabelPrefix = (label: string): string => {
const prefixMap: Record<string, string> = {
raw: 'payload',
param: 'query_params',
header: 'header_params',
body: 'req_body_params',