Merge branch 'master' into fix/feature-flag-checks

This commit is contained in:
Michael Drury 2024-08-15 17:11:38 +01:00 committed by GitHub
commit 483bb585c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 235 additions and 74 deletions

View File

@ -0,0 +1,51 @@
import {
AutomationActionStepId,
AutomationCustomIOType,
AutomationIOType,
AutomationStepDefinition,
AutomationStepType,
} from "@budibase/types"
export const definition: AutomationStepDefinition = {
name: "Branch",
icon: "Branch3",
tagline: "Branch from this step",
description: "Branching",
stepId: AutomationActionStepId.BRANCH,
internal: true,
features: {},
inputs: {},
schema: {
inputs: {
properties: {
branches: {
properties: {
name: {
type: AutomationIOType.STRING,
},
condition: {
customType: AutomationCustomIOType.FILTERS,
},
},
},
children: {
type: AutomationIOType.ARRAY,
},
},
required: ["conditions"],
},
outputs: {
properties: {
branchName: {
type: AutomationIOType.STRING,
},
result: {
type: AutomationIOType.BOOLEAN,
description: "Whether the condition was met",
},
},
required: ["output"],
},
},
type: AutomationStepType.LOGIC,
}

View File

@ -7,7 +7,7 @@ import {
ServerLogStepOutputs, ServerLogStepOutputs,
FieldType, FieldType,
} from "@budibase/types" } from "@budibase/types"
import { createAutomationBuilder } from "../utilities/AutomationBuilder" import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
import { DatabaseName } from "../../../integrations/tests/utils" import { DatabaseName } from "../../../integrations/tests/utils"
describe("Automation Scenarios", () => { describe("Automation Scenarios", () => {
@ -23,6 +23,43 @@ describe("Automation Scenarios", () => {
afterAll(setup.afterAll) afterAll(setup.afterAll)
// eslint-disable-next-line jest/no-commented-out-tests
// describe("Branching automations", () => {
// eslint-disable-next-line jest/no-commented-out-tests
// it("should run an automation with a trigger, loop, and create row step", async () => {
// const builder = createAutomationBuilder({
// name: "Test Trigger with Loop and Create Row",
// })
// builder
// .serverLog({ text: "Starting automation" })
// .branch({
// topLevelBranch1: {
// steps: stepBuilder =>
// stepBuilder.serverLog({ text: "Branch 1" }).branch({
// branch1: {
// steps: stepBuilder =>
// stepBuilder.serverLog({ text: "Branch 1.1" }),
// condition: { notEmpty: { column: 10 } },
// },
// branch2: {
// steps: stepBuilder =>
// stepBuilder.serverLog({ text: "Branch 1.2" }),
// condition: { fuzzy: { column: "sadsd" } },
// },
// }),
// condition: { equal: { column: 10 } },
// },
// topLevelBranch2: {
// steps: stepBuilder => stepBuilder.serverLog({ text: "Branch 2" }),
// condition: { equal: { column: 20 } },
// },
// })
// .run()
// })
// })
describe("Loop automations", () => { describe("Loop automations", () => {
it("should run an automation with a trigger, loop, and create row step", async () => { it("should run an automation with a trigger, loop, and create row step", async () => {
const builder = createAutomationBuilder({ const builder = createAutomationBuilder({

View File

@ -30,10 +30,13 @@ import {
AutomationStepInputs, AutomationStepInputs,
AutomationTriggerInputs, AutomationTriggerInputs,
ServerLogStepInputs, ServerLogStepInputs,
BranchStepInputs,
SearchFilters,
Branch,
} from "@budibase/types" } from "@budibase/types"
import {} from "../../steps/loop"
import TestConfiguration from "../../../tests/utilities/TestConfiguration" import TestConfiguration from "../../../tests/utilities/TestConfiguration"
import * as setup from "../utilities" import * as setup from "../utilities"
import { definition } from "../../../automations/steps/branch"
type TriggerOutputs = type TriggerOutputs =
| RowCreatedTriggerOutputs | RowCreatedTriggerOutputs
@ -43,69 +46,56 @@ type TriggerOutputs =
| CronTriggerOutputs | CronTriggerOutputs
| undefined | undefined
class AutomationBuilder { type StepBuilderFunction = (stepBuilder: StepBuilder) => void
private automationConfig: Automation = {
name: "",
definition: {
steps: [],
trigger: {} as AutomationTrigger,
},
type: "automation",
appId: setup.getConfig().getAppId(),
}
private config: TestConfiguration = setup.getConfig()
private triggerOutputs: TriggerOutputs
private triggerSet: boolean = false
constructor(options: { name?: string } = {}) { type BranchConfig = {
this.automationConfig.name = options.name || `Test Automation ${uuidv4()}` [key: string]: {
steps: StepBuilderFunction
condition: SearchFilters
}
}
class BaseStepBuilder {
protected steps: AutomationStep[] = []
protected step<TStep extends AutomationActionStepId>(
stepId: TStep,
stepSchema: Omit<AutomationStep, "id" | "stepId" | "inputs">,
inputs: AutomationStepInputs<TStep>
): this {
this.steps.push({
...stepSchema,
inputs: inputs as any,
id: uuidv4(),
stepId,
})
return this
} }
// TRIGGERS protected addBranchStep(branchConfig: BranchConfig): void {
rowSaved(inputs: RowCreatedTriggerInputs, outputs: RowCreatedTriggerOutputs) { const branchStepInputs: BranchStepInputs = {
this.triggerOutputs = outputs branches: [] as Branch[],
return this.trigger( children: {},
TRIGGER_DEFINITIONS.ROW_SAVED,
AutomationTriggerStepId.ROW_SAVED,
inputs,
outputs
)
} }
rowUpdated( Object.entries(branchConfig).forEach(([key, branch]) => {
inputs: RowUpdatedTriggerInputs, const stepBuilder = new StepBuilder()
outputs: RowUpdatedTriggerOutputs branch.steps(stepBuilder)
) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_UPDATED,
AutomationTriggerStepId.ROW_UPDATED,
inputs,
outputs
)
}
rowDeleted( branchStepInputs.branches.push({
inputs: RowDeletedTriggerInputs, name: key,
outputs: RowDeletedTriggerOutputs condition: branch.condition,
) { })
this.triggerOutputs = outputs branchStepInputs.children![key] = stepBuilder.build()
return this.trigger( })
TRIGGER_DEFINITIONS.ROW_DELETED,
AutomationTriggerStepId.ROW_DELETED,
inputs,
outputs
)
}
appAction(outputs: AppActionTriggerOutputs, inputs?: AppActionTriggerInputs) { const branchStep: AutomationStep = {
this.triggerOutputs = outputs ...definition,
return this.trigger( id: uuidv4(),
TRIGGER_DEFINITIONS.APP, stepId: AutomationActionStepId.BRANCH,
AutomationTriggerStepId.APP, inputs: branchStepInputs,
inputs, }
outputs this.steps.push(branchStep)
)
} }
// STEPS // STEPS
@ -171,6 +161,84 @@ class AutomationBuilder {
input input
) )
} }
}
class StepBuilder extends BaseStepBuilder {
build(): AutomationStep[] {
return this.steps
}
branch(branchConfig: BranchConfig): this {
this.addBranchStep(branchConfig)
return this
}
}
class AutomationBuilder extends BaseStepBuilder {
private automationConfig: Automation
private config: TestConfiguration
private triggerOutputs: any
private triggerSet: boolean = false
constructor(options: { name?: string } = {}) {
super()
this.automationConfig = {
name: options.name || `Test Automation ${uuidv4()}`,
definition: {
steps: [],
trigger: {} as AutomationTrigger,
},
type: "automation",
appId: setup.getConfig().getAppId(),
}
this.config = setup.getConfig()
}
// TRIGGERS
rowSaved(inputs: RowCreatedTriggerInputs, outputs: RowCreatedTriggerOutputs) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_SAVED,
AutomationTriggerStepId.ROW_SAVED,
inputs,
outputs
)
}
rowUpdated(
inputs: RowUpdatedTriggerInputs,
outputs: RowUpdatedTriggerOutputs
) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_UPDATED,
AutomationTriggerStepId.ROW_UPDATED,
inputs,
outputs
)
}
rowDeleted(
inputs: RowDeletedTriggerInputs,
outputs: RowDeletedTriggerOutputs
) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_DELETED,
AutomationTriggerStepId.ROW_DELETED,
inputs,
outputs
)
}
appAction(outputs: AppActionTriggerOutputs, inputs?: AppActionTriggerInputs) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.APP,
AutomationTriggerStepId.APP,
inputs,
outputs
)
}
private trigger<TStep extends AutomationTriggerStepId>( private trigger<TStep extends AutomationTriggerStepId>(
triggerSchema: AutomationTriggerDefinition, triggerSchema: AutomationTriggerDefinition,
@ -181,7 +249,6 @@ class AutomationBuilder {
if (this.triggerSet) { if (this.triggerSet) {
throw new Error("Only one trigger can be set for an automation.") throw new Error("Only one trigger can be set for an automation.")
} }
this.automationConfig.definition.trigger = { this.automationConfig.definition.trigger = {
...triggerSchema, ...triggerSchema,
stepId, stepId,
@ -194,21 +261,20 @@ class AutomationBuilder {
return this return this
} }
private step<TStep extends AutomationActionStepId>( branch(branchConfig: BranchConfig): {
stepId: TStep, run: () => Promise<AutomationResults>
stepSchema: Omit<AutomationStep, "id" | "stepId" | "inputs">, } {
inputs: AutomationStepInputs<TStep> this.addBranchStep(branchConfig)
): this { return {
this.automationConfig.definition.steps.push({ run: () => this.run(),
...stepSchema, }
inputs: inputs as any,
id: uuidv4(),
stepId,
})
return this
} }
async run() { async run() {
if (!Object.keys(this.automationConfig.definition.trigger).length) {
throw new Error("Please add a trigger to this automation test")
}
this.automationConfig.definition.steps = this.steps
const automation = await this.config.createAutomation(this.automationConfig) const automation = await this.config.createAutomation(this.automationConfig)
const results = await testAutomation( const results = await testAutomation(
this.config, this.config,
@ -218,7 +284,9 @@ class AutomationBuilder {
return this.processResults(results) return this.processResults(results)
} }
private processResults(results: { body: AutomationResults }) { private processResults(results: {
body: AutomationResults
}): AutomationResults {
results.body.steps.shift() results.body.steps.shift()
return { return {
trigger: results.body.trigger, trigger: results.body.trigger,

View File

@ -111,10 +111,15 @@ export type LoopStepOutputs = {
} }
export type BranchStepInputs = { export type BranchStepInputs = {
conditions: SearchFilters branches: Branch[]
children?: Record<string, AutomationStep[]> children?: Record<string, AutomationStep[]>
} }
export type Branch = {
name: string
condition: SearchFilters
}
export type MakeIntegrationInputs = { export type MakeIntegrationInputs = {
url: string url: string
body: any body: any