From 74f371cc7926ed3a67ec8611df449474481e0deb Mon Sep 17 00:00:00 2001 From: Waleed Date: Tue, 6 Jan 2026 15:01:55 -0800 Subject: [PATCH 1/3] fix(build): fix type assertion (#2696) * fix(build): fix type assertion * ack PR comment * more --- apps/sim/tools/http/request.ts | 8 ++++---- apps/sim/tools/http/webhook_request.ts | 2 +- apps/sim/tools/types.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/sim/tools/http/request.ts b/apps/sim/tools/http/request.ts index dfb26dd24d..db47883f50 100644 --- a/apps/sim/tools/http/request.ts +++ b/apps/sim/tools/http/request.ts @@ -70,7 +70,7 @@ export const requestTool: ToolConfig = { return allHeaders }, - body: (params: RequestParams) => { + body: ((params: RequestParams) => { if (params.formData) { const formData = new FormData() Object.entries(params.formData).forEach(([key, value]) => { @@ -90,7 +90,7 @@ export const requestTool: ToolConfig = { ) { // Convert JSON object to URL-encoded string const urlencoded = new URLSearchParams() - Object.entries(params.body).forEach(([key, value]) => { + Object.entries(params.body as Record).forEach(([key, value]) => { if (value !== undefined && value !== null) { urlencoded.append(key, String(value)) } @@ -98,11 +98,11 @@ export const requestTool: ToolConfig = { return urlencoded.toString() } - return params.body + return params.body as Record } return undefined - }, + }) as (params: RequestParams) => Record | string | FormData | undefined, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/http/webhook_request.ts b/apps/sim/tools/http/webhook_request.ts index b873a939b7..f04da4c1f8 100644 --- a/apps/sim/tools/http/webhook_request.ts +++ b/apps/sim/tools/http/webhook_request.ts @@ -68,7 +68,7 @@ export const webhookRequestTool: ToolConfig params.body, + body: (params: WebhookRequestParams) => params.body as Record, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/types.ts b/apps/sim/tools/types.ts index 324f254e09..36f7cf366a 100644 --- a/apps/sim/tools/types.ts +++ b/apps/sim/tools/types.ts @@ -93,7 +93,7 @@ export interface ToolConfig

{ url: string | ((params: P) => string) method: HttpMethod | ((params: P) => HttpMethod) headers: (params: P) => Record - body?: (params: P) => Record | string + body?: (params: P) => Record | string | FormData | undefined } // Post-processing (optional) - allows additional processing after the initial request From f502f984f3691ee94c5c3e303ce61b039507088f Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:44:25 -0800 Subject: [PATCH 2/3] improvement(router): add ports to router block (#2683) * Add ports to router block * Add tag dropdowns * Fix lint * fix tests + add context into block preview --------- Co-authored-by: Vikhyath Mondreti --- .../condition-input/condition-input.tsx | 230 +++++++++++--- .../editor/components/sub-block/sub-block.tsx | 12 + .../workflow-block/workflow-block.tsx | 149 +++++++-- apps/sim/blocks/blocks.test.ts | 3 +- apps/sim/blocks/blocks/router.ts | 300 ++++++++++++++++-- apps/sim/blocks/registry.ts | 3 +- apps/sim/blocks/types.ts | 1 + apps/sim/executor/constants.ts | 7 +- apps/sim/executor/dag/construction/edges.ts | 67 +++- .../handlers/router/router-handler.ts | 199 +++++++++++- 10 files changed, 863 insertions(+), 108 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx index 5754ee1492..9801a4f57e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx @@ -12,6 +12,7 @@ import { getCodeEditorProps, highlight, languages, + Textarea, Tooltip, } from '@/components/emcn' import { Trash } from '@/components/emcn/icons/trash' @@ -74,6 +75,8 @@ interface ConditionInputProps { previewValue?: string | null /** Whether the component is disabled */ disabled?: boolean + /** Mode: 'condition' for code editor, 'router' for text input */ + mode?: 'condition' | 'router' } /** @@ -101,7 +104,9 @@ export function ConditionInput({ isPreview = false, previewValue, disabled = false, + mode = 'condition', }: ConditionInputProps) { + const isRouterMode = mode === 'router' const params = useParams() const workspaceId = params.workspaceId as string const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlockId) @@ -161,32 +166,50 @@ export function ConditionInput({ const shouldPersistRef = useRef(false) /** - * Creates default if/else conditional blocks with stable IDs. + * Creates default blocks with stable IDs. + * For conditions: if/else blocks. For router: one route block. * - * @returns Array of two default blocks (if and else) + * @returns Array of default blocks */ - const createDefaultBlocks = (): ConditionalBlock[] => [ - { - id: generateStableId(blockId, 'if'), - title: 'if', - value: '', - showTags: false, - showEnvVars: false, - searchTerm: '', - cursorPosition: 0, - activeSourceBlockId: null, - }, - { - id: generateStableId(blockId, 'else'), - title: 'else', - value: '', - showTags: false, - showEnvVars: false, - searchTerm: '', - cursorPosition: 0, - activeSourceBlockId: null, - }, - ] + const createDefaultBlocks = (): ConditionalBlock[] => { + if (isRouterMode) { + return [ + { + id: generateStableId(blockId, 'route1'), + title: 'route1', + value: '', + showTags: false, + showEnvVars: false, + searchTerm: '', + cursorPosition: 0, + activeSourceBlockId: null, + }, + ] + } + + return [ + { + id: generateStableId(blockId, 'if'), + title: 'if', + value: '', + showTags: false, + showEnvVars: false, + searchTerm: '', + cursorPosition: 0, + activeSourceBlockId: null, + }, + { + id: generateStableId(blockId, 'else'), + title: 'else', + value: '', + showTags: false, + showEnvVars: false, + searchTerm: '', + cursorPosition: 0, + activeSourceBlockId: null, + }, + ] + } // Initialize with a loading state instead of default blocks const [conditionalBlocks, setConditionalBlocks] = useState([]) @@ -270,10 +293,13 @@ export function ConditionInput({ const parsedBlocks = safeParseJSON(effectiveValueStr) if (parsedBlocks) { - const blocksWithCorrectTitles = parsedBlocks.map((block, index) => ({ - ...block, - title: index === 0 ? 'if' : index === parsedBlocks.length - 1 ? 'else' : 'else if', - })) + // For router mode, keep original titles. For condition mode, assign if/else if/else + const blocksWithCorrectTitles = isRouterMode + ? parsedBlocks + : parsedBlocks.map((block, index) => ({ + ...block, + title: index === 0 ? 'if' : index === parsedBlocks.length - 1 ? 'else' : 'else if', + })) setConditionalBlocks(blocksWithCorrectTitles) hasInitializedRef.current = true @@ -573,12 +599,17 @@ export function ConditionInput({ /** * Updates block titles based on their position in the array. - * First block is always 'if', last is 'else', middle ones are 'else if'. + * For conditions: First block is 'if', last is 'else', middle ones are 'else if'. + * For router: Titles are user-editable and not auto-updated. * * @param blocks - Array of conditional blocks * @returns Updated blocks with correct titles */ const updateBlockTitles = (blocks: ConditionalBlock[]): ConditionalBlock[] => { + if (isRouterMode) { + // For router mode, don't change titles - they're user-editable + return blocks + } return blocks.map((block, index) => ({ ...block, title: index === 0 ? 'if' : index === blocks.length - 1 ? 'else' : 'else if', @@ -590,13 +621,15 @@ export function ConditionInput({ if (isPreview || disabled) return const blockIndex = conditionalBlocks.findIndex((block) => block.id === afterId) - if (conditionalBlocks[blockIndex]?.title === 'else') return + if (!isRouterMode && conditionalBlocks[blockIndex]?.title === 'else') return - const newBlockId = generateStableId(blockId, `else-if-${Date.now()}`) + const newBlockId = isRouterMode + ? generateStableId(blockId, `route-${Date.now()}`) + : generateStableId(blockId, `else-if-${Date.now()}`) const newBlock: ConditionalBlock = { id: newBlockId, - title: '', + title: isRouterMode ? `route-${Date.now()}` : '', value: '', showTags: false, showEnvVars: false, @@ -710,13 +743,15 @@ export function ConditionInput({

- {block.title} + {isRouterMode ? `Route ${index + 1}` : block.title}
@@ -724,7 +759,7 @@ export function ConditionInput({ - Delete Condition + + {isRouterMode ? 'Delete Route' : 'Delete Condition'} +
- {block.title !== 'else' && + {/* Router mode: show description textarea with tag/env var support */} + {isRouterMode && ( +
e.preventDefault()} + onDrop={(e) => handleDrop(block.id, e)} + > +