From 49676f2cae769098e83976c0e047a5118ca7e8b9 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Sat, 30 Dec 2023 18:51:08 +0000 Subject: [PATCH 01/36] recomitting trigger another automation work --- .../FlowChart/ActionModal.svelte | 1 - packages/server/src/automations/actions.ts | 4 + .../server/src/automations/steps/trigger.ts | 75 +++++++++++++++++++ .../types/src/documents/app/automation.ts | 1 + 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 packages/server/src/automations/steps/trigger.ts diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte index 15dd864168..a0da8e455a 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte @@ -23,7 +23,6 @@ let selectedAction let actionVal let actions = Object.entries($automationStore.blockDefinitions.ACTION) - $: collectBlockExists = checkForCollectStep($selectedAutomation) const disabled = () => { diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index 81cf4d8176..7025a2f64c 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -15,6 +15,7 @@ import * as delay from "./steps/delay" import * as queryRow from "./steps/queryRows" import * as loop from "./steps/loop" import * as collect from "./steps/collect" +import * as trigger from "./steps/trigger" import env from "../environment" import { AutomationStepSchema, @@ -41,6 +42,7 @@ const ACTION_IMPLS: Record< FILTER: filter.run, QUERY_ROWS: queryRow.run, COLLECT: collect.run, + TRIGGER_AUTOMATION: trigger.run, // these used to be lowercase step IDs, maintain for backwards compat discord: discord.run, slack: slack.run, @@ -62,6 +64,7 @@ export const BUILTIN_ACTION_DEFINITIONS: Record = QUERY_ROWS: queryRow.definition, LOOP: loop.definition, COLLECT: collect.definition, + TRIGGER: trigger.definition, // these used to be lowercase step IDs, maintain for backwards compat discord: discord.definition, slack: slack.definition, @@ -102,6 +105,7 @@ export async function getActionDefinitions() { /* istanbul ignore next */ export async function getAction(stepId: string) { + console.log(stepId) if (ACTION_IMPLS[stepId] != null) { return ACTION_IMPLS[stepId] } diff --git a/packages/server/src/automations/steps/trigger.ts b/packages/server/src/automations/steps/trigger.ts new file mode 100644 index 0000000000..7624bef817 --- /dev/null +++ b/packages/server/src/automations/steps/trigger.ts @@ -0,0 +1,75 @@ +import { + AutomationActionStepId, + AutomationStepSchema, + AutomationStepInput, + AutomationStepType, + AutomationIOType, + AutomationFeature, + AutomationResults, + Automation, +} from "@budibase/types" +import * as triggers from "../triggers" +import { db as dbCore, context } from "@budibase/backend-core" + +export const definition: AutomationStepSchema = { + name: "Trigger Automation", + tagline: "Triggers an automation synchronously", + icon: "Sync", + description: "Triggers an automation synchronously", + type: AutomationStepType.ACTION, + internal: true, + features: {}, + stepId: AutomationActionStepId.TRIGGER, + inputs: {}, + schema: { + inputs: { + properties: { + automationId: { + type: AutomationIOType.STRING, + title: "Automation ID to trigger", + }, + }, + required: ["automationId"], + }, + outputs: { + properties: { + success: { + type: AutomationIOType.BOOLEAN, + description: "Whether the automation was successful", + }, + value: { + type: AutomationIOType.OBJECT, + description: "Automation Result", + }, + }, + required: ["success", "value"], + }, + }, +} + +export async function run({ inputs }: AutomationStepInput) { + console.log("??: " + inputs.automationId) + console.log("???DSAASDFAFSDFDSFDS") + if (!inputs.automationId) { + return { + success: false, + } + } else { + const db = context.getAppDB() + let automation = await db.get(inputs.automationId) + + const response: AutomationResults = await triggers.externalTrigger( + automation, + { + fields: {}, + timeout: 120000, + }, + { getResponses: true } + ) + + return { + success: true, + value: response, + } + } +} diff --git a/packages/types/src/documents/app/automation.ts b/packages/types/src/documents/app/automation.ts index 88ce5e9b9a..bbaa74bb14 100644 --- a/packages/types/src/documents/app/automation.ts +++ b/packages/types/src/documents/app/automation.ts @@ -61,6 +61,7 @@ export enum AutomationActionStepId { LOOP = "LOOP", COLLECT = "COLLECT", OPENAI = "OPENAI", + TRIGGER = "TRIGGER", // these used to be lowercase step IDs, maintain for backwards compat discord = "discord", slack = "slack", From 734ad2c1ae7d9d7fa6f396dc7e9138c13fc45039 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 3 Jan 2024 11:59:15 +0000 Subject: [PATCH 02/36] further work for triggering automations from other automations --- .../builder/src/builderStore/store/automation/index.js | 1 + .../AutomationBuilder/FlowChart/ActionModal.svelte | 10 +++++++++- .../AutomationBuilder/FlowChart/TestDataModal.svelte | 2 ++ packages/builder/src/constants/backend/automations.js | 1 + packages/builder/src/stores/portal/licensing.js | 5 +++++ packages/pro | 2 +- packages/server/src/automations/actions.ts | 2 +- packages/server/src/automations/steps/trigger.ts | 10 ++++++---- packages/types/src/sdk/licensing/feature.ts | 1 + 9 files changed, 27 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index af83f73dc6..aecdff0246 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -155,6 +155,7 @@ const automationActions = store => ({ await store.actions.save(newAutomation) }, test: async (automation, testData) => { + console.log(testData) const result = await API.testAutomation({ automationId: automation?._id, testData, diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte index a0da8e455a..6c84875996 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte @@ -19,6 +19,7 @@ export let lastStep let syncAutomationsEnabled = $licensing.syncAutomationsEnabled + let triggerAutomationsEnabled = $licensing.triggerAutomationsEnabled let collectBlockAllowedSteps = [TriggerStepID.APP, TriggerStepID.WEBHOOK] let selectedAction let actionVal @@ -35,6 +36,10 @@ disabled: !lastStep || !syncAutomationsEnabled || collectBlockExists, message: collectDisabledMessage(), }, + TRIGGER: { + disabled: !triggerAutomationsEnabled, + message: collectDisabledMessage(), + }, } } @@ -98,6 +103,9 @@ notifications.error("Error saving automation") } } + + let lockedFeatures = [ActionStepID.COLLECT, ActionStepID.TRIGGER] + $: console.log {action.name} - {#if isDisabled && !syncAutomationsEnabled && action.stepId === ActionStepID.COLLECT} + {#if isDisabled && !syncAutomationsEnabled && !triggerAutomationsEnabled && lockedFeatures.includes(action.stepId)}
Business diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte index 76def72bf6..70162a9368 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte @@ -46,6 +46,8 @@ } const testAutomation = async () => { + console.log(testData) + console.log($selectedAutomation) try { await automationStore.actions.test($selectedAutomation, testData) $automationStore.showTestPanel = true diff --git a/packages/builder/src/constants/backend/automations.js b/packages/builder/src/constants/backend/automations.js index f89a126d3c..f26e2a7424 100644 --- a/packages/builder/src/constants/backend/automations.js +++ b/packages/builder/src/constants/backend/automations.js @@ -21,6 +21,7 @@ export const ActionStepID = { QUERY_ROWS: "QUERY_ROWS", LOOP: "LOOP", COLLECT: "COLLECT", + TRIGGER: "TRIGGER", // these used to be lowercase step IDs, maintain for backwards compat discord: "discord", slack: "slack", diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js index 3197822e53..daf4b0ce86 100644 --- a/packages/builder/src/stores/portal/licensing.js +++ b/packages/builder/src/stores/portal/licensing.js @@ -125,6 +125,10 @@ export const createLicensingStore = () => { const syncAutomationsEnabled = license.features.includes( Constants.Features.SYNC_AUTOMATIONS ) + const triggerAutomationsEnabled = license.features.includes( + Constants.Features.SYNC_AUTOMATIONS + ) + const perAppBuildersEnabled = license.features.includes( Constants.Features.APP_BUILDERS ) @@ -147,6 +151,7 @@ export const createLicensingStore = () => { auditLogsEnabled, enforceableSSO, syncAutomationsEnabled, + triggerAutomationsEnabled, isViewPermissionsEnabled, perAppBuildersEnabled, } diff --git a/packages/pro b/packages/pro index 992486c100..82de3443fd 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 992486c10044a7495496b97bdf5f454d4020bfba +Subproject commit 82de3443fd03b272555d23c42ead3a611302277d diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index 7025a2f64c..2fb08f754f 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -42,7 +42,7 @@ const ACTION_IMPLS: Record< FILTER: filter.run, QUERY_ROWS: queryRow.run, COLLECT: collect.run, - TRIGGER_AUTOMATION: trigger.run, + TRIGGER: trigger.run, // these used to be lowercase step IDs, maintain for backwards compat discord: discord.run, slack: slack.run, diff --git a/packages/server/src/automations/steps/trigger.ts b/packages/server/src/automations/steps/trigger.ts index 7624bef817..f85c24e963 100644 --- a/packages/server/src/automations/steps/trigger.ts +++ b/packages/server/src/automations/steps/trigger.ts @@ -26,7 +26,11 @@ export const definition: AutomationStepSchema = { properties: { automationId: { type: AutomationIOType.STRING, - title: "Automation ID to trigger", + title: "Automation ID", + }, + timeout: { + type: AutomationIOType.NUMBER, + title: "Timeout (ms)", }, }, required: ["automationId"], @@ -48,8 +52,6 @@ export const definition: AutomationStepSchema = { } export async function run({ inputs }: AutomationStepInput) { - console.log("??: " + inputs.automationId) - console.log("???DSAASDFAFSDFDSFDS") if (!inputs.automationId) { return { success: false, @@ -62,7 +64,7 @@ export async function run({ inputs }: AutomationStepInput) { automation, { fields: {}, - timeout: 120000, + timeout: inputs.timeout * 1000 || 120000, }, { getResponses: true } ) diff --git a/packages/types/src/sdk/licensing/feature.ts b/packages/types/src/sdk/licensing/feature.ts index 732a4a6c77..65d852e627 100644 --- a/packages/types/src/sdk/licensing/feature.ts +++ b/packages/types/src/sdk/licensing/feature.ts @@ -9,6 +9,7 @@ export enum Feature { BRANDING = "branding", SCIM = "scim", SYNC_AUTOMATIONS = "syncAutomations", + TRIGGER_AUTOMATION = "triggerAutomation", APP_BUILDERS = "appBuilders", OFFLINE = "offline", EXPANDED_PUBLIC_API = "expandedPublicApi", From 6507b6ec54af391147cd457b256be3819b4992a1 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 3 Jan 2024 12:01:13 +0000 Subject: [PATCH 03/36] remove logging --- .../automation/AutomationBuilder/FlowChart/TestDataModal.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte index 70162a9368..76def72bf6 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte @@ -46,8 +46,6 @@ } const testAutomation = async () => { - console.log(testData) - console.log($selectedAutomation) try { await automationStore.actions.test($selectedAutomation, testData) $automationStore.showTestPanel = true From 1437ce2e666301e2ad636799e3aa9b1a362ee65e Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 3 Jan 2024 15:28:07 +0000 Subject: [PATCH 04/36] some small ux updates --- .../AutomationBuilder/FlowChart/ActionModal.svelte | 7 +++---- packages/server/src/automations/steps/trigger.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte index 6c84875996..c335329844 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte @@ -19,11 +19,13 @@ export let lastStep let syncAutomationsEnabled = $licensing.syncAutomationsEnabled - let triggerAutomationsEnabled = $licensing.triggerAutomationsEnabled + let triggerAutomationsEnabled = true let collectBlockAllowedSteps = [TriggerStepID.APP, TriggerStepID.WEBHOOK] let selectedAction let actionVal let actions = Object.entries($automationStore.blockDefinitions.ACTION) + let lockedFeatures = [ActionStepID.COLLECT, ActionStepID.TRIGGER] + $: collectBlockExists = checkForCollectStep($selectedAutomation) const disabled = () => { @@ -103,9 +105,6 @@ notifications.error("Error saving automation") } } - - let lockedFeatures = [ActionStepID.COLLECT, ActionStepID.TRIGGER] - $: console.log Date: Thu, 4 Jan 2024 14:30:18 +0000 Subject: [PATCH 05/36] recommit work for trigger binding suggestions --- .../SetupPanel/AutomationBlockSetup.svelte | 173 ++++++++++-------- 1 file changed, 99 insertions(+), 74 deletions(-) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 158ecd8281..9a16b23fa2 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -51,7 +51,7 @@ export let testData export let schemaProperties export let isTestModal = false - + $: console.log(inputData) let webhookModal let drawer let fillWidth = true @@ -101,7 +101,6 @@ } } } - const onChange = Utils.sequential(async (e, key) => { // We need to cache the schema as part of the definition because it is // used in the server to detect relationships. It would be far better to @@ -145,34 +144,89 @@ if (!block || !automation) { return [] } - // Find previous steps to the selected one - let allSteps = [...automation.steps] - if (automation.trigger) { - allSteps = [automation.trigger, ...allSteps] - } + let allSteps = automation.trigger + ? [automation.trigger, ...automation.steps] + : [...automation.steps] let blockIdx = allSteps.findIndex(step => step.id === block.id) - - // Extract all outputs from all previous steps as available bindingsx§x let bindings = [] let loopBlockCount = 0 + + const addBinding = (name, value, icon, idx, isLoopBlock, bindingName) => { + const runtimeBinding = determineRuntimeBinding(name, idx, isLoopBlock) + const categoryName = determineCategoryName(idx, isLoopBlock, bindingName) + + bindings.push( + createBindingObject( + name, + value, + icon, + idx, + loopBlockCount, + isLoopBlock, + runtimeBinding, + categoryName, + bindingName + ) + ) + } + + const determineRuntimeBinding = (name, idx, isLoopBlock) => { + if (idx === 0 && automation.trigger?.event === "app:trigger") { + return `trigger.fields.${name}` + } + return isLoopBlock + ? `loop.${name}` + : `steps.${idx - loopBlockCount}.${name}` + } + + const determineCategoryName = (idx, isLoopBlock, bindingName) => { + if (idx === 0) return "Trigger outputs" + if (isLoopBlock) return "Loop Outputs" + return bindingName + ? `${bindingName} outputs` + : `Step ${idx - loopBlockCount} outputs` + } + + const createBindingObject = ( + name, + value, + icon, + idx, + loopBlockCount, + isLoopBlock, + runtimeBinding, + categoryName, + bindingName + ) => { + return { + readableBinding: bindingName + ? `${bindingName}.${name}` + : runtimeBinding, + runtimeBinding, + type: value.type, + description: value.description, + icon, + category: categoryName, + display: { + type: value.type, + name, + rank: isLoopBlock ? idx + 1 : idx - loopBlockCount, + }, + } + } + for (let idx = 0; idx < blockIdx; idx++) { let wasLoopBlock = allSteps[idx - 1]?.stepId === ActionStepID.LOOP let isLoopBlock = allSteps[idx]?.stepId === ActionStepID.LOOP && - allSteps.find(x => x.blockToLoop === block.id) - - // If the previous block was a loop block, decrement the index so the following - // steps are in the correct order - if (wasLoopBlock) { - loopBlockCount++ - continue - } - + allSteps.some(x => x.blockToLoop === block.id) let schema = allSteps[idx]?.schema?.outputs?.properties ?? {} + let bindingName = + automation.stepNames?.[allSteps[idx - loopBlockCount].id] - // If its a Loop Block, we need to add this custom schema if (isLoopBlock) { + // Reset schema to only include 'currentItem' for loop blocks schema = { currentItem: { type: "string", @@ -180,75 +234,46 @@ }, } } - const outputs = Object.entries(schema) - let bindingIcon = "" - let bindingRank = 0 - if (idx === 0) { - bindingIcon = automation.trigger.icon - } else if (isLoopBlock) { - bindingIcon = "Reuse" - bindingRank = idx + 1 - } else { - bindingIcon = allSteps[idx].icon - bindingRank = idx - loopBlockCount + + if (idx === 0 && automation.trigger?.event === "app:trigger") { + schema = Object.fromEntries( + Object.keys(automation.trigger.inputs.fields).map(key => [ + key, + { type: automation.trigger.inputs.fields[key] }, + ]) + ) } - let bindingName = - automation.stepNames?.[allSteps[idx - loopBlockCount].id] - bindings = bindings.concat( - outputs.map(([name, value]) => { - let runtimeName = isLoopBlock - ? `loop.${name}` - : block.name.startsWith("JS") - ? `steps[${idx - loopBlockCount}].${name}` - : `steps.${idx - loopBlockCount}.${name}` - const runtime = idx === 0 ? `trigger.${name}` : runtimeName - let categoryName - if (idx === 0) { - categoryName = "Trigger outputs" - } else if (isLoopBlock) { - categoryName = "Loop Outputs" - } else if (bindingName) { - categoryName = `${bindingName} outputs` - } else { - categoryName = `Step ${idx - loopBlockCount} outputs` - } + let icon = + idx === 0 + ? automation.trigger.icon + : isLoopBlock + ? "Reuse" + : allSteps[idx].icon - return { - readableBinding: bindingName ? `${bindingName}.${name}` : runtime, - runtimeBinding: runtime, - type: value.type, - description: value.description, - icon: bindingIcon, - category: categoryName, - display: { - type: value.type, - name: name, - rank: bindingRank, - }, - } - }) + // Continue if the previous block was a loop block to skip bindings from the block that the loop is attached to + if (wasLoopBlock) { + loopBlockCount++ + continue + } + + Object.entries(schema).forEach(([name, value]) => + addBinding(name, value, icon, idx, isLoopBlock, bindingName) ) } // Environment bindings if ($licensing.environmentVariablesEnabled) { bindings = bindings.concat( - getEnvironmentBindings().map(binding => { - return { - ...binding, - display: { - ...binding.display, - rank: 98, - }, - } - }) + getEnvironmentBindings().map(binding => ({ + ...binding, + display: { ...binding.display, rank: 98 }, + })) ) } return bindings } - function lookForFilters(properties) { if (!properties) { return [] From e99a7672a774f96e7f5a6d32cd56c0da714ffb62 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 5 Jan 2024 16:12:31 +0000 Subject: [PATCH 06/36] test and pr comments --- .../builderStore/store/automation/index.js | 1 - .../FlowChart/ActionModal.svelte | 2 +- packages/server/src/automations/actions.ts | 1 - .../src/automations/tests/trigger.spec.ts | 33 +++++++++++++++ .../server/src/tests/utilities/structures.ts | 40 ++++++++++++++++++- 5 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 packages/server/src/automations/tests/trigger.spec.ts diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index aecdff0246..af83f73dc6 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -155,7 +155,6 @@ const automationActions = store => ({ await store.actions.save(newAutomation) }, test: async (automation, testData) => { - console.log(testData) const result = await API.testAutomation({ automationId: automation?._id, testData, diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte index c335329844..0c97853dd6 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte @@ -19,7 +19,7 @@ export let lastStep let syncAutomationsEnabled = $licensing.syncAutomationsEnabled - let triggerAutomationsEnabled = true + let triggerAutomationsEnabled = $licensing.triggerAutomationsEnabled let collectBlockAllowedSteps = [TriggerStepID.APP, TriggerStepID.WEBHOOK] let selectedAction let actionVal diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index 2fb08f754f..a3997ad21c 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -105,7 +105,6 @@ export async function getActionDefinitions() { /* istanbul ignore next */ export async function getAction(stepId: string) { - console.log(stepId) if (ACTION_IMPLS[stepId] != null) { return ACTION_IMPLS[stepId] } diff --git a/packages/server/src/automations/tests/trigger.spec.ts b/packages/server/src/automations/tests/trigger.spec.ts new file mode 100644 index 0000000000..e8a2cc9345 --- /dev/null +++ b/packages/server/src/automations/tests/trigger.spec.ts @@ -0,0 +1,33 @@ +jest.spyOn(global.console, "error") + +import * as setup from "./utilities" +import * as automation from "../index" + +describe("Test triggering an automation from another automation", () => { + let config = setup.getConfig() + + beforeAll(async () => { + await automation.init() + await config.init() + }) + + afterAll(async () => { + await automation.shutdown() + setup.afterAll() + }) + + it("should trigger an other server log automation", async () => { + let newAutomation = await config.createAutomation() + + const inputs: any = { automationId: newAutomation._id, timeout: 12000 } + const res = await setup.runStep(setup.actions.TRIGGER.stepId, inputs) + // Check if the SERVER_LOG step was successful + expect(res.value[1].outputs.success).toBe(true) + }) + + it("should fail gracefully if the automation id is incorrect", async () => { + const inputs: any = { automationId: null, timeout: 12000 } + const res = await setup.runStep(setup.actions.TRIGGER.stepId, inputs) + expect(res.success).toBe(false) + }) +}) diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index 83be8b6d58..ce08011e76 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -146,7 +146,45 @@ export function basicAutomation(appId?: string): Automation { }, }, }, - steps: [], + steps: [ + { + stepId: AutomationActionStepId.SERVER_LOG, + name: "Backend log", + tagline: "Console log a value in the backend", + icon: "Monitoring", + description: "Logs the given text to the server (using console.log)", + internal: true, + features: { + LOOPING: true, + }, + inputs: { + text: "sdfsdf", + }, + schema: { + inputs: { + properties: { + text: { + type: "string", + title: "Text to log", + }, + }, + required: ["text"], + }, + outputs: { + properties: { + success: { + description: "Whether the action was successful", + }, + message: { + description: "What was output", + }, + }, + required: ["success", "message"], + }, + }, + id: "y8lkZbeSe", + }, + ], }, type: "automation", appId: appId!, From 186fd844843c21ef3d7d016c5856b1f59928699e Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 8 Jan 2024 09:31:41 +0000 Subject: [PATCH 07/36] remove log --- .../automation/SetupPanel/AutomationBlockSetup.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 9a16b23fa2..10ddd29c63 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -51,7 +51,7 @@ export let testData export let schemaProperties export let isTestModal = false - $: console.log(inputData) + let webhookModal let drawer let fillWidth = true From 93c5b3721bbc09a15727608901be2e545c997dae Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 9 Jan 2024 11:02:51 +0000 Subject: [PATCH 08/36] some tweaks to fix bindings for row created / updated events --- .../SetupPanel/AutomationBlockSetup.svelte | 70 ++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 10ddd29c63..ecc748599f 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -51,7 +51,6 @@ export let testData export let schemaProperties export let isTestModal = false - let webhookModal let drawer let fillWidth = true @@ -145,13 +144,17 @@ return [] } - let allSteps = automation.trigger - ? [automation.trigger, ...automation.steps] - : [...automation.steps] + // Find previous steps to the selected one + let allSteps = [...automation.steps] + + if (automation.trigger) { + allSteps = [automation.trigger, ...allSteps] + } let blockIdx = allSteps.findIndex(step => step.id === block.id) + + // Extract all outputs from all previous steps as available bindingsx§x let bindings = [] let loopBlockCount = 0 - const addBinding = (name, value, icon, idx, isLoopBlock, bindingName) => { const runtimeBinding = determineRuntimeBinding(name, idx, isLoopBlock) const categoryName = determineCategoryName(idx, isLoopBlock, bindingName) @@ -172,12 +175,28 @@ } const determineRuntimeBinding = (name, idx, isLoopBlock) => { + let runtimeName + + /* Begin special cases for generating custom schemas based on triggers */ if (idx === 0 && automation.trigger?.event === "app:trigger") { return `trigger.fields.${name}` } - return isLoopBlock - ? `loop.${name}` - : `steps.${idx - loopBlockCount}.${name}` + + if ( + (idx === 0 && automation.trigger?.event === "row:update") || + automation.trigger?.event === "row:save" + ) { + if (name !== "id" && name !== "revision") return `trigger.row.${name}` + } + /* end special cases */ + if (isLoopBlock) { + runtimeName = `loop.${name}` + } else if (block.name.startsWith("JS")) { + runtimeName = `steps[${idx - loopBlockCount}].${name}` + } else { + runtimeName = `steps.${idx - loopBlockCount}.${name}` + } + return idx === 0 ? `trigger.${name}` : runtimeName } const determineCategoryName = (idx, isLoopBlock, bindingName) => { @@ -221,12 +240,11 @@ let isLoopBlock = allSteps[idx]?.stepId === ActionStepID.LOOP && allSteps.some(x => x.blockToLoop === block.id) - let schema = allSteps[idx]?.schema?.outputs?.properties ?? {} + let schema = cloneDeep(allSteps[idx]?.schema?.outputs?.properties) ?? {} let bindingName = automation.stepNames?.[allSteps[idx - loopBlockCount].id] if (isLoopBlock) { - // Reset schema to only include 'currentItem' for loop blocks schema = { currentItem: { type: "string", @@ -243,7 +261,22 @@ ]) ) } - + if ( + (idx === 0 && automation.trigger.event === "row:update") || + (idx === 0 && automation.trigger.event === "row:save") + ) { + let table = $tables.list.find( + table => table._id === automation.trigger.inputs.tableId + ) + // We want to generate our own schema for the bindings from the table schema itself + for (const key in table?.schema) { + schema[key] = { + type: table.schema[key].type, + } + } + // remove the original binding + delete schema.row + } let icon = idx === 0 ? automation.trigger.icon @@ -251,7 +284,6 @@ ? "Reuse" : allSteps[idx].icon - // Continue if the previous block was a loop block to skip bindings from the block that the loop is attached to if (wasLoopBlock) { loopBlockCount++ continue @@ -265,13 +297,17 @@ // Environment bindings if ($licensing.environmentVariablesEnabled) { bindings = bindings.concat( - getEnvironmentBindings().map(binding => ({ - ...binding, - display: { ...binding.display, rank: 98 }, - })) + getEnvironmentBindings().map(binding => { + return { + ...binding, + display: { + ...binding.display, + rank: 98, + }, + } + }) ) } - return bindings } function lookForFilters(properties) { From ce81df4d1ea268d7ff8fcbfa512aa2b87295ac12 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 9 Jan 2024 15:05:24 +0000 Subject: [PATCH 09/36] recommit json display work --- packages/builder/package.json | 1 + .../AutomationBuilder/TestDisplay.svelte | 67 +++++++--- .../AutomationPanel/AutomationPanel.svelte | 114 ++++++++++++++---- 3 files changed, 138 insertions(+), 44 deletions(-) diff --git a/packages/builder/package.json b/packages/builder/package.json index 9472c51965..273994ed0e 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -66,6 +66,7 @@ "@fortawesome/free-solid-svg-icons": "^6.4.2", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", + "@zerodevx/svelte-json-view": "^1.0.7", "codemirror": "^5.59.0", "dayjs": "^1.10.8", "downloadjs": "1.4.7", diff --git a/packages/builder/src/components/automation/AutomationBuilder/TestDisplay.svelte b/packages/builder/src/components/automation/AutomationBuilder/TestDisplay.svelte index 89406f15d8..9fbc4b6bc1 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/TestDisplay.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/TestDisplay.svelte @@ -1,7 +1,8 @@ - - -
-
Automations
-
- -
-
-
- -
+ From 8d4010cc54927332db1cbb4c754ec8af67dceaa3 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 9 Jan 2024 20:32:12 +0000 Subject: [PATCH 10/36] set condition outputs --- packages/server/src/automations/steps/filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/automations/steps/filter.ts b/packages/server/src/automations/steps/filter.ts index 3b000f8f29..6867809500 100644 --- a/packages/server/src/automations/steps/filter.ts +++ b/packages/server/src/automations/steps/filter.ts @@ -99,7 +99,7 @@ export async function run({ inputs }: AutomationStepInput) { } else { result = false } - return { success: true, result } + return { success: true, result, refValue: field, comparisonValue: value } } catch (err) { return { success: false, result: false } } From 78ef231e03c1854a534144f8b77ead1a1fa33a50 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 10 Jan 2024 16:34:52 +0000 Subject: [PATCH 11/36] fix issue with being able to select any automation to trigger --- .../SetupPanel/AutomationBlockSetup.svelte | 10 ++- .../SetupPanel/AutomationSelector.svelte | 86 +++++++++++++++++++ .../server/src/automations/steps/trigger.ts | 23 +++-- .../types/src/documents/app/automation.ts | 2 + 4 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 packages/builder/src/components/automation/SetupPanel/AutomationSelector.svelte diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 158ecd8281..b9400c0d86 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -28,6 +28,7 @@ import CodeEditorModal from "./CodeEditorModal.svelte" import QuerySelector from "./QuerySelector.svelte" import QueryParamSelector from "./QueryParamSelector.svelte" + import AutomationSelector from "./AutomationSelector.svelte" import CronBuilder from "./CronBuilder.svelte" import Editor from "components/integration/QueryEditor.svelte" import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte" @@ -286,7 +287,8 @@ value.customType !== "code" && value.customType !== "queryParams" && value.customType !== "cron" && - value.customType !== "triggerSchema" + value.customType !== "triggerSchema" && + value.customType !== "automationFields" ) } @@ -421,6 +423,12 @@ on:change={e => onChange(e, key)} value={inputData[key]} /> + {:else if value.customType === "automationFields"} + onChange(e, key)} + value={inputData[key]} + {bindings} + /> {:else if value.customType === "queryParams"} onChange(e, key)} diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationSelector.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationSelector.svelte new file mode 100644 index 0000000000..ae45bfd8a1 --- /dev/null +++ b/packages/builder/src/components/automation/SetupPanel/AutomationSelector.svelte @@ -0,0 +1,86 @@ + + +
+ +
+