Improve handling of loop handlebars string replacement

This commit is contained in:
Peter Clement 2022-04-18 09:22:23 +01:00
parent 47dcc24491
commit ef90021b05
5 changed files with 43 additions and 17 deletions

View File

@ -103,7 +103,7 @@ globals:
google: google:
clientId: "" clientId: ""
secret: "" secret: ""
automationMaxIterations: "0" automationMaxIterations: "500"
createSecrets: true # creates an internal API key, JWT secrets and redis password for you createSecrets: true # creates an internal API key, JWT secrets and redis password for you

View File

@ -1,4 +1,5 @@
const { getTable } = require("../api/controllers/table/utils") const { getTable } = require("../api/controllers/table/utils")
const { findHBSBlocks } = require("@budibase/string-templates")
/** /**
* When values are input to the system generally they will be of type string as this is required for template strings. * When values are input to the system generally they will be of type string as this is required for template strings.
@ -74,3 +75,14 @@ exports.getError = err => {
} }
return typeof err !== "string" ? err.toString() : err return typeof err !== "string" ? err.toString() : err
} }
exports.substituteLoopStep = (hbsString, substitute) => {
let blocks = findHBSBlocks(hbsString)
for (let block of blocks) {
let oldBlock = block
block = block.replace(/loop/, substitute)
hbsString = hbsString.replace(new RegExp(oldBlock, "g"), block)
}
return hbsString
}

View File

@ -32,7 +32,7 @@ exports.definition = {
properties: { properties: {
items: { items: {
customType: "item", customType: "item",
description: "the item currently being executed", description: "The item currently being executed",
}, },
success: { success: {
type: "boolean", type: "boolean",
@ -43,7 +43,7 @@ exports.definition = {
descriptions: "The amount of times the block ran", descriptions: "The amount of times the block ran",
}, },
}, },
required: ["success"], required: ["success, items, iterations"],
}, },
}, },
type: "LOGIC", type: "LOGIC",

View File

@ -190,5 +190,11 @@ exports.WebhookType = {
AUTOMATION: "automation", AUTOMATION: "automation",
} }
exports.AutomationErrors = {
INCORRECT_TYPE: "INCORRECT_TYPE",
MAX_ITERATIONS: "MAX_ITERATIONS_REACHED",
FAILURE_CONDITION: "FAILURE_CONDITION_MET",
}
// pass through the list from the auth/core lib // pass through the list from the auth/core lib
exports.ObjectStoreBuckets = ObjectStoreBuckets exports.ObjectStoreBuckets = ObjectStoreBuckets

View File

@ -8,7 +8,7 @@ const { DocumentTypes } = require("../db/utils")
const { doInTenant } = require("@budibase/backend-core/tenancy") const { doInTenant } = require("@budibase/backend-core/tenancy")
const { definitions: triggerDefs } = require("../automations/triggerInfo") const { definitions: triggerDefs } = require("../automations/triggerInfo")
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
const { AutomationErrors } = require("../constants")
const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId
const LOOP_STEP_ID = actions.ACTION_DEFINITIONS.LOOP.stepId const LOOP_STEP_ID = actions.ACTION_DEFINITIONS.LOOP.stepId
@ -146,7 +146,7 @@ class Orchestrator {
typeof newInput.binding !== "string") typeof newInput.binding !== "string")
) { ) {
this.updateContextAndOutput(loopStepNumber, step, tempOutput, { this.updateContextAndOutput(loopStepNumber, step, tempOutput, {
status: "INCORRECT_TYPE", status: AutomationErrors.INCORRECT_TYPE,
success: false, success: false,
}) })
loopSteps = null loopSteps = null
@ -156,18 +156,26 @@ class Orchestrator {
// The "Loop" binding in the front end is "fake", so replace it here so the context can understand it // The "Loop" binding in the front end is "fake", so replace it here so the context can understand it
// Pretty hacky because we need to account for the row object // Pretty hacky because we need to account for the row object
for (let key in originalStepInput) { for (let [key, value] of Object.entries(originalStepInput)) {
if (key === "row") { if (typeof value === "object") {
for (let val in originalStepInput["row"]) { for (let [innerKey, innerValue] of Object.entries(
originalStepInput["row"][val] = originalStepInput["row"][ originalStepInput[key]
val )) {
].replace(/loop/, `steps.${loopStepNumber}`) if (typeof innerValue === "string") {
originalStepInput[key][innerKey] =
automationUtils.substituteLoopStep(
innerValue,
`steps.${loopStepNumber}`
)
}
} }
} else { } else {
originalStepInput[key] = originalStepInput[key].replace( if (typeof value === "string") {
/loop/, originalStepInput[key] = automationUtils.substituteLoopStep(
`steps.${loopStepNumber}` value,
) `steps.${loopStepNumber}`
)
}
} }
} }
@ -176,7 +184,7 @@ class Orchestrator {
index === loopStep.inputs.iterations index === loopStep.inputs.iterations
) { ) {
this.updateContextAndOutput(loopStepNumber, step, tempOutput, { this.updateContextAndOutput(loopStepNumber, step, tempOutput, {
status: "MAX_ITERATIONS_REACHED", status: AutomationErrors.MAX_ITERATIONS,
success: true, success: true,
}) })
loopSteps = null loopSteps = null
@ -189,7 +197,7 @@ class Orchestrator {
loopStep.inputs.failure loopStep.inputs.failure
) { ) {
this.updateContextAndOutput(loopStepNumber, step, tempOutput, { this.updateContextAndOutput(loopStepNumber, step, tempOutput, {
status: "FAILURE_CONDITION_MET", status: AutomationErrors.FAILURE_CONDITION,
success: false, success: false,
}) })
loopSteps = null loopSteps = null