Workflow iterator continues on faillure (#18325)

<img width="450" height="212" alt="Capture d’écran 2026-03-03 à 11 41
54"
src="https://github.com/user-attachments/assets/b2c29a48-7dc0-4b16-a085-8f305d21f7ca"
/>

New status `FAIL_SAFE` added. This status propagates to the following
nodes until reaching the iterator, that will start the new iteration.

The difference with `SKIP` is that, when the parent nodes have at least
one `FAIL_SAFE`, it becomes `FAIL_SAFE` too. While a parent 1 `SKIP` +
parent 2 `SUCCESS` => to be executed.

I also thought about just going back to the iterator as a break would,
but since we have branches, it may lead to inconsistent statuses with
parallel updates.
This commit is contained in:
Thomas Trompette
2026-03-03 14:18:57 +01:00
committed by GitHub
parent d48c58640c
commit b2b3a3f860
29 changed files with 1410 additions and 456 deletions
@@ -1,4 +1,5 @@
import { FormArrayFieldInput } from '@/object-record/record-field/ui/form-types/components/FormArrayFieldInput';
import { FormBooleanFieldToggleInput } from '@/object-record/record-field/ui/form-types/components/FormBooleanFieldToggleInput';
import { type FieldArrayValue } from '@/object-record/record-field/ui/types/FieldMetadata';
import { type WorkflowIteratorAction } from '@/workflow/types/Workflow';
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
@@ -56,6 +57,8 @@ export const WorkflowEditActionIterator = ({
const [formData, setFormData] = useState({
items: parsedItems,
initialLoopStepIds: action.settings.input.initialLoopStepIds || [],
shouldContinueOnIterationFailure:
action.settings.input.shouldContinueOnIterationFailure ?? false,
});
const saveAction = useDebouncedCallback(
@@ -71,6 +74,8 @@ export const WorkflowEditActionIterator = ({
input: {
items: updatedFormData.items,
initialLoopStepIds: updatedFormData.initialLoopStepIds,
shouldContinueOnIterationFailure:
updatedFormData.shouldContinueOnIterationFailure,
},
},
});
@@ -80,7 +85,7 @@ export const WorkflowEditActionIterator = ({
const handleFieldChange = (
field: string,
value: string | FieldArrayValue,
value: string | FieldArrayValue | boolean,
) => {
if (actionOptions.readonly === true) {
return;
@@ -104,6 +109,15 @@ export const WorkflowEditActionIterator = ({
readonly={actionOptions.readonly}
VariablePicker={WorkflowVariablePicker}
/>
<FormBooleanFieldToggleInput
description={t`Continue on iteration failure`}
value={formData.shouldContinueOnIterationFailure}
onChange={(value) =>
handleFieldChange('shouldContinueOnIterationFailure', value)
}
disabled={actionOptions.readonly}
hint={t`Will continue to the next iteration even if the current one fails`}
/>
</WorkflowStepBody>
{!actionOptions.readonly && <WorkflowStepFooter stepId={action.id} />}
</>