mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
fix(triggers): fix triggers in subflows (#1883)
This commit is contained in:
committed by
GitHub
parent
cd48cd4de4
commit
991b0e31ad
@@ -11,6 +11,7 @@ import {
|
||||
export enum TriggerWarningType {
|
||||
DUPLICATE_TRIGGER = 'duplicate_trigger',
|
||||
LEGACY_INCOMPATIBILITY = 'legacy_incompatibility',
|
||||
TRIGGER_IN_SUBFLOW = 'trigger_in_subflow',
|
||||
}
|
||||
|
||||
interface TriggerWarningDialogProps {
|
||||
@@ -32,6 +33,8 @@ export function TriggerWarningDialog({
|
||||
return 'Cannot mix trigger types'
|
||||
case TriggerWarningType.DUPLICATE_TRIGGER:
|
||||
return `Only one ${triggerName} trigger allowed`
|
||||
case TriggerWarningType.TRIGGER_IN_SUBFLOW:
|
||||
return 'Triggers not allowed in subflows'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +44,8 @@ export function TriggerWarningDialog({
|
||||
return 'Cannot add new trigger blocks when a legacy Start block exists. Available in newer workflows.'
|
||||
case TriggerWarningType.DUPLICATE_TRIGGER:
|
||||
return `A workflow can only have one ${triggerName} trigger block. Please remove the existing one before adding a new one.`
|
||||
case TriggerWarningType.TRIGGER_IN_SUBFLOW:
|
||||
return 'Triggers cannot be placed inside loop or parallel subflows.'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -731,6 +731,24 @@ const WorkflowContent = React.memo(() => {
|
||||
prevDiffReadyRef.current = isDiffReady
|
||||
}, [isDiffReady, diffAnalysis, fitView])
|
||||
|
||||
// Listen for trigger warning events
|
||||
useEffect(() => {
|
||||
const handleShowTriggerWarning = (event: CustomEvent) => {
|
||||
const { type, triggerName } = event.detail
|
||||
setTriggerWarning({
|
||||
open: true,
|
||||
triggerName: triggerName || 'trigger',
|
||||
type: type === 'trigger_in_subflow' ? TriggerWarningType.TRIGGER_IN_SUBFLOW : type,
|
||||
})
|
||||
}
|
||||
|
||||
window.addEventListener('show-trigger-warning', handleShowTriggerWarning as EventListener)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('show-trigger-warning', handleShowTriggerWarning as EventListener)
|
||||
}
|
||||
}, [setTriggerWarning])
|
||||
|
||||
// Handler for trigger selection from list
|
||||
const handleTriggerSelect = useCallback(
|
||||
(triggerId: string, enableTriggerMode?: boolean) => {
|
||||
@@ -849,6 +867,22 @@ const WorkflowContent = React.memo(() => {
|
||||
const name = getUniqueBlockName(baseName, blocks)
|
||||
|
||||
if (containerInfo) {
|
||||
// Check if this is a trigger block or has trigger mode enabled
|
||||
const isTriggerBlock =
|
||||
blockConfig.category === 'triggers' ||
|
||||
blockConfig.triggers?.enabled ||
|
||||
data.enableTriggerMode === true
|
||||
|
||||
if (isTriggerBlock) {
|
||||
const triggerName = TriggerUtils.getDefaultTriggerName(data.type) || 'trigger'
|
||||
setTriggerWarning({
|
||||
open: true,
|
||||
triggerName,
|
||||
type: TriggerWarningType.TRIGGER_IN_SUBFLOW,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate position relative to the container's content area
|
||||
// Account for header (50px), left padding (16px), and top padding (16px)
|
||||
const headerHeight = 50
|
||||
@@ -1714,6 +1748,28 @@ const WorkflowContent = React.memo(() => {
|
||||
return
|
||||
}
|
||||
|
||||
// Trigger blocks cannot be placed inside loop or parallel subflows
|
||||
if (potentialParentId) {
|
||||
const block = blocks[node.id]
|
||||
if (block && TriggerUtils.isTriggerBlock(block)) {
|
||||
const triggerName = TriggerUtils.getDefaultTriggerName(block.type) || 'trigger'
|
||||
setTriggerWarning({
|
||||
open: true,
|
||||
triggerName,
|
||||
type: TriggerWarningType.TRIGGER_IN_SUBFLOW,
|
||||
})
|
||||
logger.warn('Prevented trigger block from being placed inside a container', {
|
||||
blockId: node.id,
|
||||
blockType: block.type,
|
||||
attemptedParentId: potentialParentId,
|
||||
})
|
||||
// Reset state without updating parent
|
||||
setDraggedNodeId(null)
|
||||
setPotentialParentId(null)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Update the node's parent relationship
|
||||
if (potentialParentId) {
|
||||
// Compute relative position BEFORE updating parent to avoid stale state
|
||||
|
||||
@@ -971,6 +971,23 @@ export function useCollaborativeWorkflow() {
|
||||
|
||||
const newTriggerMode = !currentBlock.triggerMode
|
||||
|
||||
// When enabling trigger mode, check if block is inside a subflow
|
||||
if (newTriggerMode && currentBlock.data?.parentId) {
|
||||
const parent = workflowStore.blocks[currentBlock.data.parentId]
|
||||
if (parent && (parent.type === 'loop' || parent.type === 'parallel')) {
|
||||
// Dispatch custom event to show warning modal
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('show-trigger-warning', {
|
||||
detail: {
|
||||
type: 'trigger_in_subflow',
|
||||
triggerName: 'trigger',
|
||||
},
|
||||
})
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
executeQueuedOperation(
|
||||
'update-trigger-mode',
|
||||
'block',
|
||||
|
||||
@@ -564,4 +564,32 @@ export class TriggerUtils {
|
||||
|
||||
return `Multiple ${triggerName} Trigger blocks found. Keep only one.`
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a block is inside a loop or parallel subflow
|
||||
* @param blockId - ID of the block to check
|
||||
* @param blocks - Record of all blocks in the workflow
|
||||
* @returns true if the block is inside a loop or parallel, false otherwise
|
||||
*/
|
||||
static isBlockInSubflow<T extends { id: string; data?: { parentId?: string } }>(
|
||||
blockId: string,
|
||||
blocks: T[] | Record<string, T>
|
||||
): boolean {
|
||||
const blockArray = Array.isArray(blocks) ? blocks : Object.values(blocks)
|
||||
const block = blockArray.find((b) => b.id === blockId)
|
||||
|
||||
if (!block || !block.data?.parentId) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the parent is a loop or parallel block
|
||||
const parent = blockArray.find((b) => b.id === block.data?.parentId)
|
||||
if (!parent) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Type-safe check: parent must have a 'type' property
|
||||
const parentWithType = parent as T & { type?: string }
|
||||
return parentWithType.type === 'loop' || parentWithType.type === 'parallel'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1051,6 +1051,20 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
||||
|
||||
const newTriggerMode = !block.triggerMode
|
||||
|
||||
// When switching TO trigger mode, check if block is inside a subflow
|
||||
if (newTriggerMode && block.data?.parentId) {
|
||||
const parent = get().blocks[block.data.parentId]
|
||||
if (parent && (parent.type === 'loop' || parent.type === 'parallel')) {
|
||||
logger.warn('Cannot enable trigger mode for block inside loop or parallel subflow', {
|
||||
blockId: id,
|
||||
blockType: block.type,
|
||||
parentId: block.data.parentId,
|
||||
parentType: parent.type,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// When switching TO trigger mode, remove all incoming connections
|
||||
let filteredEdges = [...get().edges]
|
||||
if (newTriggerMode) {
|
||||
|
||||
Reference in New Issue
Block a user