diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts index 4cc36a67d..0cfc45369 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts @@ -34,3 +34,4 @@ export { Text } from './text/text' export { TimeInput } from './time-input/time-input' export { ToolInput } from './tool-input/tool-input' export { VariablesInput } from './variables-input/variables-input' +export { WorkflowSelectorInput } from './workflow-selector/workflow-selector-input' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/workflow-selector/workflow-selector-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/workflow-selector/workflow-selector-input.tsx new file mode 100644 index 000000000..5771e9f89 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/workflow-selector/workflow-selector-input.tsx @@ -0,0 +1,45 @@ +'use client' + +import { useMemo } from 'react' +import { SelectorCombobox } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/selector-combobox/selector-combobox' +import type { SubBlockConfig } from '@/blocks/types' +import type { SelectorContext } from '@/hooks/selectors/types' +import { useWorkflowRegistry } from '@/stores/workflows/registry/store' + +interface WorkflowSelectorInputProps { + blockId: string + subBlock: SubBlockConfig + disabled?: boolean + isPreview?: boolean + previewValue?: string | null +} + +export function WorkflowSelectorInput({ + blockId, + subBlock, + disabled = false, + isPreview = false, + previewValue, +}: WorkflowSelectorInputProps) { + const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) + + const context: SelectorContext = useMemo( + () => ({ + excludeWorkflowId: activeWorkflowId ?? undefined, + }), + [activeWorkflowId] + ) + + return ( + + ) +} 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 2ea7cb557..274bba15b 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 @@ -40,6 +40,7 @@ import { TimeInput, ToolInput, VariablesInput, + WorkflowSelectorInput, } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components' import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate' import type { SubBlockConfig } from '@/blocks/types' @@ -90,7 +91,6 @@ const isFieldRequired = (config: SubBlockConfig, subBlockValues?: Record ) + case 'workflow-selector': + return ( + + ) + case 'mcp-server-selector': return ( => { - try { - const { workflows, activeWorkflowId } = useWorkflowRegistry.getState() - - // Filter out the current workflow to prevent recursion - const availableWorkflows = Object.entries(workflows) - .filter(([id]) => id !== activeWorkflowId) - .map(([id, workflow]) => ({ - label: workflow.name || `Workflow ${id.slice(0, 8)}`, - id: id, - })) - .sort((a, b) => a.label.localeCompare(b.label)) - - return availableWorkflows - } catch (error) { - logger.error('Error getting available workflows:', error) - return [] - } -} export const WorkflowBlock: BlockConfig = { type: 'workflow', @@ -38,8 +13,7 @@ export const WorkflowBlock: BlockConfig = { { id: 'workflowId', title: 'Select Workflow', - type: 'combobox', - options: getAvailableWorkflows, + type: 'workflow-selector', placeholder: 'Search workflows...', required: true, }, diff --git a/apps/sim/blocks/blocks/workflow_input.ts b/apps/sim/blocks/blocks/workflow_input.ts index c918ded44..16e48c4f2 100644 --- a/apps/sim/blocks/blocks/workflow_input.ts +++ b/apps/sim/blocks/blocks/workflow_input.ts @@ -1,18 +1,5 @@ import { WorkflowIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { useWorkflowRegistry } from '@/stores/workflows/registry/store' - -const getAvailableWorkflows = (): Array<{ label: string; id: string }> => { - try { - const { workflows, activeWorkflowId } = useWorkflowRegistry.getState() - return Object.entries(workflows) - .filter(([id]) => id !== activeWorkflowId) - .map(([id, w]) => ({ label: w.name || `Workflow ${id.slice(0, 8)}`, id })) - .sort((a, b) => a.label.localeCompare(b.label)) - } catch { - return [] - } -} export const WorkflowInputBlock: BlockConfig = { type: 'workflow_input', @@ -25,18 +12,16 @@ export const WorkflowInputBlock: BlockConfig = { `, category: 'blocks', docsLink: 'https://docs.sim.ai/blocks/workflow', - bgColor: '#6366F1', // Indigo - modern and professional + bgColor: '#6366F1', icon: WorkflowIcon, subBlocks: [ { id: 'workflowId', title: 'Select Workflow', - type: 'combobox', - options: getAvailableWorkflows, + type: 'workflow-selector', placeholder: 'Search workflows...', required: true, }, - // Renders dynamic mapping UI based on selected child workflow's Start trigger inputFormat { id: 'inputMapping', title: 'Input Mapping', diff --git a/apps/sim/hooks/selectors/registry.ts b/apps/sim/hooks/selectors/registry.ts index 0a373af29..6b0674b75 100644 --- a/apps/sim/hooks/selectors/registry.ts +++ b/apps/sim/hooks/selectors/registry.ts @@ -6,6 +6,7 @@ import type { SelectorOption, SelectorQueryArgs, } from '@/hooks/selectors/types' +import { useWorkflowRegistry } from '@/stores/workflows/registry/store' const SELECTOR_STALE = 60 * 1000 @@ -853,6 +854,36 @@ const registry: Record = { })) }, }, + 'sim.workflows': { + key: 'sim.workflows', + staleTime: 0, // Always fetch fresh from store + getQueryKey: ({ context }: SelectorQueryArgs) => [ + 'selectors', + 'sim.workflows', + context.excludeWorkflowId ?? 'none', + ], + enabled: () => true, + fetchList: async ({ context }: SelectorQueryArgs): Promise => { + const { workflows } = useWorkflowRegistry.getState() + return Object.entries(workflows) + .filter(([id]) => id !== context.excludeWorkflowId) + .map(([id, workflow]) => ({ + id, + label: workflow.name || `Workflow ${id.slice(0, 8)}`, + })) + .sort((a, b) => a.label.localeCompare(b.label)) + }, + fetchById: async ({ detailId }: SelectorQueryArgs): Promise => { + if (!detailId) return null + const { workflows } = useWorkflowRegistry.getState() + const workflow = workflows[detailId] + if (!workflow) return null + return { + id: detailId, + label: workflow.name || `Workflow ${detailId.slice(0, 8)}`, + } + }, + }, } export function getSelectorDefinition(key: SelectorKey): SelectorDefinition { diff --git a/apps/sim/hooks/selectors/types.ts b/apps/sim/hooks/selectors/types.ts index d42340f58..b884a4719 100644 --- a/apps/sim/hooks/selectors/types.ts +++ b/apps/sim/hooks/selectors/types.ts @@ -29,6 +29,7 @@ export type SelectorKey = | 'webflow.sites' | 'webflow.collections' | 'webflow.items' + | 'sim.workflows' export interface SelectorOption { id: string @@ -52,6 +53,7 @@ export interface SelectorContext { siteId?: string collectionId?: string spreadsheetId?: string + excludeWorkflowId?: string } export interface SelectorQueryArgs {