diff --git a/api/core/workflow/nodes/trigger_webhook/entities.py b/api/core/workflow/nodes/trigger_webhook/entities.py index d615fbf938..27e8f69664 100644 --- a/api/core/workflow/nodes/trigger_webhook/entities.py +++ b/api/core/workflow/nodes/trigger_webhook/entities.py @@ -48,7 +48,7 @@ class WebhookData(BaseNodeData): SYNC = "async" # only support method: Method = Method.GET - content_type: ContentType = Field(alias="content-type", default=ContentType.JSON) + content_type: ContentType = Field(default=ContentType.JSON) headers: Sequence[WebhookParameter] = Field(default_factory=list) params: Sequence[WebhookParameter] = Field(default_factory=list) # query parameters body: Sequence[WebhookBodyParameter] = Field(default_factory=list) diff --git a/api/core/workflow/nodes/trigger_webhook/node.py b/api/core/workflow/nodes/trigger_webhook/node.py index e5f6f149c0..a18fb20c70 100644 --- a/api/core/workflow/nodes/trigger_webhook/node.py +++ b/api/core/workflow/nodes/trigger_webhook/node.py @@ -42,7 +42,7 @@ class TriggerWebhookNode(BaseNode): "type": "webhook", "config": { "method": "get", - "content-type": "application/json", + "content_type": "application/json", "headers": [], "params": [], "body": [], diff --git a/api/tests/test_containers_integration_tests/services/test_webhook_service.py b/api/tests/test_containers_integration_tests/services/test_webhook_service.py index f671a1e29d..fb7d7b5e16 100644 --- a/api/tests/test_containers_integration_tests/services/test_webhook_service.py +++ b/api/tests/test_containers_integration_tests/services/test_webhook_service.py @@ -89,7 +89,7 @@ class TestWebhookService: "data": { "title": "Test Webhook", "method": "post", - "content-type": "application/json", + "content_type": "application/json", "headers": [ {"name": "Authorization", "required": True}, {"name": "Content-Type", "required": False}, diff --git a/web/app/components/workflow/constants.ts b/web/app/components/workflow/constants.ts index d4998b2c70..baf2870a61 100644 --- a/web/app/components/workflow/constants.ts +++ b/web/app/components/workflow/constants.ts @@ -508,7 +508,7 @@ export const RETRIEVAL_OUTPUT_STRUCT = `{ }` export const SUPPORT_OUTPUT_VARS_NODE = [ - BlockEnum.Start, BlockEnum.LLM, BlockEnum.KnowledgeRetrieval, BlockEnum.Code, BlockEnum.TemplateTransform, + BlockEnum.Start, BlockEnum.TriggerWebhook, BlockEnum.LLM, BlockEnum.KnowledgeRetrieval, BlockEnum.Code, BlockEnum.TemplateTransform, BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier, BlockEnum.ParameterExtractor, BlockEnum.Iteration, BlockEnum.Loop, BlockEnum.DocExtractor, BlockEnum.ListFilter, diff --git a/web/app/components/workflow/nodes/_base/components/variable/utils.ts b/web/app/components/workflow/nodes/_base/components/variable/utils.ts index d96c9be6cf..8aa226282b 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/utils.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/utils.ts @@ -22,6 +22,7 @@ import type { StartNodeType } from '@/app/components/workflow/nodes/start/types' import type { ConversationVariable, EnvironmentVariable, Node, NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' import type { VariableAssignerNodeType } from '@/app/components/workflow/nodes/variable-assigner/types' import type { Field as StructField } from '@/app/components/workflow/nodes/llm/types' +import type { WebhookTriggerNodeType } from '@/app/components/workflow/nodes/trigger-webhook/types' import { AGENT_OUTPUT_STRUCT, @@ -290,6 +291,36 @@ const formatItem = ( break } + case BlockEnum.TriggerWebhook: { + const { + variables = [], + } = data as WebhookTriggerNodeType + res.vars = variables.map((v) => { + const type = inputVarTypeToVarType(v.type) + const varRes: Var = { + variable: v.variable, + type, + isParagraph: v.type === InputVarType.paragraph, + isSelect: v.type === InputVarType.select, + options: v.options, + required: v.required, + } + try { + if(type === VarType.object && v.json_schema) { + varRes.children = { + schema: JSON.parse(v.json_schema), + } + } + } + catch (error) { + console.error('Error formatting TriggerWebhook variable:', error) + } + return varRes + }) + + break + } + case BlockEnum.LLM: { res.vars = [...LLM_OUTPUT_STRUCT] if (data.structured_output_enabled && data.structured_output?.schema?.properties && Object.keys(data.structured_output.schema.properties).length > 0) { diff --git a/web/app/components/workflow/nodes/trigger-plugin/default.ts b/web/app/components/workflow/nodes/trigger-plugin/default.ts index 3c7103e499..e63563df3d 100644 --- a/web/app/components/workflow/nodes/trigger-plugin/default.ts +++ b/web/app/components/workflow/nodes/trigger-plugin/default.ts @@ -1,7 +1,7 @@ import { BlockEnum } from '../../types' import type { NodeDefault } from '../../types' import type { PluginTriggerNodeType } from './types' -import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks' +import { ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks' const nodeDefault: NodeDefault = { defaultValue: { @@ -15,8 +15,8 @@ const nodeDefault: NodeDefault = { }, getAvailableNextNodes(isChatMode: boolean) { const nodes = isChatMode - ? ALL_CHAT_AVAILABLE_BLOCKS - : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End) + ? [] + : ALL_COMPLETION_AVAILABLE_BLOCKS return nodes.filter(type => type !== BlockEnum.Start) }, checkValid(payload: PluginTriggerNodeType, t: any) { diff --git a/web/app/components/workflow/nodes/trigger-schedule/__tests__/default.test.ts b/web/app/components/workflow/nodes/trigger-schedule/__tests__/default.test.ts index 45ccdb1de0..efafc256d5 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/__tests__/default.test.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/__tests__/default.test.ts @@ -32,7 +32,6 @@ describe('Schedule Trigger Node Default', () => { it('should have correct default value', () => { expect(nodeDefault.defaultValue.mode).toBe('visual') expect(nodeDefault.defaultValue.frequency).toBe('weekly') - expect(nodeDefault.defaultValue.enabled).toBe(true) }) it('should have empty prev nodes', () => { diff --git a/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-edge-cases.test.ts b/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-edge-cases.test.ts index 0f7f3afe0c..d3ebfcb65f 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-edge-cases.test.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-edge-cases.test.ts @@ -9,7 +9,6 @@ const createMonthlyConfig = (monthly_days: (number | 'last')[], time = '10:30 AM monthly_days, }, timezone, - enabled: true, }) describe('Monthly Edge Cases', () => { diff --git a/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-multiselect.test.ts b/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-multiselect.test.ts index ed998c7749..f9d609d372 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-multiselect.test.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-multiselect.test.ts @@ -9,7 +9,6 @@ const createMonthlyConfig = (monthlyDays: (number | 'last')[], time = '10:30 AM' monthly_days: monthlyDays, }, timezone: 'UTC', - enabled: true, id: 'test', type: 'trigger-schedule', data: {}, @@ -117,8 +116,7 @@ describe('Monthly Multi-Select Execution Time Calculator', () => { time: '10:30 AM', }, timezone: 'UTC', - enabled: true, - id: 'test', + id: 'test', type: 'trigger-schedule', data: {}, position: { x: 0, y: 0 }, diff --git a/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-validation.test.ts b/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-validation.test.ts index ca708aadab..c23622efad 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-validation.test.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/__tests__/monthly-validation.test.ts @@ -22,7 +22,6 @@ describe('Monthly Validation', () => { monthly_days: [15], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -39,7 +38,6 @@ describe('Monthly Validation', () => { monthly_days: ['last' as const], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -58,7 +56,6 @@ describe('Monthly Validation', () => { monthly_days: [1, 15, 30], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -75,7 +72,6 @@ describe('Monthly Validation', () => { monthly_days: [1, 15, 'last' as const], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -92,7 +88,6 @@ describe('Monthly Validation', () => { monthly_days: [], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -109,7 +104,6 @@ describe('Monthly Validation', () => { monthly_days: [1, 35, 15], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -127,7 +121,6 @@ describe('Monthly Validation', () => { time: '10:30 AM', }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -144,7 +137,6 @@ describe('Monthly Validation', () => { monthly_days: [1, 15], }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) @@ -161,7 +153,6 @@ describe('Monthly Validation', () => { monthly_days: Array.from({ length: 31 }, (_, i) => i + 1), }, timezone: 'UTC', - enabled: true, } const result = nodeDefault.checkValid(config, mockT) diff --git a/web/app/components/workflow/nodes/trigger-schedule/__tests__/weekly-time-logic.test.ts b/web/app/components/workflow/nodes/trigger-schedule/__tests__/weekly-time-logic.test.ts index 2a89858e7d..30dc11d602 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/__tests__/weekly-time-logic.test.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/__tests__/weekly-time-logic.test.ts @@ -15,7 +15,6 @@ const createWeeklyConfig = ( weekdays, }, timezone, - enabled: true, }) describe('Weekly Schedule Time Logic Tests', () => { @@ -364,8 +363,7 @@ describe('Weekly Schedule Time Logic Tests', () => { time: '2:00 PM', }, timezone: 'UTC', - enabled: true, - } + } const weeklyTimes = getNextExecutionTimes(weeklyConfig, 1) const dailyTimes = getNextExecutionTimes(dailyConfig, 1) @@ -389,8 +387,7 @@ describe('Weekly Schedule Time Logic Tests', () => { time: '2:00 PM', }, timezone: 'UTC', - enabled: true, - } + } const weeklyTimes = getNextExecutionTimes(weeklyConfig, 1) const dailyTimes = getNextExecutionTimes(dailyConfig, 1) diff --git a/web/app/components/workflow/nodes/trigger-schedule/constants.ts b/web/app/components/workflow/nodes/trigger-schedule/constants.ts index b3d5fdb244..22507e2142 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/constants.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/constants.ts @@ -4,7 +4,6 @@ import type { ScheduleTriggerNodeType } from './types' export const getDefaultScheduleConfig = (): Partial => ({ mode: 'visual', frequency: 'weekly', - enabled: true, visual_config: { time: '11:30 AM', weekdays: ['sun'], diff --git a/web/app/components/workflow/nodes/trigger-schedule/default.ts b/web/app/components/workflow/nodes/trigger-schedule/default.ts index 5de75df799..4c5991aa80 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/default.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/default.ts @@ -1,7 +1,7 @@ import { BlockEnum } from '../../types' import type { NodeDefault } from '../../types' import type { ScheduleTriggerNodeType } from './types' -import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks' +import { ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks' import { isValidCronExpression } from './utils/cron-parser' import { getNextExecutionTimes } from './utils/execution-time-calculator' import { getDefaultScheduleConfig } from './constants' @@ -114,8 +114,8 @@ const nodeDefault: NodeDefault = { }, getAvailableNextNodes(isChatMode: boolean) { const nodes = isChatMode - ? ALL_CHAT_AVAILABLE_BLOCKS - : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End) + ? [] + : ALL_COMPLETION_AVAILABLE_BLOCKS return nodes.filter(type => type !== BlockEnum.Start) }, checkValid(payload: ScheduleTriggerNodeType, t: any) { diff --git a/web/app/components/workflow/nodes/trigger-schedule/types.ts b/web/app/components/workflow/nodes/trigger-schedule/types.ts index 403208a118..c32089b59b 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/types.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/types.ts @@ -17,5 +17,4 @@ export type ScheduleTriggerNodeType = CommonNodeType & { cron_expression?: string // Cron expression when mode is 'cron' visual_config?: VisualConfig // User-friendly configuration when mode is 'visual' timezone: string // User profile timezone (e.g., 'Asia/Shanghai', 'America/New_York') - enabled: boolean // Whether the trigger is active } diff --git a/web/app/components/workflow/nodes/trigger-schedule/use-config.ts b/web/app/components/workflow/nodes/trigger-schedule/use-config.ts index efc72371c5..acf39201d8 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/use-config.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/use-config.ts @@ -16,7 +16,6 @@ const useConfig = (id: string, payload: ScheduleTriggerNodeType) => { mode: payload.mode || 'visual', frequency: payload.frequency || 'weekly', timezone: userProfile.timezone || 'UTC', - enabled: payload.enabled !== undefined ? payload.enabled : true, visual_config: { ...getDefaultVisualConfig(), ...payload.visual_config, diff --git a/web/app/components/workflow/nodes/trigger-schedule/utils/execution-time-calculator.spec.ts b/web/app/components/workflow/nodes/trigger-schedule/utils/execution-time-calculator.spec.ts index d39deaace3..2defa1486a 100644 --- a/web/app/components/workflow/nodes/trigger-schedule/utils/execution-time-calculator.spec.ts +++ b/web/app/components/workflow/nodes/trigger-schedule/utils/execution-time-calculator.spec.ts @@ -14,7 +14,6 @@ const createMockData = (overrides: Partial = {}): Sched time: '2:30 PM', }, timezone: 'UTC', - enabled: true, ...overrides, }) diff --git a/web/app/components/workflow/nodes/trigger-webhook/__tests__/default.test.ts b/web/app/components/workflow/nodes/trigger-webhook/__tests__/default.test.ts index 11a81c4a94..a16227f766 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/__tests__/default.test.ts +++ b/web/app/components/workflow/nodes/trigger-webhook/__tests__/default.test.ts @@ -21,7 +21,7 @@ describe('Webhook Trigger Node Default', () => { // Core webhook configuration expect(defaultValue.webhook_url).toBe('') expect(defaultValue.method).toBe('POST') - expect(defaultValue['content-type']).toBe('application/json') + expect(defaultValue.content_type).toBe('application/json') // Response configuration fields expect(defaultValue.async_mode).toBe(true) diff --git a/web/app/components/workflow/nodes/trigger-webhook/default.ts b/web/app/components/workflow/nodes/trigger-webhook/default.ts index bf1eb65a80..17a1d945eb 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/default.ts +++ b/web/app/components/workflow/nodes/trigger-webhook/default.ts @@ -1,29 +1,29 @@ import { BlockEnum } from '../../types' import type { NodeDefault } from '../../types' import type { WebhookTriggerNodeType } from './types' -import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks' +import { ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks' import type { DefaultValueForm } from '@/app/components/workflow/nodes/_base/components/error-handle/types' const nodeDefault: NodeDefault = { defaultValue: { - 'webhook_url': '', - 'method': 'POST', - 'content-type': 'application/json', - 'headers': [], - 'params': [], - 'body': [], - 'async_mode': true, - 'status_code': 200, - 'response_body': '', - 'default_value': [] as DefaultValueForm[], + webhook_url: '', + method: 'POST', + content_type: 'application/json', + headers: [], + params: [], + body: [], + async_mode: true, + status_code: 200, + response_body: '', + default_value: [] as DefaultValueForm[], }, getAvailablePrevNodes(_isChatMode: boolean) { return [] }, getAvailableNextNodes(isChatMode: boolean) { const nodes = isChatMode - ? ALL_CHAT_AVAILABLE_BLOCKS - : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End) + ? [] + : ALL_COMPLETION_AVAILABLE_BLOCKS return nodes.filter(type => type !== BlockEnum.Start) }, checkValid(_payload: WebhookTriggerNodeType, _t: any) { diff --git a/web/app/components/workflow/nodes/trigger-webhook/panel.tsx b/web/app/components/workflow/nodes/trigger-webhook/panel.tsx index 1dc979b7a9..aeea0eec72 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/panel.tsx +++ b/web/app/components/workflow/nodes/trigger-webhook/panel.tsx @@ -135,7 +135,7 @@ const Panel: FC> = ({
handleContentTypeChange(item.value as string)} disabled={readOnly} className="h-8 text-sm" diff --git a/web/app/components/workflow/nodes/trigger-webhook/types.ts b/web/app/components/workflow/nodes/trigger-webhook/types.ts index 9e06da4f1a..a236dc20de 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/types.ts +++ b/web/app/components/workflow/nodes/trigger-webhook/types.ts @@ -1,4 +1,4 @@ -import type { CommonNodeType } from '@/app/components/workflow/types' +import type { CommonNodeType, InputVar } from '@/app/components/workflow/types' import type { DefaultValueForm } from '@/app/components/workflow/nodes/_base/components/error-handle/types' import type { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types' @@ -18,17 +18,18 @@ export type WebhookHeader = { } export type WebhookTriggerNodeType = CommonNodeType & { - 'webhook_url'?: string - 'webhook_debug_url'?: string - 'method': HttpMethod - 'content-type': string - 'headers': WebhookHeader[] - 'params': WebhookParameter[] - 'body': WebhookParameter[] - 'async_mode': boolean - 'status_code': number - 'response_body': string - 'http_methods'?: HttpMethod[] - 'error_strategy'?: ErrorHandleTypeEnum - 'default_value'?: DefaultValueForm[] + webhook_url?: string + webhook_debug_url?: string + method: HttpMethod + content_type: string + headers: WebhookHeader[] + params: WebhookParameter[] + body: WebhookParameter[] + async_mode: boolean + status_code: number + response_body: string + http_methods?: HttpMethod[] + error_strategy?: ErrorHandleTypeEnum + default_value?: DefaultValueForm[] + variables: InputVar[] } diff --git a/web/app/components/workflow/nodes/trigger-webhook/use-config.ts b/web/app/components/workflow/nodes/trigger-webhook/use-config.ts index f14b7acde8..82f44f7ea7 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/use-config.ts +++ b/web/app/components/workflow/nodes/trigger-webhook/use-config.ts @@ -1,5 +1,6 @@ import { useCallback } from 'react' import produce from 'immer' +import { useTranslation } from 'react-i18next' import type { HttpMethod, WebhookHeader, WebhookParameter, WebhookTriggerNodeType } from './types' import { useNodesReadOnly } from '@/app/components/workflow/hooks' import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' @@ -7,8 +8,13 @@ import { useStore as useAppStore } from '@/app/components/app/store' import type { DefaultValueForm } from '@/app/components/workflow/nodes/_base/components/error-handle/types' import type { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types' import { fetchWebhookUrl } from '@/service/apps' +import type { InputVar } from '@/app/components/workflow/types' +import { InputVarType } from '@/app/components/workflow/types' +import Toast from '@/app/components/base/toast' +import { hasDuplicateStr } from '@/utils/var' const useConfig = (id: string, payload: WebhookTriggerNodeType) => { + const { t } = useTranslation() const { nodesReadOnly: readOnly } = useNodesReadOnly() const { inputs, setInputs } = useNodeCrud(id, payload) const appId = useAppStore.getState().appDetail?.id @@ -21,27 +27,84 @@ const useConfig = (id: string, payload: WebhookTriggerNodeType) => { const handleContentTypeChange = useCallback((contentType: string) => { setInputs(produce(inputs, (draft) => { - draft['content-type'] = contentType + draft.content_type = contentType })) }, [inputs, setInputs]) - const handleHeadersChange = useCallback((headers: WebhookHeader[]) => { - setInputs(produce(inputs, (draft) => { - draft.headers = headers - })) - }, [inputs, setInputs]) + // Helper function to convert ParameterType to InputVarType + const toInputVarType = useCallback((type: string): InputVarType => { + const typeMap: Record = { + string: InputVarType.textInput, + number: InputVarType.number, + boolean: InputVarType.checkbox, + array: InputVarType.textInput, // Arrays as text for now + object: InputVarType.jsonObject, + } + return typeMap[type] || InputVarType.textInput + }, []) + + const syncVariablesInDraft = useCallback(( + draft: WebhookTriggerNodeType, + newData: (WebhookParameter | WebhookHeader)[], + ) => { + if (!draft.variables) + draft.variables = [] + + if(hasDuplicateStr(newData.map(item => item.name))) { + Toast.notify({ + type: 'error', + message: t('appDebug.varKeyError.keyAlreadyExists', { + key: t('appDebug.variableConfig.varName'), + }), + }) + return false + } + + // Add or update variables + newData.forEach((item) => { + const varName = item.name + const existingVarIndex = draft.variables.findIndex(v => v.variable === varName) + + const inputVarType = 'type' in item + ? toInputVarType(item.type) + : InputVarType.textInput // Headers default to text + + const newVar: InputVar = { + type: inputVarType, + label: varName, + variable: varName, + required: item.required, + } + + if (existingVarIndex >= 0) + draft.variables[existingVarIndex] = newVar + else + draft.variables.push(newVar) + }) + + return true + }, [toInputVarType, t]) const handleParamsChange = useCallback((params: WebhookParameter[]) => { setInputs(produce(inputs, (draft) => { draft.params = params + syncVariablesInDraft(draft, params) })) - }, [inputs, setInputs]) + }, [inputs, setInputs, syncVariablesInDraft]) + + const handleHeadersChange = useCallback((headers: WebhookHeader[]) => { + setInputs(produce(inputs, (draft) => { + draft.headers = headers + syncVariablesInDraft(draft, headers) + })) + }, [inputs, setInputs, syncVariablesInDraft]) const handleBodyChange = useCallback((body: WebhookParameter[]) => { setInputs(produce(inputs, (draft) => { draft.body = body + syncVariablesInDraft(draft, body) })) - }, [inputs, setInputs]) + }, [inputs, setInputs, syncVariablesInDraft]) const handleAsyncModeChange = useCallback((asyncMode: boolean) => { setInputs(produce(inputs, (draft) => {