From 8d4d86556976bbdce041e94e063260f105209c3f Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 15 Jan 2026 15:40:24 -0800 Subject: [PATCH 01/20] hide form deployment tab from docs --- apps/docs/content/docs/en/execution/meta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/content/docs/en/execution/meta.json b/apps/docs/content/docs/en/execution/meta.json index 02f2c537db..37cac68f5a 100644 --- a/apps/docs/content/docs/en/execution/meta.json +++ b/apps/docs/content/docs/en/execution/meta.json @@ -1,3 +1,3 @@ { - "pages": ["index", "basics", "api", "form", "logging", "costs"] + "pages": ["index", "basics", "api", "logging", "costs"] } From 87280c8a3de2c8942a8c58c33dd5cfbf2f34d5c7 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 15 Jan 2026 16:38:58 -0800 Subject: [PATCH 02/20] progress --- .../components/combobox/combobox.tsx | 37 ++- .../components/dropdown/dropdown.tsx | 37 ++- .../sub-block/hooks/use-depends-on-gate.ts | 40 ++- .../editor/components/sub-block/sub-block.tsx | 51 +++- .../panel/components/editor/editor.tsx | 119 +++++++-- .../hooks/use-editor-subblock-layout.ts | 82 +++--- .../workflow-block/workflow-block.tsx | 120 ++++++--- .../components/block-details-sidebar.tsx | 86 +++---- apps/sim/hooks/use-collaborative-workflow.ts | 20 ++ .../credentials/credential-extractor.ts | 64 ++--- .../sim/lib/workflows/subblocks/visibility.ts | 236 ++++++++++++++++++ apps/sim/serializer/index.test.ts | 67 +++-- apps/sim/serializer/index.ts | 222 ++++++++-------- apps/sim/socket/constants.ts | 1 + apps/sim/socket/database/operations.ts | 40 +++ apps/sim/socket/middleware/permissions.ts | 1 + apps/sim/socket/validation/schemas.ts | 3 + apps/sim/stores/workflows/workflow/store.ts | 29 +++ apps/sim/stores/workflows/workflow/types.ts | 4 + 19 files changed, 918 insertions(+), 341 deletions(-) create mode 100644 apps/sim/lib/workflows/subblocks/visibility.ts diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx index 0565fb998c..9b4dff1d38 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx @@ -2,16 +2,23 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useReactFlow } from 'reactflow' import { Combobox, type ComboboxOption } from '@/components/emcn/components' import { cn } from '@/lib/core/utils/cn' +import { + buildCanonicalIndex, + hasAdvancedValues, + resolveDependencyValue, +} from '@/lib/workflows/subblocks/visibility' import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text' import { SubBlockInputController } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sub-block-input-controller' import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value' import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-accessible-reference-prefixes' +import { getBlock } from '@/blocks/registry' import type { SubBlockConfig } from '@/blocks/types' import { getDependsOnFields } from '@/blocks/utils' import { usePermissionConfig } from '@/hooks/use-permission-config' import { getProviderFromModel } from '@/providers/utils' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' +import { useWorkflowStore } from '@/stores/workflows/workflow/store' /** * Constants for ComboBox component behavior @@ -91,15 +98,41 @@ export function ComboBox({ // Dependency tracking for fetchOptions const dependsOnFields = useMemo(() => getDependsOnFields(dependsOn), [dependsOn]) const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) + const blockState = useWorkflowStore((state) => state.blocks[blockId]) + const blockConfig = blockState?.type ? getBlock(blockState.type) : null + const canonicalIndex = useMemo( + () => buildCanonicalIndex(blockConfig?.subBlocks || []), + [blockConfig?.subBlocks] + ) + const canonicalModeOverrides = blockState?.data?.canonicalModes const dependencyValues = useSubBlockStore( useCallback( (state) => { if (dependsOnFields.length === 0 || !activeWorkflowId) return [] const workflowValues = state.workflowValues[activeWorkflowId] || {} const blockValues = workflowValues[blockId] || {} - return dependsOnFields.map((depKey) => blockValues[depKey] ?? null) + const displayAdvancedOptions = + (blockState?.advancedMode ?? false) || + hasAdvancedValues(blockConfig?.subBlocks || [], blockValues, canonicalIndex) + return dependsOnFields.map((depKey) => + resolveDependencyValue( + depKey, + blockValues, + displayAdvancedOptions, + canonicalIndex, + canonicalModeOverrides + ) + ) }, - [dependsOnFields, activeWorkflowId, blockId] + [ + dependsOnFields, + activeWorkflowId, + blockId, + blockState?.advancedMode, + blockConfig?.subBlocks, + canonicalIndex, + canonicalModeOverrides, + ] ) ) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx index 8edd3f3800..f6fced676d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx @@ -1,12 +1,19 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { Badge } from '@/components/emcn' import { Combobox, type ComboboxOption } from '@/components/emcn/components' +import { + buildCanonicalIndex, + hasAdvancedValues, + resolveDependencyValue, +} from '@/lib/workflows/subblocks/visibility' import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value' +import { getBlock } from '@/blocks/registry' import type { SubBlockConfig } from '@/blocks/types' import { getDependsOnFields } from '@/blocks/utils' import { ResponseBlockHandler } from '@/executor/handlers/response/response-handler' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' +import { useWorkflowStore } from '@/stores/workflows/workflow/store' /** * Dropdown option type - can be a simple string or an object with label, id, and optional icon @@ -89,15 +96,41 @@ export function Dropdown({ const dependsOnFields = useMemo(() => getDependsOnFields(dependsOn), [dependsOn]) const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) + const blockState = useWorkflowStore((state) => state.blocks[blockId]) + const blockConfig = blockState?.type ? getBlock(blockState.type) : null + const canonicalIndex = useMemo( + () => buildCanonicalIndex(blockConfig?.subBlocks || []), + [blockConfig?.subBlocks] + ) + const canonicalModeOverrides = blockState?.data?.canonicalModes const dependencyValues = useSubBlockStore( useCallback( (state) => { if (dependsOnFields.length === 0 || !activeWorkflowId) return [] const workflowValues = state.workflowValues[activeWorkflowId] || {} const blockValues = workflowValues[blockId] || {} - return dependsOnFields.map((depKey) => blockValues[depKey] ?? null) + const displayAdvancedOptions = + (blockState?.advancedMode ?? false) || + hasAdvancedValues(blockConfig?.subBlocks || [], blockValues, canonicalIndex) + return dependsOnFields.map((depKey) => + resolveDependencyValue( + depKey, + blockValues, + displayAdvancedOptions, + canonicalIndex, + canonicalModeOverrides + ) + ) }, - [dependsOnFields, activeWorkflowId, blockId] + [ + dependsOnFields, + activeWorkflowId, + blockId, + blockState?.advancedMode, + blockConfig?.subBlocks, + canonicalIndex, + canonicalModeOverrides, + ] ) ) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate.ts index 3c145f52fc..118f85fe4e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate.ts @@ -1,9 +1,16 @@ 'use client' import { useMemo } from 'react' +import { + buildCanonicalIndex, + hasAdvancedValues, + resolveDependencyValue, +} from '@/lib/workflows/subblocks/visibility' +import { getBlock } from '@/blocks/registry' import type { SubBlockConfig } from '@/blocks/types' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' +import { useWorkflowStore } from '@/stores/workflows/workflow/store' type DependsOnConfig = string[] | { all?: string[]; any?: string[] } @@ -50,6 +57,13 @@ export function useDependsOnGate( const previewContextValues = opts?.previewContextValues const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) + const blockState = useWorkflowStore((state) => state.blocks[blockId]) + const blockConfig = blockState?.type ? getBlock(blockState.type) : null + const canonicalIndex = useMemo( + () => buildCanonicalIndex(blockConfig?.subBlocks || []), + [blockConfig?.subBlocks] + ) + const canonicalModeOverrides = blockState?.data?.canonicalModes // Parse dependsOn config to get all/any field lists const { allFields, anyFields, allDependsOnFields } = useMemo( @@ -89,9 +103,21 @@ export function useDependsOnGate( // If previewContextValues are provided (e.g., tool parameters), use those first if (previewContextValues) { + const displayAdvancedOptions = hasAdvancedValues( + blockConfig?.subBlocks || [], + previewContextValues, + canonicalIndex + ) const map: Record = {} for (const key of allDependsOnFields) { - map[key] = normalizeDependencyValue(previewContextValues[key]) + const resolvedValue = resolveDependencyValue( + key, + previewContextValues, + displayAdvancedOptions, + canonicalIndex, + canonicalModeOverrides + ) + map[key] = normalizeDependencyValue(resolvedValue) } return map } @@ -106,9 +132,19 @@ export function useDependsOnGate( const workflowValues = state.workflowValues[activeWorkflowId] || {} const blockValues = (workflowValues as any)[blockId] || {} + const displayAdvancedOptions = + (blockState?.advancedMode ?? false) || + hasAdvancedValues(blockConfig?.subBlocks || [], blockValues, canonicalIndex) const map: Record = {} for (const key of allDependsOnFields) { - map[key] = normalizeDependencyValue((blockValues as any)[key]) + const resolvedValue = resolveDependencyValue( + key, + blockValues, + displayAdvancedOptions, + canonicalIndex, + canonicalModeOverrides + ) + map[key] = normalizeDependencyValue(resolvedValue) } return map }) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx index b3ec7fec07..c826521d62 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx @@ -1,5 +1,5 @@ import { type JSX, type MouseEvent, memo, useRef, useState } from 'react' -import { AlertTriangle, Wand2 } from 'lucide-react' +import { AlertTriangle, ArrowLeftRight, Wand2 } from 'lucide-react' import { Label, Tooltip } from '@/components/emcn/components' import { Button } from '@/components/ui/button' import { cn } from '@/lib/core/utils/cn' @@ -68,6 +68,11 @@ interface SubBlockProps { disabled?: boolean fieldDiffStatus?: FieldDiffStatus allowExpandInPreview?: boolean + canonicalToggle?: { + mode: 'basic' | 'advanced' + disabled?: boolean + onToggle?: () => void + } } /** @@ -183,7 +188,12 @@ const renderLabel = ( onSearchCancel: () => void searchInputRef: React.RefObject }, - subBlockValues?: Record + subBlockValues?: Record, + canonicalToggle?: { + mode: 'basic' | 'advanced' + disabled?: boolean + onToggle?: () => void + } ): JSX.Element | null => { if (config.type === 'switch') return null if (!config.title) return null @@ -204,12 +214,41 @@ const renderLabel = ( } = wandState const required = isFieldRequired(config, subBlockValues) + const showCanonicalToggle = !!canonicalToggle && !isPreview + const canonicalToggleDisabled = disabled || canonicalToggle?.disabled return (