Add handling for failure conditions
This commit is contained in:
parent
d4ff168ae4
commit
999199dcf6
|
@ -92,7 +92,7 @@
|
|||
)
|
||||
loopBlock.blockToLoop = block.id
|
||||
block.loopBlock = loopBlock.id
|
||||
automationStore.actions.addBlockToAutomation(loopBlock, blockIdx - 1)
|
||||
automationStore.actions.addBlockToAutomation(loopBlock, blockIdx)
|
||||
await automationStore.actions.save(
|
||||
$automationStore.selectedAutomation?.automation
|
||||
)
|
||||
|
@ -131,16 +131,6 @@
|
|||
</div>
|
||||
|
||||
<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
|
||||
style="margin-left: 10px;"
|
||||
on:click={() => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { ModalContent, Icon, Detail, TextArea } from "@budibase/bbui"
|
||||
import { ModalContent, Icon, Detail, TextArea, Label } from "@budibase/bbui"
|
||||
|
||||
export let testResult
|
||||
export let isTrigger
|
||||
|
@ -10,7 +10,7 @@
|
|||
<ModalContent
|
||||
showCloseIcon={false}
|
||||
showConfirmButton={false}
|
||||
title="Test Automation"
|
||||
title="Test Results"
|
||||
cancelText="Close"
|
||||
>
|
||||
<div slot="header">
|
||||
|
@ -26,7 +26,18 @@
|
|||
{/if}
|
||||
</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
|
||||
on:click={() => {
|
||||
inputToggled = !inputToggled
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte"
|
||||
import { LuceneUtils } from "@budibase/frontend-core"
|
||||
import { getSchemaForTable } from "builderStore/dataBinding"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
|
||||
export let block
|
||||
export let testData
|
||||
|
@ -88,34 +89,61 @@
|
|||
if (!block || !automation) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Find previous steps to the selected one
|
||||
let allSteps = [...automation.steps]
|
||||
|
||||
if (automation.trigger) {
|
||||
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 = []
|
||||
for (let idx = 0; idx < blockIdx; idx++) {
|
||||
const outputs = Object.entries(
|
||||
allSteps[idx].schema?.outputs?.properties ?? {}
|
||||
)
|
||||
let isLoopBlock = allSteps[idx + 1]?.blockToLoop === block.id
|
||||
|
||||
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(
|
||||
outputs.map(([name, value]) => {
|
||||
let runtimeName =
|
||||
$automationStore.selectedAutomation.automation.definition.steps.find(
|
||||
x => block.id === x.blockToLoop
|
||||
)
|
||||
? `loop.${name}`
|
||||
: `steps.${idx}.${name}`
|
||||
let runtimeName = isLoopBlock
|
||||
? `loop.${name}`
|
||||
: `steps.${idx}.${name}`
|
||||
const runtime = idx === 0 ? `trigger.${name}` : runtimeName
|
||||
return {
|
||||
label: runtime,
|
||||
type: value.type,
|
||||
description: value.description,
|
||||
category: idx === 0 ? "Trigger outputs" : `Step ${idx} outputs`,
|
||||
category:
|
||||
idx === 0
|
||||
? "Trigger outputs"
|
||||
: isLoopBlock
|
||||
? "Loop Outputs"
|
||||
: `Step ${idx} outputs`,
|
||||
path: runtime,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -48,8 +48,3 @@ exports.definition = {
|
|||
},
|
||||
type: "LOGIC",
|
||||
}
|
||||
|
||||
exports.run = async function filter({ inputs }) {
|
||||
let currentItem = inputs.binding
|
||||
return { currentItem }
|
||||
}
|
||||
|
|
|
@ -86,26 +86,149 @@ class Orchestrator {
|
|||
let stepCount = 0
|
||||
let loopStepNumber
|
||||
let loopSteps = []
|
||||
let lastLoopStep
|
||||
for (let step of automation.definition.steps) {
|
||||
stepCount++
|
||||
let input
|
||||
if (step.stepId === LOOP_STEP_ID) {
|
||||
loopStep = step
|
||||
loopStepNumber = stepCount
|
||||
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++) {
|
||||
let originalStepInput = cloneDeep(step.inputs)
|
||||
|
||||
/*
|
||||
if (step.stepId === LOOP_STEP_ID && index >= loopStep.inputs.iterations) {
|
||||
this.executionOutput.steps[loopStepNumber].outputs.status = "Loop Broken"
|
||||
break
|
||||
// Handle if the user has set a max iteration count or if it reaches the max limit set by us
|
||||
if (loopStep) {
|
||||
// lets first of all handle the input
|
||||
// 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
|
||||
if (stopped) {
|
||||
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 (loopStep) {
|
||||
this._context.steps[loopStepNumber] = {
|
||||
currentItem: loopStep.inputs.binding.split(",")[index],
|
||||
}
|
||||
}
|
||||
let stepFn = await this.getStepFunctionality(step.stepId)
|
||||
let inputs = await processObject(originalStepInput, this._context)
|
||||
inputs = automationUtils.cleanInputValues(inputs, step.schema.inputs)
|
||||
|
@ -143,7 +261,6 @@ class Orchestrator {
|
|||
})
|
||||
continue
|
||||
}
|
||||
this._context.steps.splice(loopStepNumber, 1)
|
||||
if (loopStep && loopSteps) {
|
||||
loopSteps.push(outputs)
|
||||
} else {
|
||||
|
@ -158,26 +275,34 @@ class Orchestrator {
|
|||
console.error(`Automation error - ${step.stepId} - ${err}`)
|
||||
return err
|
||||
}
|
||||
|
||||
if (index === iterations - 1) {
|
||||
lastLoopStep = loopStep
|
||||
loopStep = null
|
||||
break
|
||||
if (loopStep) {
|
||||
iterationCount++
|
||||
if (index === iterations - 1) {
|
||||
loopStep = null
|
||||
this._context.steps.splice(loopStepNumber, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loopSteps && loopSteps.length) {
|
||||
let tempOutput = { success: true, outputs: loopSteps }
|
||||
this.executionOutput.steps.splice(loopStep, 0, {
|
||||
id: lastLoopStep.id,
|
||||
stepId: lastLoopStep.stepId,
|
||||
let tempOutput = {
|
||||
success: true,
|
||||
items: loopSteps,
|
||||
iterations: iterationCount,
|
||||
}
|
||||
this.executionOutput.steps.splice(loopStepNumber + 1, 0, {
|
||||
id: step.id,
|
||||
stepId: step.stepId,
|
||||
outputs: tempOutput,
|
||||
inputs: step.inputs,
|
||||
})
|
||||
this._context.steps.splice(loopStep, 0, tempOutput)
|
||||
|
||||
this._context.steps.splice(loopStepNumber, 0, tempOutput)
|
||||
loopSteps = null
|
||||
}
|
||||
}
|
||||
|
||||
return this.executionOutput
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue