Add handling for failure conditions
This commit is contained in:
parent
d4ff168ae4
commit
999199dcf6
|
@ -92,7 +92,7 @@
|
||||||
)
|
)
|
||||||
loopBlock.blockToLoop = block.id
|
loopBlock.blockToLoop = block.id
|
||||||
block.loopBlock = loopBlock.id
|
block.loopBlock = loopBlock.id
|
||||||
automationStore.actions.addBlockToAutomation(loopBlock, blockIdx - 1)
|
automationStore.actions.addBlockToAutomation(loopBlock, blockIdx)
|
||||||
await automationStore.actions.save(
|
await automationStore.actions.save(
|
||||||
$automationStore.selectedAutomation?.automation
|
$automationStore.selectedAutomation?.automation
|
||||||
)
|
)
|
||||||
|
@ -131,16 +131,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="blockTitle">
|
<div class="blockTitle">
|
||||||
{#if testResult && testResult[0]}
|
|
||||||
<div style="float: right;" on:click={() => resultsModal.show()}>
|
|
||||||
<StatusLight
|
|
||||||
positive={isTrigger || testResult[0].outputs?.success}
|
|
||||||
negative={!testResult[0].outputs?.success}
|
|
||||||
><Body size="XS">View response</Body></StatusLight
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style="margin-left: 10px;"
|
style="margin-left: 10px;"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { ModalContent, Icon, Detail, TextArea } from "@budibase/bbui"
|
import { ModalContent, Icon, Detail, TextArea, Label } from "@budibase/bbui"
|
||||||
|
|
||||||
export let testResult
|
export let testResult
|
||||||
export let isTrigger
|
export let isTrigger
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<ModalContent
|
<ModalContent
|
||||||
showCloseIcon={false}
|
showCloseIcon={false}
|
||||||
showConfirmButton={false}
|
showConfirmButton={false}
|
||||||
title="Test Automation"
|
title="Test Results"
|
||||||
cancelText="Close"
|
cancelText="Close"
|
||||||
>
|
>
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
|
@ -26,7 +26,18 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span>
|
||||||
|
{#if testResult[0].outputs.iterations}
|
||||||
|
<div style="display: flex;">
|
||||||
|
<Icon name="Reuse" />
|
||||||
|
<div style="margin-left: 10px;">
|
||||||
|
<Label>
|
||||||
|
This loop ran {testResult[0].outputs.iterations} times.</Label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
<div
|
<div
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
inputToggled = !inputToggled
|
inputToggled = !inputToggled
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte"
|
import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte"
|
||||||
import { LuceneUtils } from "@budibase/frontend-core"
|
import { LuceneUtils } from "@budibase/frontend-core"
|
||||||
import { getSchemaForTable } from "builderStore/dataBinding"
|
import { getSchemaForTable } from "builderStore/dataBinding"
|
||||||
|
import { cloneDeep } from "lodash/fp"
|
||||||
|
|
||||||
export let block
|
export let block
|
||||||
export let testData
|
export let testData
|
||||||
|
@ -88,34 +89,61 @@
|
||||||
if (!block || !automation) {
|
if (!block || !automation) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find previous steps to the selected one
|
// Find previous steps to the selected one
|
||||||
let allSteps = [...automation.steps]
|
let allSteps = [...automation.steps]
|
||||||
|
|
||||||
if (automation.trigger) {
|
if (automation.trigger) {
|
||||||
allSteps = [automation.trigger, ...allSteps]
|
allSteps = [automation.trigger, ...allSteps]
|
||||||
}
|
}
|
||||||
const blockIdx = allSteps.findIndex(step => step.id === block.id)
|
let blockIdx = allSteps.findIndex(step => step.id === block.id)
|
||||||
|
|
||||||
// Extract all outputs from all previous steps as available bindings
|
let loopBlockIdx = cloneDeep(allSteps)
|
||||||
|
.splice(0, blockIdx)
|
||||||
|
.findIndex(x => x.stepId === "LOOP")
|
||||||
|
// if a loop stepId exists in previous steps, we need to decerement the blockIdx
|
||||||
|
if (loopBlockIdx > -1 && blockIdx > loopBlockIdx) {
|
||||||
|
blockIdx--
|
||||||
|
}
|
||||||
|
// Extract all outputs from all previous steps as available bindins
|
||||||
let bindings = []
|
let bindings = []
|
||||||
for (let idx = 0; idx < blockIdx; idx++) {
|
for (let idx = 0; idx < blockIdx; idx++) {
|
||||||
const outputs = Object.entries(
|
let isLoopBlock = allSteps[idx + 1]?.blockToLoop === block.id
|
||||||
allSteps[idx].schema?.outputs?.properties ?? {}
|
|
||||||
)
|
let schema = allSteps[idx]?.schema?.outputs?.properties ?? {}
|
||||||
|
if (isLoopBlock) {
|
||||||
|
schema = {
|
||||||
|
currentItem: {
|
||||||
|
type: "string",
|
||||||
|
description: "the item currently being executed",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopBlockIdx && allSteps[blockIdx - 1]?.stepId === "LOOP") {
|
||||||
|
schema = {
|
||||||
|
...schema,
|
||||||
|
...$automationStore.blockDefinitions.ACTION.LOOP.schema.outputs
|
||||||
|
.properties.properties,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const outputs = Object.entries(schema)
|
||||||
|
|
||||||
bindings = bindings.concat(
|
bindings = bindings.concat(
|
||||||
outputs.map(([name, value]) => {
|
outputs.map(([name, value]) => {
|
||||||
let runtimeName =
|
let runtimeName = isLoopBlock
|
||||||
$automationStore.selectedAutomation.automation.definition.steps.find(
|
? `loop.${name}`
|
||||||
x => block.id === x.blockToLoop
|
: `steps.${idx}.${name}`
|
||||||
)
|
|
||||||
? `loop.${name}`
|
|
||||||
: `steps.${idx}.${name}`
|
|
||||||
const runtime = idx === 0 ? `trigger.${name}` : runtimeName
|
const runtime = idx === 0 ? `trigger.${name}` : runtimeName
|
||||||
return {
|
return {
|
||||||
label: runtime,
|
label: runtime,
|
||||||
type: value.type,
|
type: value.type,
|
||||||
description: value.description,
|
description: value.description,
|
||||||
category: idx === 0 ? "Trigger outputs" : `Step ${idx} outputs`,
|
category:
|
||||||
|
idx === 0
|
||||||
|
? "Trigger outputs"
|
||||||
|
: isLoopBlock
|
||||||
|
? "Loop Outputs"
|
||||||
|
: `Step ${idx} outputs`,
|
||||||
path: runtime,
|
path: runtime,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -48,8 +48,3 @@ exports.definition = {
|
||||||
},
|
},
|
||||||
type: "LOGIC",
|
type: "LOGIC",
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.run = async function filter({ inputs }) {
|
|
||||||
let currentItem = inputs.binding
|
|
||||||
return { currentItem }
|
|
||||||
}
|
|
||||||
|
|
|
@ -86,26 +86,149 @@ class Orchestrator {
|
||||||
let stepCount = 0
|
let stepCount = 0
|
||||||
let loopStepNumber
|
let loopStepNumber
|
||||||
let loopSteps = []
|
let loopSteps = []
|
||||||
let lastLoopStep
|
|
||||||
for (let step of automation.definition.steps) {
|
for (let step of automation.definition.steps) {
|
||||||
stepCount++
|
stepCount++
|
||||||
|
let input
|
||||||
if (step.stepId === LOOP_STEP_ID) {
|
if (step.stepId === LOOP_STEP_ID) {
|
||||||
loopStep = step
|
loopStep = step
|
||||||
loopStepNumber = stepCount
|
loopStepNumber = stepCount
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let iterations = loopStep ? loopStep.inputs.binding.split(",").length : 1
|
|
||||||
|
|
||||||
|
if (loopStep) {
|
||||||
|
input = await processObject(loopStep.inputs, this._context)
|
||||||
|
}
|
||||||
|
let iterations = loopStep ? input.binding.length : 1
|
||||||
|
let iterationCount = 0
|
||||||
for (let index = 0; index < iterations; index++) {
|
for (let index = 0; index < iterations; index++) {
|
||||||
let originalStepInput = cloneDeep(step.inputs)
|
let originalStepInput = cloneDeep(step.inputs)
|
||||||
|
|
||||||
/*
|
// Handle if the user has set a max iteration count or if it reaches the max limit set by us
|
||||||
if (step.stepId === LOOP_STEP_ID && index >= loopStep.inputs.iterations) {
|
if (loopStep) {
|
||||||
this.executionOutput.steps[loopStepNumber].outputs.status = "Loop Broken"
|
// lets first of all handle the input
|
||||||
break
|
// if the input is array then use it, if it is a string then split it on every new line
|
||||||
|
let newInput = await processObject(
|
||||||
|
loopStep.inputs,
|
||||||
|
cloneDeep(this._context)
|
||||||
|
)
|
||||||
|
newInput = automationUtils.cleanInputValues(
|
||||||
|
newInput,
|
||||||
|
loopStep.schema.inputs
|
||||||
|
)
|
||||||
|
this._context.steps[loopStepNumber] = {
|
||||||
|
currentItem: newInput.binding[index],
|
||||||
|
}
|
||||||
|
let tempOutput = { items: loopSteps, iterations: iterationCount }
|
||||||
|
|
||||||
|
if (
|
||||||
|
loopStep.inputs.option === "Array" &&
|
||||||
|
!Array.isArray(newInput.binding)
|
||||||
|
) {
|
||||||
|
this.executionOutput.steps.splice(loopStepNumber, 0, {
|
||||||
|
id: step.id,
|
||||||
|
stepId: step.stepId,
|
||||||
|
outputs: {
|
||||||
|
...tempOutput,
|
||||||
|
success: true,
|
||||||
|
status: "INCORRECT_TYPE",
|
||||||
|
},
|
||||||
|
inputs: step.inputs,
|
||||||
|
})
|
||||||
|
this._context.steps.splice(loopStepNumber, 0, {
|
||||||
|
...tempOutput,
|
||||||
|
success: true,
|
||||||
|
status: "INCORRECT_TYPE",
|
||||||
|
})
|
||||||
|
|
||||||
|
loopSteps = null
|
||||||
|
loopStep = null
|
||||||
|
break
|
||||||
|
} else if (
|
||||||
|
loopStep.inputs.option === "String" &&
|
||||||
|
typeof newInput.binding !== "string"
|
||||||
|
) {
|
||||||
|
this.executionOutput.steps.splice(loopStepNumber, 0, {
|
||||||
|
id: step.id,
|
||||||
|
stepId: step.stepId,
|
||||||
|
outputs: {
|
||||||
|
...tempOutput,
|
||||||
|
success: false,
|
||||||
|
status: "INCORRECT_TYPE",
|
||||||
|
},
|
||||||
|
inputs: step.inputs,
|
||||||
|
})
|
||||||
|
this._context.steps.splice(loopStepNumber, 0, {
|
||||||
|
...tempOutput,
|
||||||
|
success: true,
|
||||||
|
status: "INCORRECT_TYPE",
|
||||||
|
})
|
||||||
|
|
||||||
|
loopSteps = null
|
||||||
|
loopStep = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "Loop" binding in the front end is "fake", so replace it here so the context can understand it
|
||||||
|
for (let key in originalStepInput) {
|
||||||
|
if (key === "row") {
|
||||||
|
for (let test in originalStepInput["row"]) {
|
||||||
|
originalStepInput["row"][test] = originalStepInput["row"][
|
||||||
|
test
|
||||||
|
].replace(/loop/, `steps.${loopStepNumber}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
originalStepInput[key] = originalStepInput[key].replace(
|
||||||
|
/loop/,
|
||||||
|
`steps.${loopStepNumber}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= loopStep.inputs.iterations) {
|
||||||
|
this.executionOutput.steps.splice(loopStepNumber, 0, {
|
||||||
|
id: step.id,
|
||||||
|
stepId: step.stepId,
|
||||||
|
outputs: { ...tempOutput, success: true, status: "LOOP_BROKEN" },
|
||||||
|
inputs: step.inputs,
|
||||||
|
})
|
||||||
|
this._context.steps.splice(loopStepNumber, 0, {
|
||||||
|
...tempOutput,
|
||||||
|
success: true,
|
||||||
|
status: "LOOP_BROKEN",
|
||||||
|
})
|
||||||
|
|
||||||
|
loopSteps = null
|
||||||
|
loopStep = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this._context.steps[loopStepNumber]?.currentItem ===
|
||||||
|
loopStep.inputs.failure
|
||||||
|
) {
|
||||||
|
console.log("hello?????")
|
||||||
|
this.executionOutput.steps.splice(loopStepNumber, 0, {
|
||||||
|
id: step.id,
|
||||||
|
stepId: step.stepId,
|
||||||
|
outputs: {
|
||||||
|
...tempOutput,
|
||||||
|
success: false,
|
||||||
|
status: "FAILURE_CONDITION_MET",
|
||||||
|
},
|
||||||
|
inputs: step.inputs,
|
||||||
|
})
|
||||||
|
this._context.steps.splice(loopStepNumber, 0, {
|
||||||
|
...tempOutput,
|
||||||
|
success: false,
|
||||||
|
status: "FAILURE_CONDITION_MET",
|
||||||
|
})
|
||||||
|
|
||||||
|
loopSteps = null
|
||||||
|
loopStep = null
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
// execution stopped, record state for that
|
// execution stopped, record state for that
|
||||||
if (stopped) {
|
if (stopped) {
|
||||||
this.updateExecutionOutput(step.id, step.stepId, {}, STOPPED_STATUS)
|
this.updateExecutionOutput(step.id, step.stepId, {}, STOPPED_STATUS)
|
||||||
|
@ -113,11 +236,6 @@ class Orchestrator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a loop step, we need to manually add the bindings to the context
|
// If it's a loop step, we need to manually add the bindings to the context
|
||||||
if (loopStep) {
|
|
||||||
this._context.steps[loopStepNumber] = {
|
|
||||||
currentItem: loopStep.inputs.binding.split(",")[index],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let stepFn = await this.getStepFunctionality(step.stepId)
|
let stepFn = await this.getStepFunctionality(step.stepId)
|
||||||
let inputs = await processObject(originalStepInput, this._context)
|
let inputs = await processObject(originalStepInput, this._context)
|
||||||
inputs = automationUtils.cleanInputValues(inputs, step.schema.inputs)
|
inputs = automationUtils.cleanInputValues(inputs, step.schema.inputs)
|
||||||
|
@ -143,7 +261,6 @@ class Orchestrator {
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
this._context.steps.splice(loopStepNumber, 1)
|
|
||||||
if (loopStep && loopSteps) {
|
if (loopStep && loopSteps) {
|
||||||
loopSteps.push(outputs)
|
loopSteps.push(outputs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,26 +275,34 @@ class Orchestrator {
|
||||||
console.error(`Automation error - ${step.stepId} - ${err}`)
|
console.error(`Automation error - ${step.stepId} - ${err}`)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if (loopStep) {
|
||||||
if (index === iterations - 1) {
|
iterationCount++
|
||||||
lastLoopStep = loopStep
|
if (index === iterations - 1) {
|
||||||
loopStep = null
|
loopStep = null
|
||||||
break
|
this._context.steps.splice(loopStepNumber, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loopSteps && loopSteps.length) {
|
if (loopSteps && loopSteps.length) {
|
||||||
let tempOutput = { success: true, outputs: loopSteps }
|
let tempOutput = {
|
||||||
this.executionOutput.steps.splice(loopStep, 0, {
|
success: true,
|
||||||
id: lastLoopStep.id,
|
items: loopSteps,
|
||||||
stepId: lastLoopStep.stepId,
|
iterations: iterationCount,
|
||||||
|
}
|
||||||
|
this.executionOutput.steps.splice(loopStepNumber + 1, 0, {
|
||||||
|
id: step.id,
|
||||||
|
stepId: step.stepId,
|
||||||
outputs: tempOutput,
|
outputs: tempOutput,
|
||||||
inputs: step.inputs,
|
inputs: step.inputs,
|
||||||
})
|
})
|
||||||
this._context.steps.splice(loopStep, 0, tempOutput)
|
|
||||||
|
this._context.steps.splice(loopStepNumber, 0, tempOutput)
|
||||||
loopSteps = null
|
loopSteps = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.executionOutput
|
return this.executionOutput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue