diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index d9d48ede38..1ade332f0a 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -553,7 +553,10 @@ describe("/automations", () => { it.each(testCases)( "$description", async ({ filters, row, oldRow, expectToRun }) => { - let automation = await updateRowAutomationWithFilters(config.getAppId()) + let automation = await updateRowAutomationWithFilters( + config.getAppId(), + table._id! + ) automation.definition.trigger.inputs = { tableId: table._id, filters, diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index cff269cd80..2058723faa 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -19,13 +19,12 @@ import * as collect from "./steps/collect" import * as triggerAutomationRun from "./steps/triggerAutomationRun" import env from "../environment" import { - AutomationStepSchema, PluginType, - AutomationStep, AutomationActionStepId, ActionImplementations, Hosting, ActionImplementation, + AutomationStepDefinition, } from "@budibase/types" import sdk from "../sdk" import { getAutomationPlugin } from "../utilities/fileSystem" @@ -56,29 +55,31 @@ const ACTION_IMPLS: ActionImplType = { n8n: n8n.run, } -export const BUILTIN_ACTION_DEFINITIONS: Record = - { - SEND_EMAIL_SMTP: sendSmtpEmail.definition, - CREATE_ROW: createRow.definition, - UPDATE_ROW: updateRow.definition, - DELETE_ROW: deleteRow.definition, - OUTGOING_WEBHOOK: outgoingWebhook.definition, - EXECUTE_SCRIPT: executeScript.definition, - EXECUTE_QUERY: executeQuery.definition, - SERVER_LOG: serverLog.definition, - DELAY: delay.definition, - FILTER: filter.definition, - QUERY_ROWS: queryRow.definition, - LOOP: loop.definition, - COLLECT: collect.definition, - TRIGGER_AUTOMATION_RUN: triggerAutomationRun.definition, - // these used to be lowercase step IDs, maintain for backwards compat - discord: discord.definition, - slack: slack.definition, - zapier: zapier.definition, - integromat: make.definition, - n8n: n8n.definition, - } +export const BUILTIN_ACTION_DEFINITIONS: Record< + string, + AutomationStepDefinition +> = { + SEND_EMAIL_SMTP: sendSmtpEmail.definition, + CREATE_ROW: createRow.definition, + UPDATE_ROW: updateRow.definition, + DELETE_ROW: deleteRow.definition, + OUTGOING_WEBHOOK: outgoingWebhook.definition, + EXECUTE_SCRIPT: executeScript.definition, + EXECUTE_QUERY: executeQuery.definition, + SERVER_LOG: serverLog.definition, + DELAY: delay.definition, + FILTER: filter.definition, + QUERY_ROWS: queryRow.definition, + LOOP: loop.definition, + COLLECT: collect.definition, + TRIGGER_AUTOMATION_RUN: triggerAutomationRun.definition, + // these used to be lowercase step IDs, maintain for backwards compat + discord: discord.definition, + slack: slack.definition, + zapier: zapier.definition, + integromat: make.definition, + n8n: n8n.definition, +} // don't add the bash script/definitions unless in self host // the fact this isn't included in any definitions means it cannot be @@ -101,7 +102,7 @@ export async function getActionDefinitions() { if (env.SELF_HOSTED) { const plugins = await sdk.plugins.fetch(PluginType.AUTOMATION) for (let plugin of plugins) { - const schema = plugin.schema.schema as AutomationStep + const schema = plugin.schema.schema as AutomationStepDefinition actionDefinitions[schema.stepId] = { ...schema, custom: true, diff --git a/packages/server/src/automations/automationUtils.ts b/packages/server/src/automations/automationUtils.ts index 6e42f8e4bc..bb94df9131 100644 --- a/packages/server/src/automations/automationUtils.ts +++ b/packages/server/src/automations/automationUtils.ts @@ -9,8 +9,8 @@ import { FieldType, Row, LoopStepType, + LoopStepInputs, } from "@budibase/types" -import { LoopInput } from "../definitions/automations" import { objectStore, context } from "@budibase/backend-core" import * as uuid from "uuid" import path from "path" @@ -31,7 +31,10 @@ import path from "path" * @returns The inputs object which has had all the various types supported by this function converted to their * primitive types. */ -export function cleanInputValues(inputs: Record, schema?: any) { +export function cleanInputValues>( + inputs: any, + schema?: any +): T { if (schema == null) { return inputs } @@ -61,16 +64,18 @@ export function cleanInputValues(inputs: Record, schema?: any) { } } //Check if input field for Update Row should be a relationship and cast to array - for (let key in inputs.row) { - if ( - inputs.schema?.[key]?.type === "link" && - inputs.row[key] && - typeof inputs.row[key] === "string" - ) { - try { - inputs.row[key] = JSON.parse(inputs.row[key]) - } catch (e) { - //Link is not an array or object, so continue + if (inputs?.row) { + for (let key in inputs.row) { + if ( + inputs.schema?.[key]?.type === "link" && + inputs.row[key] && + typeof inputs.row[key] === "string" + ) { + try { + inputs.row[key] = JSON.parse(inputs.row[key]) + } catch (e) { + //Link is not an array or object, so continue + } } } } @@ -267,7 +272,7 @@ export function stringSplit(value: string | string[]) { return value.split(",") } -export function typecastForLooping(input: LoopInput) { +export function typecastForLooping(input: LoopStepInputs) { if (!input || !input.binding) { return null } diff --git a/packages/server/src/automations/loopUtils.ts b/packages/server/src/automations/loopUtils.ts index 9a8d2443d7..2596fb796d 100644 --- a/packages/server/src/automations/loopUtils.ts +++ b/packages/server/src/automations/loopUtils.ts @@ -5,14 +5,15 @@ type ObjValue = { [key: string]: string | ObjValue } -export function replaceFakeBindings( - originalStepInput: Record, +export function replaceFakeBindings>( + originalStepInput: T, loopStepNumber: number -) { +): T { + const result: Record = {} for (const [key, value] of Object.entries(originalStepInput)) { - originalStepInput[key] = replaceBindingsRecursive(value, loopStepNumber) + result[key] = replaceBindingsRecursive(value, loopStepNumber) } - return originalStepInput + return result as T } function replaceBindingsRecursive( diff --git a/packages/server/src/automations/steps/bash.ts b/packages/server/src/automations/steps/bash.ts index d33bfb3d6c..636e659ffe 100644 --- a/packages/server/src/automations/steps/bash.ts +++ b/packages/server/src/automations/steps/bash.ts @@ -7,13 +7,13 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, BashStepInputs, BashStepOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Bash Scripting", tagline: "Execute a bash command", icon: "JourneyEvent", diff --git a/packages/server/src/automations/steps/collect.ts b/packages/server/src/automations/steps/collect.ts index 2451fd1cf6..3b2ca7d21f 100644 --- a/packages/server/src/automations/steps/collect.ts +++ b/packages/server/src/automations/steps/collect.ts @@ -1,13 +1,13 @@ import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, CollectStepInputs, CollectStepOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Collect Data", tagline: "Collect data to be sent to design", icon: "Collection", diff --git a/packages/server/src/automations/steps/createRow.ts b/packages/server/src/automations/steps/createRow.ts index 9908f138b8..4b9010dd01 100644 --- a/packages/server/src/automations/steps/createRow.ts +++ b/packages/server/src/automations/steps/createRow.ts @@ -10,14 +10,14 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, CreateRowStepInputs, CreateRowStepOutputs, } from "@budibase/types" import { EventEmitter } from "events" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Create Row", tagline: "Create a {{inputs.enriched.table.name}} row", icon: "TableRowAddBottom", diff --git a/packages/server/src/automations/steps/delay.ts b/packages/server/src/automations/steps/delay.ts index 5392f42b4b..c623693488 100644 --- a/packages/server/src/automations/steps/delay.ts +++ b/packages/server/src/automations/steps/delay.ts @@ -2,13 +2,13 @@ import { wait } from "../../utilities" import { AutomationActionStepId, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, DelayStepInputs, DelayStepOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Delay", icon: "Clock", tagline: "Delay for {{inputs.time}} milliseconds", diff --git a/packages/server/src/automations/steps/deleteRow.ts b/packages/server/src/automations/steps/deleteRow.ts index fa26dddb45..c4c42d8200 100644 --- a/packages/server/src/automations/steps/deleteRow.ts +++ b/packages/server/src/automations/steps/deleteRow.ts @@ -4,16 +4,16 @@ import { buildCtx } from "./utils" import { getError } from "../automationUtils" import { AutomationActionStepId, - AutomationStepSchema, AutomationStepType, AutomationIOType, AutomationCustomIOType, AutomationFeature, DeleteRowStepInputs, DeleteRowStepOutputs, + AutomationStepDefinition, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { description: "Delete a row from your database", icon: "TableRowRemoveCenter", name: "Delete Row", diff --git a/packages/server/src/automations/steps/discord.ts b/packages/server/src/automations/steps/discord.ts index 355f84b987..1ce21fc89e 100644 --- a/packages/server/src/automations/steps/discord.ts +++ b/packages/server/src/automations/steps/discord.ts @@ -2,18 +2,18 @@ import fetch from "node-fetch" import { getFetchResponse } from "./utils" import { AutomationActionStepId, - AutomationStepSchema, AutomationStepType, AutomationIOType, AutomationFeature, ExternalAppStepOutputs, DiscordStepInputs, + AutomationStepDefinition, } from "@budibase/types" const DEFAULT_USERNAME = "Budibase Automate" const DEFAULT_AVATAR_URL = "https://i.imgur.com/a1cmTKM.png" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Discord Message", tagline: "Send a message to a Discord server", description: "Send a message to a Discord server", diff --git a/packages/server/src/automations/steps/executeQuery.ts b/packages/server/src/automations/steps/executeQuery.ts index eb033b8883..a42182df37 100644 --- a/packages/server/src/automations/steps/executeQuery.ts +++ b/packages/server/src/automations/steps/executeQuery.ts @@ -7,13 +7,13 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, ExecuteQueryStepInputs, ExecuteQueryStepOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "External Data Connector", tagline: "Execute Data Connector", icon: "Data", diff --git a/packages/server/src/automations/steps/executeScript.ts b/packages/server/src/automations/steps/executeScript.ts index 3962da53ca..97145f3e14 100644 --- a/packages/server/src/automations/steps/executeScript.ts +++ b/packages/server/src/automations/steps/executeScript.ts @@ -6,14 +6,14 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, ExecuteScriptStepInputs, ExecuteScriptStepOutputs, } from "@budibase/types" import { EventEmitter } from "events" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "JS Scripting", tagline: "Execute JavaScript Code", icon: "Code", diff --git a/packages/server/src/automations/steps/filter.ts b/packages/server/src/automations/steps/filter.ts index 6d35a72698..84cea00b93 100644 --- a/packages/server/src/automations/steps/filter.ts +++ b/packages/server/src/automations/steps/filter.ts @@ -1,6 +1,6 @@ import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, FilterStepInputs, @@ -21,7 +21,7 @@ export const PrettyFilterConditions = { [FilterConditions.LESS_THAN]: "Less than", } -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Condition", tagline: "{{inputs.field}} {{inputs.condition}} {{inputs.value}}", icon: "Branch2", diff --git a/packages/server/src/automations/steps/loop.ts b/packages/server/src/automations/steps/loop.ts index cdf494c288..ba39b30975 100644 --- a/packages/server/src/automations/steps/loop.ts +++ b/packages/server/src/automations/steps/loop.ts @@ -2,11 +2,11 @@ import { AutomationActionStepId, AutomationCustomIOType, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Looping", icon: "Reuse", tagline: "Loop the block", diff --git a/packages/server/src/automations/steps/make.ts b/packages/server/src/automations/steps/make.ts index 45e31fbaa2..62cfd66302 100644 --- a/packages/server/src/automations/steps/make.ts +++ b/packages/server/src/automations/steps/make.ts @@ -2,7 +2,7 @@ import fetch from "node-fetch" import { getFetchResponse } from "./utils" import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationFeature, @@ -10,7 +10,7 @@ import { MakeIntegrationInputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Make Integration", stepTitle: "Make", tagline: "Trigger a Make scenario", diff --git a/packages/server/src/automations/steps/n8n.ts b/packages/server/src/automations/steps/n8n.ts index b2fbce6de7..8e55d2535b 100644 --- a/packages/server/src/automations/steps/n8n.ts +++ b/packages/server/src/automations/steps/n8n.ts @@ -2,7 +2,7 @@ import fetch, { HeadersInit } from "node-fetch" import { getFetchResponse } from "./utils" import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationFeature, @@ -11,7 +11,7 @@ import { n8nStepInputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "n8n Integration", stepTitle: "n8n", tagline: "Trigger an n8n workflow", diff --git a/packages/server/src/automations/steps/openai.ts b/packages/server/src/automations/steps/openai.ts index 279a0a9df0..1c148b2e73 100644 --- a/packages/server/src/automations/steps/openai.ts +++ b/packages/server/src/automations/steps/openai.ts @@ -2,7 +2,7 @@ import { OpenAI } from "openai" import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, OpenAIStepInputs, @@ -17,7 +17,7 @@ enum Model { GPT_4 = "gpt-4", } -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "OpenAI", tagline: "Send prompts to ChatGPT", icon: "Algorithm", diff --git a/packages/server/src/automations/steps/outgoingWebhook.ts b/packages/server/src/automations/steps/outgoingWebhook.ts index 04972fefae..70b8b1f476 100644 --- a/packages/server/src/automations/steps/outgoingWebhook.ts +++ b/packages/server/src/automations/steps/outgoingWebhook.ts @@ -6,7 +6,7 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, ExternalAppStepOutputs, OutgoingWebhookStepInputs, @@ -26,7 +26,7 @@ const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH] * NOTE: this functionality is deprecated - it no longer should be used. */ -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { deprecated: true, name: "Outgoing webhook", tagline: "Send a {{inputs.requestMethod}} request", diff --git a/packages/server/src/automations/steps/queryRows.ts b/packages/server/src/automations/steps/queryRows.ts index 526e994c1f..dc4dda4482 100644 --- a/packages/server/src/automations/steps/queryRows.ts +++ b/packages/server/src/automations/steps/queryRows.ts @@ -8,7 +8,7 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, EmptyFilterOption, SortOrder, @@ -21,7 +21,7 @@ const SortOrderPretty = { [SortOrder.DESCENDING]: "Descending", } -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { description: "Query rows from the database", icon: "Search", name: "Query rows", diff --git a/packages/server/src/automations/steps/sendSmtpEmail.ts b/packages/server/src/automations/steps/sendSmtpEmail.ts index 4950bfb3f3..72ca410528 100644 --- a/packages/server/src/automations/steps/sendSmtpEmail.ts +++ b/packages/server/src/automations/steps/sendSmtpEmail.ts @@ -2,7 +2,7 @@ import { sendSmtpEmail } from "../../utilities/workerRequests" import * as automationUtils from "../automationUtils" import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationFeature, @@ -11,7 +11,7 @@ import { BaseAutomationOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { description: "Send an email using SMTP", tagline: "Send SMTP email to {{inputs.to}}", icon: "Email", diff --git a/packages/server/src/automations/steps/serverLog.ts b/packages/server/src/automations/steps/serverLog.ts index 482325b744..ffc517c05e 100644 --- a/packages/server/src/automations/steps/serverLog.ts +++ b/packages/server/src/automations/steps/serverLog.ts @@ -1,6 +1,6 @@ import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationFeature, @@ -14,7 +14,7 @@ import { * GET/DELETE requests cannot handle body elements so they will not be sent if configured. */ -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Backend log", tagline: "Console log a value in the backend", icon: "Monitoring", diff --git a/packages/server/src/automations/steps/slack.ts b/packages/server/src/automations/steps/slack.ts index 3ed462796b..353611260c 100644 --- a/packages/server/src/automations/steps/slack.ts +++ b/packages/server/src/automations/steps/slack.ts @@ -2,7 +2,7 @@ import fetch from "node-fetch" import { getFetchResponse } from "./utils" import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationFeature, @@ -10,7 +10,7 @@ import { SlackStepInputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Slack Message", tagline: "Send a message to Slack", description: "Send a message to Slack", diff --git a/packages/server/src/automations/steps/triggerAutomationRun.ts b/packages/server/src/automations/steps/triggerAutomationRun.ts index cc73200ab3..c43f46b6f9 100644 --- a/packages/server/src/automations/steps/triggerAutomationRun.ts +++ b/packages/server/src/automations/steps/triggerAutomationRun.ts @@ -1,6 +1,6 @@ import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationResults, @@ -14,7 +14,7 @@ import { context } from "@budibase/backend-core" import { features } from "@budibase/pro" import env from "../../environment" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Trigger an automation", tagline: "Triggers an automation synchronously", icon: "Sync", diff --git a/packages/server/src/automations/steps/updateRow.ts b/packages/server/src/automations/steps/updateRow.ts index a029fb7413..65b9bf93d3 100644 --- a/packages/server/src/automations/steps/updateRow.ts +++ b/packages/server/src/automations/steps/updateRow.ts @@ -7,13 +7,13 @@ import { AutomationCustomIOType, AutomationFeature, AutomationIOType, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, UpdateRowStepInputs, UpdateRowStepOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Update Row", tagline: "Update a {{inputs.enriched.table.name}} row", icon: "Refresh", diff --git a/packages/server/src/automations/steps/zapier.ts b/packages/server/src/automations/steps/zapier.ts index 6de94b0486..888dae1e68 100644 --- a/packages/server/src/automations/steps/zapier.ts +++ b/packages/server/src/automations/steps/zapier.ts @@ -2,7 +2,7 @@ import fetch from "node-fetch" import { getFetchResponse } from "./utils" import { AutomationActionStepId, - AutomationStepSchema, + AutomationStepDefinition, AutomationStepType, AutomationIOType, AutomationFeature, @@ -10,7 +10,7 @@ import { ZapierStepOutputs, } from "@budibase/types" -export const definition: AutomationStepSchema = { +export const definition: AutomationStepDefinition = { name: "Zapier Webhook", stepId: AutomationActionStepId.zapier, type: AutomationStepType.ACTION, diff --git a/packages/server/src/automations/tests/utilities/AutomationBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationBuilder.ts index 0598d69c17..b3a9d57d06 100644 --- a/packages/server/src/automations/tests/utilities/AutomationBuilder.ts +++ b/packages/server/src/automations/tests/utilities/AutomationBuilder.ts @@ -1,23 +1,9 @@ import { v4 as uuidv4 } from "uuid" import { testAutomation } from "../../../api/routes/tests/utilities/TestFunctions" -import { - RowCreatedTriggerInputs, - RowCreatedTriggerOutputs, -} from "../../triggerInfo/rowSaved" -import { - RowUpdatedTriggerInputs, - RowUpdatedTriggerOutputs, -} from "../../triggerInfo/rowUpdated" import {} from "../../steps/createRow" import { BUILTIN_ACTION_DEFINITIONS } from "../../actions" import { TRIGGER_DEFINITIONS } from "../../triggers" import { - RowDeletedTriggerInputs, - RowDeletedTriggerOutputs, -} from "../../triggerInfo/rowDeleted" -import { - AutomationStepSchema, - AutomationTriggerSchema, LoopStepInputs, DeleteRowStepInputs, UpdateRowStepInputs, @@ -28,16 +14,26 @@ import { SmtpEmailStepInputs, ExecuteQueryStepInputs, QueryRowsStepInputs, + AutomationActionStepId, + AutomationTriggerStepId, + AutomationStep, + AutomationTriggerDefinition, + RowDeletedTriggerInputs, + RowDeletedTriggerOutputs, + RowUpdatedTriggerOutputs, + RowUpdatedTriggerInputs, + RowCreatedTriggerInputs, + RowCreatedTriggerOutputs, + AppActionTriggerOutputs, + CronTriggerOutputs, + AppActionTriggerInputs, + AutomationStepInputs, + AutomationTriggerInputs, ServerLogStepInputs, } from "@budibase/types" import {} from "../../steps/loop" import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as setup from "../utilities" -import { - AppActionTriggerInputs, - AppActionTriggerOutputs, -} from "../../triggerInfo/app" -import { CronTriggerOutputs } from "../../triggerInfo/cron" type TriggerOutputs = | RowCreatedTriggerOutputs @@ -68,7 +64,12 @@ class AutomationBuilder { // TRIGGERS rowSaved(inputs: RowCreatedTriggerInputs, outputs: RowCreatedTriggerOutputs) { this.triggerOutputs = outputs - return this.trigger(TRIGGER_DEFINITIONS.ROW_SAVED, inputs, outputs) + return this.trigger( + TRIGGER_DEFINITIONS.ROW_SAVED, + AutomationTriggerStepId.ROW_SAVED, + inputs, + outputs + ) } rowUpdated( @@ -76,7 +77,12 @@ class AutomationBuilder { outputs: RowUpdatedTriggerOutputs ) { this.triggerOutputs = outputs - return this.trigger(TRIGGER_DEFINITIONS.ROW_UPDATED, inputs, outputs) + return this.trigger( + TRIGGER_DEFINITIONS.ROW_UPDATED, + AutomationTriggerStepId.ROW_UPDATED, + inputs, + outputs + ) } rowDeleted( @@ -84,57 +90,102 @@ class AutomationBuilder { outputs: RowDeletedTriggerOutputs ) { this.triggerOutputs = outputs - return this.trigger(TRIGGER_DEFINITIONS.ROW_DELETED, inputs, 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, inputs, outputs) + return this.trigger( + TRIGGER_DEFINITIONS.APP, + AutomationTriggerStepId.APP, + inputs, + outputs + ) } // STEPS createRow(inputs: CreateRowStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.CREATE_ROW, inputs) + return this.step( + AutomationActionStepId.CREATE_ROW, + BUILTIN_ACTION_DEFINITIONS.CREATE_ROW, + inputs + ) } updateRow(inputs: UpdateRowStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.UPDATE_ROW, inputs) + return this.step( + AutomationActionStepId.UPDATE_ROW, + BUILTIN_ACTION_DEFINITIONS.UPDATE_ROW, + inputs + ) } deleteRow(inputs: DeleteRowStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.DELETE_ROW, inputs) + return this.step( + AutomationActionStepId.DELETE_ROW, + BUILTIN_ACTION_DEFINITIONS.DELETE_ROW, + inputs + ) } sendSmtpEmail(inputs: SmtpEmailStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.SEND_EMAIL_SMTP, inputs) + return this.step( + AutomationActionStepId.SEND_EMAIL_SMTP, + BUILTIN_ACTION_DEFINITIONS.SEND_EMAIL_SMTP, + inputs + ) } executeQuery(inputs: ExecuteQueryStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.EXECUTE_QUERY, inputs) + return this.step( + AutomationActionStepId.EXECUTE_QUERY, + BUILTIN_ACTION_DEFINITIONS.EXECUTE_QUERY, + inputs + ) } queryRows(inputs: QueryRowsStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.QUERY_ROWS, inputs) + return this.step( + AutomationActionStepId.QUERY_ROWS, + BUILTIN_ACTION_DEFINITIONS.QUERY_ROWS, + inputs + ) } loop(inputs: LoopStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.LOOP, inputs) + return this.step( + AutomationActionStepId.LOOP, + BUILTIN_ACTION_DEFINITIONS.LOOP, + inputs + ) } serverLog(input: ServerLogStepInputs): this { - return this.step(BUILTIN_ACTION_DEFINITIONS.SERVER_LOG, input) + return this.step( + AutomationActionStepId.SERVER_LOG, + BUILTIN_ACTION_DEFINITIONS.SERVER_LOG, + input + ) } - private trigger( - triggerSchema: AutomationTriggerSchema, - inputs?: T, + private trigger( + triggerSchema: AutomationTriggerDefinition, + stepId: TStep, + inputs?: AutomationTriggerInputs, outputs?: TriggerOutputs ): this { if (this.triggerSet) { throw new Error("Only one trigger can be set for an automation.") } + this.automationConfig.definition.trigger = { ...triggerSchema, - inputs: inputs || {}, + stepId, + inputs: inputs || ({} as any), id: uuidv4(), } this.triggerOutputs = outputs @@ -143,14 +194,16 @@ class AutomationBuilder { return this } - private step( - stepSchema: AutomationStepSchema, - inputs: T + private step( + stepId: TStep, + stepSchema: Omit, + inputs: AutomationStepInputs ): this { this.automationConfig.definition.steps.push({ ...stepSchema, - inputs, + inputs: inputs as any, id: uuidv4(), + stepId, }) return this } diff --git a/packages/server/src/automations/triggerInfo/app.ts b/packages/server/src/automations/triggerInfo/app.ts index c1945eb23d..05f787f2b1 100644 --- a/packages/server/src/automations/triggerInfo/app.ts +++ b/packages/server/src/automations/triggerInfo/app.ts @@ -2,12 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, AutomationTriggerStepId, AutomationEventType, + AutomationTriggerDefinition, } from "@budibase/types" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { name: "App Action", event: AutomationEventType.APP_TRIGGER, icon: "Apps", @@ -39,11 +39,3 @@ export const definition: AutomationTriggerSchema = { }, type: AutomationStepType.TRIGGER, } - -export type AppActionTriggerInputs = { - fields: object -} - -export type AppActionTriggerOutputs = { - fields: object -} diff --git a/packages/server/src/automations/triggerInfo/cron.ts b/packages/server/src/automations/triggerInfo/cron.ts index 781c1a8708..9fdeac0e96 100644 --- a/packages/server/src/automations/triggerInfo/cron.ts +++ b/packages/server/src/automations/triggerInfo/cron.ts @@ -2,12 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, + AutomationTriggerDefinition, AutomationTriggerStepId, AutomationEventType, } from "@budibase/types" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { name: "Cron Trigger", event: AutomationEventType.CRON_TRIGGER, icon: "Clock", @@ -38,11 +38,3 @@ export const definition: AutomationTriggerSchema = { }, type: AutomationStepType.TRIGGER, } - -export type CronTriggerInputs = { - cron: string -} - -export type CronTriggerOutputs = { - timestamp: number -} diff --git a/packages/server/src/automations/triggerInfo/index.ts b/packages/server/src/automations/triggerInfo/index.ts index 58a6fea3ad..4e2a8b46ec 100644 --- a/packages/server/src/automations/triggerInfo/index.ts +++ b/packages/server/src/automations/triggerInfo/index.ts @@ -1,5 +1,5 @@ import { - AutomationTriggerSchema, + AutomationTriggerDefinition, AutomationTriggerStepId, } from "@budibase/types" import * as app from "./app" @@ -12,7 +12,7 @@ import * as rowAction from "./rowAction" export const definitions: Record< keyof typeof AutomationTriggerStepId, - AutomationTriggerSchema + AutomationTriggerDefinition > = { ROW_SAVED: rowSaved.definition, ROW_UPDATED: rowUpdated.definition, diff --git a/packages/server/src/automations/triggerInfo/rowAction.ts b/packages/server/src/automations/triggerInfo/rowAction.ts index 862812fe2c..d6a8020e52 100644 --- a/packages/server/src/automations/triggerInfo/rowAction.ts +++ b/packages/server/src/automations/triggerInfo/rowAction.ts @@ -2,12 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, AutomationTriggerStepId, AutomationEventType, + AutomationTriggerDefinition, } from "@budibase/types" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { type: AutomationStepType.TRIGGER, name: "Row Action", event: AutomationEventType.ROW_ACTION, // TODO diff --git a/packages/server/src/automations/triggerInfo/rowDeleted.ts b/packages/server/src/automations/triggerInfo/rowDeleted.ts index 0ebf908ec1..64d9f4ac84 100644 --- a/packages/server/src/automations/triggerInfo/rowDeleted.ts +++ b/packages/server/src/automations/triggerInfo/rowDeleted.ts @@ -2,13 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, + AutomationTriggerDefinition, AutomationTriggerStepId, AutomationEventType, - Row, } from "@budibase/types" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { name: "Row Deleted", event: AutomationEventType.ROW_DELETE, icon: "TableRowRemoveCenter", @@ -40,11 +39,3 @@ export const definition: AutomationTriggerSchema = { }, type: AutomationStepType.TRIGGER, } - -export type RowDeletedTriggerInputs = { - tableId: string -} - -export type RowDeletedTriggerOutputs = { - row: Row -} diff --git a/packages/server/src/automations/triggerInfo/rowSaved.ts b/packages/server/src/automations/triggerInfo/rowSaved.ts index 93f036d13a..57b52397ad 100644 --- a/packages/server/src/automations/triggerInfo/rowSaved.ts +++ b/packages/server/src/automations/triggerInfo/rowSaved.ts @@ -2,14 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, AutomationTriggerStepId, AutomationEventType, - Row, + AutomationTriggerDefinition, } from "@budibase/types" -import { SearchFilters } from "aws-sdk/clients/elasticbeanstalk" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { name: "Row Created", event: AutomationEventType.ROW_SAVE, icon: "TableRowAddBottom", @@ -54,14 +52,3 @@ export const definition: AutomationTriggerSchema = { }, type: AutomationStepType.TRIGGER, } - -export type RowCreatedTriggerInputs = { - tableId: string - filters?: SearchFilters -} - -export type RowCreatedTriggerOutputs = { - row: Row - id: string - revision: string -} diff --git a/packages/server/src/automations/triggerInfo/rowUpdated.ts b/packages/server/src/automations/triggerInfo/rowUpdated.ts index 148a0bd3f3..16c1bba4e3 100644 --- a/packages/server/src/automations/triggerInfo/rowUpdated.ts +++ b/packages/server/src/automations/triggerInfo/rowUpdated.ts @@ -2,14 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, + AutomationTriggerDefinition, AutomationTriggerStepId, AutomationEventType, - Row, - SearchFilters, } from "@budibase/types" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { name: "Row Updated", event: AutomationEventType.ROW_UPDATE, icon: "Refresh", @@ -61,14 +59,3 @@ export const definition: AutomationTriggerSchema = { }, type: AutomationStepType.TRIGGER, } - -export type RowUpdatedTriggerInputs = { - tableId: string - filters?: SearchFilters -} - -export type RowUpdatedTriggerOutputs = { - row: Row - id: string - revision?: string -} diff --git a/packages/server/src/automations/triggerInfo/webhook.ts b/packages/server/src/automations/triggerInfo/webhook.ts index b97c76ec61..3e86832dba 100644 --- a/packages/server/src/automations/triggerInfo/webhook.ts +++ b/packages/server/src/automations/triggerInfo/webhook.ts @@ -2,12 +2,12 @@ import { AutomationCustomIOType, AutomationIOType, AutomationStepType, - AutomationTriggerSchema, AutomationTriggerStepId, AutomationEventType, + AutomationTriggerDefinition, } from "@budibase/types" -export const definition: AutomationTriggerSchema = { +export const definition: AutomationTriggerDefinition = { name: "Webhook", event: AutomationEventType.WEBHOOK_TRIGGER, icon: "Send", diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts index febc8b6a56..18b033cdcf 100644 --- a/packages/server/src/automations/triggers.ts +++ b/packages/server/src/automations/triggers.ts @@ -54,9 +54,9 @@ async function queueRelevantRowAutomations( return trigger && trigger.event === eventType && !automation.disabled }) - for (let automation of automations) { - let automationDef = automation.definition - let automationTrigger = automationDef?.trigger + for (const automation of automations) { + const automationDef = automation.definition + const automationTrigger = automationDef?.trigger // don't queue events which are for dev apps, only way to test automations is // running tests on them, in production the test flag will never // be checked due to lazy evaluation (first always false) diff --git a/packages/server/src/automations/unitTests/automationUtils.spec.ts b/packages/server/src/automations/unitTests/automationUtils.spec.ts index 7706dab4cc..e855fd4be0 100644 --- a/packages/server/src/automations/unitTests/automationUtils.spec.ts +++ b/packages/server/src/automations/unitTests/automationUtils.spec.ts @@ -44,7 +44,9 @@ describe("automationUtils", () => { }) it("should handle null values", () => { // expect it to handle where the binding is null - expect(typecastForLooping({ option: LoopStepType.ARRAY })).toEqual(null) + expect( + typecastForLooping({ option: LoopStepType.ARRAY, binding: null }) + ).toEqual(null) expect(() => typecastForLooping({ option: LoopStepType.ARRAY, binding: "test" }) ).toThrow() diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index 93b8f907fd..62125ea589 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -10,7 +10,8 @@ import { quotas } from "@budibase/pro" import { Automation, AutomationJob, - AutomationStepSchema, + AutomationStepDefinition, + AutomationTriggerDefinition, } from "@budibase/types" import { automationsEnabled } from "../features" import { helpers, REBOOT_CRON } from "@budibase/shared-core" @@ -116,7 +117,10 @@ export async function updateTestHistory( } export function removeDeprecated( - definitions: Record + definitions: Record< + string, + AutomationStepDefinition | AutomationTriggerDefinition + > ) { const base = cloneDeep(definitions) for (let key of Object.keys(base)) { diff --git a/packages/server/src/definitions/automations.ts b/packages/server/src/definitions/automations.ts index 2a51c737f2..e84eecea51 100644 --- a/packages/server/src/definitions/automations.ts +++ b/packages/server/src/definitions/automations.ts @@ -1,12 +1,4 @@ -import { - AutomationResults, - AutomationStep, - LoopStepType, -} from "@budibase/types" - -export interface LoopStep extends AutomationStep { - inputs: LoopInput -} +import { AutomationResults, LoopStepType } from "@budibase/types" export interface LoopInput { option: LoopStepType diff --git a/packages/server/src/sdk/app/rowActions.ts b/packages/server/src/sdk/app/rowActions.ts index 36d2ed7b92..f557887b15 100644 --- a/packages/server/src/sdk/app/rowActions.ts +++ b/packages/server/src/sdk/app/rowActions.ts @@ -1,6 +1,7 @@ import { context, HTTPError, utils } from "@budibase/backend-core" import { + AutomationTriggerStepId, SEPARATOR, TableRowActions, VirtualDocumentType, @@ -61,6 +62,7 @@ export async function create(tableId: string, rowAction: { name: string }) { trigger: { id: "trigger", ...TRIGGER_DEFINITIONS.ROW_ACTION, + stepId: AutomationTriggerStepId.ROW_ACTION, inputs: { tableId, rowActionId: newRowActionId, diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index 698f6d8236..8d64734ee3 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -151,6 +151,8 @@ export function automationStep( return { id: utils.newid(), ...actionDefinition, + stepId: AutomationActionStepId.CREATE_ROW, + inputs: { row: {} }, } } @@ -160,7 +162,7 @@ export function automationTrigger( return { id: utils.newid(), ...triggerDefinition, - } + } as AutomationTrigger } export function newAutomation({ @@ -209,7 +211,9 @@ export function basicAutomation(appId?: string): Automation { description: "test", type: AutomationStepType.TRIGGER, id: "test", - inputs: {}, + inputs: { + fields: {}, + }, schema: { inputs: { properties: {}, @@ -241,7 +245,7 @@ export function serverLogAutomation(appId?: string): Automation { description: "test", type: AutomationStepType.TRIGGER, id: "test", - inputs: {}, + inputs: { fields: {} }, schema: { inputs: { properties: {}, @@ -394,7 +398,7 @@ export function filterAutomation(appId: string, tableId?: string): Automation { type: AutomationStepType.ACTION, internal: true, stepId: AutomationActionStepId.FILTER, - inputs: {}, + inputs: { field: "name", value: "test", condition: "EQ" }, schema: BUILTIN_ACTION_DEFINITIONS.EXECUTE_SCRIPT.schema, }, ], @@ -408,7 +412,7 @@ export function filterAutomation(appId: string, tableId?: string): Automation { event: "row:save", stepId: AutomationTriggerStepId.ROW_SAVED, inputs: { - tableId, + tableId: tableId!, }, schema: TRIGGER_DEFINITIONS.ROW_SAVED.schema, }, @@ -417,7 +421,10 @@ export function filterAutomation(appId: string, tableId?: string): Automation { return automation } -export function updateRowAutomationWithFilters(appId: string): Automation { +export function updateRowAutomationWithFilters( + appId: string, + tableId: string +): Automation { const automation: Automation = { name: "updateRowWithFilters", type: "automation", @@ -433,7 +440,7 @@ export function updateRowAutomationWithFilters(appId: string): Automation { type: AutomationStepType.ACTION, internal: true, stepId: AutomationActionStepId.SERVER_LOG, - inputs: {}, + inputs: { text: "log statement" }, schema: BUILTIN_ACTION_DEFINITIONS.SERVER_LOG.schema, }, ], @@ -442,12 +449,11 @@ export function updateRowAutomationWithFilters(appId: string): Automation { tagline: "An automation trigger", description: "A trigger", icon: "Icon", - id: "a", type: AutomationStepType.TRIGGER, event: "row:update", stepId: AutomationTriggerStepId.ROW_UPDATED, - inputs: {}, + inputs: { tableId }, schema: TRIGGER_DEFINITIONS.ROW_UPDATED.schema, }, }, diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 2e95542229..c2470e78d4 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -23,13 +23,9 @@ import { AutomationStatus, AutomationStep, AutomationStepStatus, -} from "@budibase/types" -import { - AutomationContext, - LoopInput, LoopStep, - TriggerOutput, -} from "../definitions/automations" +} from "@budibase/types" +import { AutomationContext, TriggerOutput } from "../definitions/automations" import { WorkerCallback } from "./definitions" import { context, logging } from "@budibase/backend-core" import { processObject } from "@budibase/string-templates" @@ -40,8 +36,6 @@ import env from "../environment" import tracer from "dd-trace" threadUtils.threadSetup() -const FILTER_STEP_ID = actions.BUILTIN_ACTION_DEFINITIONS.FILTER.stepId -const LOOP_STEP_ID = actions.BUILTIN_ACTION_DEFINITIONS.LOOP.stepId const CRON_STEP_ID = triggerDefs.CRON.stepId const STOPPED_STATUS = { success: true, status: AutomationStatus.STOPPED } @@ -256,7 +250,7 @@ class Orchestrator { this._context.env = await sdkUtils.getEnvironmentVariables() let automation = this._automation let stopped = false - let loopStep: LoopStep | undefined = undefined + let loopStep: LoopStep | undefined let stepCount = 0 let currentLoopStepIndex: number = 0 @@ -276,7 +270,7 @@ class Orchestrator { } } const start = performance.now() - for (let step of automation.definition.steps) { + for (const step of automation.definition.steps) { const stepSpan = tracer.startSpan("Orchestrator.execute.step", { childOf: span, }) @@ -293,7 +287,7 @@ class Orchestrator { }, }) - let input: LoopInput | undefined, + let input, iterations = 1, iterationCount = 0 @@ -310,8 +304,8 @@ class Orchestrator { } stepCount++ - if (step.stepId === LOOP_STEP_ID) { - loopStep = step as LoopStep + if (step.stepId === AutomationActionStepId.LOOP) { + loopStep = step currentLoopStepIndex = stepCount continue } @@ -331,7 +325,7 @@ class Orchestrator { } try { loopStep.inputs.binding = automationUtils.typecastForLooping( - loopStep.inputs as LoopInput + loopStep.inputs ) } catch (err) { this.updateContextAndOutput( @@ -368,7 +362,7 @@ class Orchestrator { if ( stepIndex === env.AUTOMATION_MAX_ITERATIONS || (loopStep.inputs.iterations && - stepIndex === parseInt(loopStep.inputs.iterations)) + stepIndex === loopStep.inputs.iterations) ) { this.updateContextAndOutput( currentLoopStepIndex, @@ -443,7 +437,10 @@ class Orchestrator { this._context.steps[stepCount] = outputs // if filter causes us to stop execution don't break the loop, set a var // so that we can finish iterating through the steps and record that it stopped - if (step.stepId === FILTER_STEP_ID && !outputs.result) { + if ( + step.stepId === AutomationActionStepId.FILTER && + !outputs.result + ) { stopped = true this.updateExecutionOutput( step.id, diff --git a/packages/types/src/documents/app/automation/StepInputsOutputs.ts b/packages/types/src/documents/app/automation/StepInputsOutputs.ts new file mode 100644 index 0000000000..e62a6e3f08 --- /dev/null +++ b/packages/types/src/documents/app/automation/StepInputsOutputs.ts @@ -0,0 +1,277 @@ +import { SortOrder } from "../../../api" +import { SearchFilters, EmptyFilterOption } from "../../../sdk" +import { HttpMethod } from "../query" +import { Row } from "../row" +import { LoopStepType, EmailAttachment, AutomationResults } from "./automation" +import { AutomationStep, AutomationStepOutputs } from "./schema" + +export type BaseAutomationOutputs = { + success?: boolean + response?: { + [key: string]: any + message?: string + } +} +export type ExternalAppStepOutputs = { + httpStatus?: number + response: string + success: boolean +} + +export type BashStepInputs = { + code: string +} + +export type BashStepOutputs = BaseAutomationOutputs & { + stdout?: string +} + +export type CollectStepInputs = { + collection: string +} + +export type CollectStepOutputs = BaseAutomationOutputs & { + value?: any +} + +export type CreateRowStepInputs = { + row: Row +} + +export type CreateRowStepOutputs = BaseAutomationOutputs & { + row?: Row + id?: string + revision?: string +} + +export type DelayStepInputs = { + time: number +} + +export type DelayStepOutputs = BaseAutomationOutputs + +export type DeleteRowStepInputs = { + tableId: string + id: string + revision?: string +} + +export type DeleteRowStepOutputs = BaseAutomationOutputs & { + row?: Row +} + +export type DiscordStepInputs = { + url: string + username?: string + avatar_url?: string + content: string +} + +export type ExecuteQueryStepInputs = { + query: { + queryId: string + } +} + +export type ExecuteQueryStepOutputs = BaseAutomationOutputs & { + info?: any +} + +export type ExecuteScriptStepInputs = { + code: string +} + +export type ExecuteScriptStepOutputs = BaseAutomationOutputs & { + value?: string +} + +export type FilterStepInputs = { + field: any + condition: string + value: any +} + +export type FilterStepOutputs = BaseAutomationOutputs & { + result: boolean + refValue?: any + comparisonValue?: any +} + +export type LoopStepInputs = { + option: LoopStepType + binding: any + iterations?: number + failure?: string +} + +export type LoopStepOutputs = { + items: AutomationStepOutputs[] + success: boolean + iterations: number +} + +export type BranchStepInputs = { + conditions: SearchFilters + children?: Record +} + +export type MakeIntegrationInputs = { + url: string + body: any +} + +export type n8nStepInputs = { + url: string + method: HttpMethod + authorization: string + body: any +} + +export type OpenAIStepInputs = { + prompt: string + model: Model +} +enum Model { + GPT_35_TURBO = "gpt-3.5-turbo", + // will only work with api keys that have access to the GPT4 API + GPT_4 = "gpt-4", +} + +export type OpenAIStepOutputs = Omit & { + response?: string | null +} + +export type QueryRowsStepInputs = { + tableId: string + filters?: SearchFilters + "filters-def"?: any + sortColumn?: string + sortOrder?: SortOrder + limit?: number + onEmptyFilter?: EmptyFilterOption +} + +export type QueryRowsStepOutputs = BaseAutomationOutputs & { + rows?: Row[] +} + +export type SmtpEmailStepInputs = { + to: string + from: string + subject: string + contents: string + cc: string + bcc: string + addInvite?: boolean + startTime: Date + endTime: Date + summary: string + location?: string + url?: string + attachments?: EmailAttachment[] +} + +export type SmtpEmailStepOutputs = BaseAutomationOutputs +export type ServerLogStepInputs = { + text: string +} + +export type ServerLogStepOutputs = BaseAutomationOutputs & { + message: string +} +export type SlackStepInputs = { + url: string + text: string +} + +export type TriggerAutomationStepInputs = { + automation: { + automationId: string + } + timeout: number +} + +export type TriggerAutomationStepOutputs = BaseAutomationOutputs & { + value?: AutomationResults["steps"] +} + +export type UpdateRowStepInputs = { + meta: Record + row: Row + rowId: string +} + +export type UpdateRowStepOutputs = BaseAutomationOutputs & { + row?: Row + id?: string + revision?: string +} + +export type ZapierStepInputs = { + url: string + body: any +} + +export type ZapierStepOutputs = Omit & { + response: string +} +enum RequestType { + POST = "POST", + GET = "GET", + PUT = "PUT", + DELETE = "DELETE", + PATCH = "PATCH", +} + +export type OutgoingWebhookStepInputs = { + requestMethod: RequestType + url: string + requestBody: string + headers: string +} + +export type AppActionTriggerInputs = { + fields: object +} + +export type AppActionTriggerOutputs = { + fields: object +} + +export type CronTriggerInputs = { + cron: string +} + +export type CronTriggerOutputs = { + timestamp: number +} + +export type RowDeletedTriggerInputs = { + tableId: string +} + +export type RowDeletedTriggerOutputs = { + row: Row +} + +export type RowCreatedTriggerInputs = { + tableId: string + filters?: SearchFilters +} + +export type RowCreatedTriggerOutputs = { + row: Row + id: string + revision: string +} + +export type RowUpdatedTriggerInputs = { + tableId: string + filters?: SearchFilters +} + +export type RowUpdatedTriggerOutputs = { + row: Row + id: string + revision?: string +} diff --git a/packages/types/src/documents/app/automation/automation.ts b/packages/types/src/documents/app/automation/automation.ts index d8fad4c8e8..fcc3af445c 100644 --- a/packages/types/src/documents/app/automation/automation.ts +++ b/packages/types/src/documents/app/automation/automation.ts @@ -4,6 +4,7 @@ import { User } from "../../global" import { ReadStream } from "fs" import { Row } from "../row" import { Table } from "../table" +import { AutomationStep, AutomationTrigger } from "./schema" export enum AutomationIOType { OBJECT = "object", @@ -71,6 +72,7 @@ export enum AutomationActionStepId { COLLECT = "COLLECT", OPENAI = "OPENAI", TRIGGER_AUTOMATION_RUN = "TRIGGER_AUTOMATION_RUN", + BRANCH = "BRANCH", // these used to be lowercase step IDs, maintain for backwards compat discord = "discord", slack = "slack", @@ -164,44 +166,10 @@ export interface InputOutputBlock { required?: string[] } -export interface AutomationStepSchema { - name: string - stepTitle?: string - tagline: string - icon: string - description: string - type: AutomationStepType - internal?: boolean - deprecated?: boolean - stepId: AutomationTriggerStepId | AutomationActionStepId - blockToLoop?: string - inputs: Record - schema: { - inputs: InputOutputBlock - outputs: InputOutputBlock - } - custom?: boolean - features?: Partial> -} - export enum AutomationFeature { LOOPING = "LOOPING", } -export interface AutomationStep extends AutomationStepSchema { - id: string -} - -export interface AutomationTriggerSchema extends AutomationStepSchema { - type: AutomationStepType.TRIGGER - event?: string - cronJobId?: string -} - -export interface AutomationTrigger extends AutomationTriggerSchema { - id: string -} - export enum AutomationStepStatus { NO_ITERATIONS = "no_iterations", } diff --git a/packages/types/src/documents/app/automation/index.ts b/packages/types/src/documents/app/automation/index.ts index 017596670d..f978ef36e3 100644 --- a/packages/types/src/documents/app/automation/index.ts +++ b/packages/types/src/documents/app/automation/index.ts @@ -1,2 +1,3 @@ export * from "./automation" export * from "./schema" +export * from "./StepInputsOutputs" diff --git a/packages/types/src/documents/app/automation/schema.ts b/packages/types/src/documents/app/automation/schema.ts index 2c7af3e463..599256694d 100644 --- a/packages/types/src/documents/app/automation/schema.ts +++ b/packages/types/src/documents/app/automation/schema.ts @@ -1,14 +1,57 @@ -import { SortOrder } from "../../../api" -import { EmptyFilterOption, Hosting, SearchFilters } from "../../../sdk" -import { HttpMethod } from "../query" -import { Row } from "../row" +import { Hosting } from "../../../sdk" import { AutomationActionStepId, - AutomationResults, - EmailAttachment, - LoopStepType, ActionImplementation, + AutomationStepType, + AutomationFeature, + InputOutputBlock, + AutomationTriggerStepId, } from "./automation" +import { + CollectStepInputs, + CollectStepOutputs, + CreateRowStepInputs, + CreateRowStepOutputs, + DelayStepInputs, + DelayStepOutputs, + DeleteRowStepInputs, + DeleteRowStepOutputs, + ExecuteQueryStepInputs, + ExecuteQueryStepOutputs, + ExecuteScriptStepInputs, + ExecuteScriptStepOutputs, + FilterStepInputs, + FilterStepOutputs, + QueryRowsStepInputs, + QueryRowsStepOutputs, + SmtpEmailStepInputs, + ServerLogStepInputs, + ServerLogStepOutputs, + TriggerAutomationStepInputs, + TriggerAutomationStepOutputs, + UpdateRowStepInputs, + UpdateRowStepOutputs, + OutgoingWebhookStepInputs, + ExternalAppStepOutputs, + DiscordStepInputs, + SlackStepInputs, + ZapierStepInputs, + ZapierStepOutputs, + MakeIntegrationInputs, + n8nStepInputs, + BashStepInputs, + BashStepOutputs, + OpenAIStepInputs, + OpenAIStepOutputs, + LoopStepInputs, + AppActionTriggerInputs, + CronTriggerInputs, + RowUpdatedTriggerInputs, + RowCreatedTriggerInputs, + RowDeletedTriggerInputs, + BranchStepInputs, + BaseAutomationOutputs, +} from "./StepInputsOutputs" export type ActionImplementations = { [AutomationActionStepId.COLLECT]: ActionImplementation< @@ -27,7 +70,6 @@ export type ActionImplementations = { DeleteRowStepInputs, DeleteRowStepOutputs > - [AutomationActionStepId.EXECUTE_QUERY]: ActionImplementation< ExecuteQueryStepInputs, ExecuteQueryStepOutputs @@ -72,7 +114,6 @@ export type ActionImplementations = { SlackStepInputs, ExternalAppStepOutputs > - [AutomationActionStepId.zapier]: ActionImplementation< ZapierStepInputs, ZapierStepOutputs @@ -98,6 +139,24 @@ export type ActionImplementations = { } : {}) +export interface AutomationStepSchemaBase { + name: string + stepTitle?: string + tagline: string + icon: string + description: string + type: AutomationStepType + internal?: boolean + deprecated?: boolean + blockToLoop?: string + schema: { + inputs: InputOutputBlock + outputs: InputOutputBlock + } + custom?: boolean + features?: Partial> +} + export type AutomationStepOutputs = | CollectStepOutputs | CreateRowStepOutputs @@ -116,223 +175,204 @@ export type AutomationStepOutputs = | UpdateRowStepOutputs | ZapierStepOutputs -export type BaseAutomationOutputs = { - success?: boolean - response?: { - [key: string]: any - message?: string - } -} +export type AutomationStepInputs = + T extends AutomationActionStepId.COLLECT + ? CollectStepInputs + : T extends AutomationActionStepId.CREATE_ROW + ? CreateRowStepInputs + : T extends AutomationActionStepId.DELAY + ? DelayStepInputs + : T extends AutomationActionStepId.DELETE_ROW + ? DeleteRowStepInputs + : T extends AutomationActionStepId.EXECUTE_QUERY + ? ExecuteQueryStepInputs + : T extends AutomationActionStepId.EXECUTE_SCRIPT + ? ExecuteScriptStepInputs + : T extends AutomationActionStepId.FILTER + ? FilterStepInputs + : T extends AutomationActionStepId.QUERY_ROWS + ? QueryRowsStepInputs + : T extends AutomationActionStepId.SEND_EMAIL_SMTP + ? SmtpEmailStepInputs + : T extends AutomationActionStepId.SERVER_LOG + ? ServerLogStepInputs + : T extends AutomationActionStepId.TRIGGER_AUTOMATION_RUN + ? TriggerAutomationStepInputs + : T extends AutomationActionStepId.UPDATE_ROW + ? UpdateRowStepInputs + : T extends AutomationActionStepId.OUTGOING_WEBHOOK + ? OutgoingWebhookStepInputs + : T extends AutomationActionStepId.discord + ? DiscordStepInputs + : T extends AutomationActionStepId.slack + ? SlackStepInputs + : T extends AutomationActionStepId.zapier + ? ZapierStepInputs + : T extends AutomationActionStepId.integromat + ? MakeIntegrationInputs + : T extends AutomationActionStepId.n8n + ? n8nStepInputs + : T extends AutomationActionStepId.EXECUTE_BASH + ? BashStepInputs + : T extends AutomationActionStepId.OPENAI + ? OpenAIStepInputs + : T extends AutomationActionStepId.LOOP + ? LoopStepInputs + : T extends AutomationActionStepId.BRANCH + ? BranchStepInputs + : never -export type ExternalAppStepOutputs = { - httpStatus?: number - response: string - success: boolean -} - -export type BashStepInputs = { - code: string -} - -export type BashStepOutputs = BaseAutomationOutputs & { - stdout?: string -} - -export type CollectStepInputs = { - collection: string -} - -export type CollectStepOutputs = BaseAutomationOutputs & { - value?: any -} - -export type CreateRowStepInputs = { - row: Row -} - -export type CreateRowStepOutputs = BaseAutomationOutputs & { - row?: Row - id?: string - revision?: string -} - -export type DelayStepInputs = { - time: number -} - -export type DelayStepOutputs = BaseAutomationOutputs - -export type DeleteRowStepInputs = { - tableId: string +export interface AutomationStepSchema + extends AutomationStepSchemaBase { id: string - revision?: string + stepId: TStep + inputs: AutomationStepInputs & Record // The record union to be removed once the types are fixed } -export type DeleteRowStepOutputs = BaseAutomationOutputs & { - row?: Row +export type CollectStep = AutomationStepSchema + +export type CreateRowStep = + AutomationStepSchema + +export type DelayStep = AutomationStepSchema + +export type DeleteRowStep = + AutomationStepSchema + +export type ExecuteQueryStep = + AutomationStepSchema + +export type ExecuteScriptStep = + AutomationStepSchema + +export type FilterStep = AutomationStepSchema + +export type QueryRowsStep = + AutomationStepSchema + +export type SendEmailSmtpStep = + AutomationStepSchema + +export type ServerLogStep = + AutomationStepSchema + +export type TriggerAutomationRunStep = + AutomationStepSchema + +export type UpdateRowStep = + AutomationStepSchema + +export type OutgoingWebhookStep = + AutomationStepSchema + +export type DiscordStep = AutomationStepSchema + +export type SlackStep = AutomationStepSchema + +export type ZapierStep = AutomationStepSchema + +export type IntegromatStep = + AutomationStepSchema + +export type N8nStep = AutomationStepSchema + +export type ExecuteBashStep = + AutomationStepSchema + +export type OpenAIStep = AutomationStepSchema + +export type LoopStep = AutomationStepSchema + +export type BranchStep = AutomationStepSchema +export type AutomationStep = + | CollectStep + | CreateRowStep + | DelayStep + | DeleteRowStep + | ExecuteQueryStep + | ExecuteScriptStep + | FilterStep + | QueryRowsStep + | SendEmailSmtpStep + | ServerLogStep + | TriggerAutomationRunStep + | UpdateRowStep + | OutgoingWebhookStep + | DiscordStep + | SlackStep + | ZapierStep + | IntegromatStep + | N8nStep + | LoopStep + | ExecuteBashStep + | OpenAIStep + | BranchStep + +type EmptyInputs = {} +export type AutomationStepDefinition = Omit & { + inputs: EmptyInputs } -export type DiscordStepInputs = { - url: string - username?: string - avatar_url?: string - content: string +export type AutomationTriggerDefinition = Omit< + AutomationTrigger, + "id" | "inputs" +> & { + inputs: EmptyInputs } -export type ExecuteQueryStepInputs = { - query: { - queryId: string - } +export type AutomationTriggerInputs = + T extends AutomationTriggerStepId.APP + ? AppActionTriggerInputs + : T extends AutomationTriggerStepId.CRON + ? CronTriggerInputs + : T extends AutomationTriggerStepId.ROW_ACTION + ? Record + : T extends AutomationTriggerStepId.ROW_DELETED + ? RowDeletedTriggerInputs + : T extends AutomationTriggerStepId.ROW_SAVED + ? RowCreatedTriggerInputs + : T extends AutomationTriggerStepId.ROW_UPDATED + ? RowUpdatedTriggerInputs + : T extends AutomationTriggerStepId.WEBHOOK + ? Record + : never + +export interface AutomationTriggerSchema< + TTrigger extends AutomationTriggerStepId +> extends AutomationStepSchemaBase { + id: string + type: AutomationStepType.TRIGGER + event?: string + cronJobId?: string + stepId: TTrigger + inputs: AutomationTriggerInputs & Record // The record union to be removed once the types are fixed } -export type ExecuteQueryStepOutputs = BaseAutomationOutputs & { - info?: any -} +export type AutomationTrigger = + | AppActionTrigger + | CronTrigger + | RowActionTrigger + | RowDeletedTrigger + | RowSavedTrigger + | RowUpdatedTrigger + | WebhookTrigger -export type ExecuteScriptStepInputs = { - code: string -} +export type AppActionTrigger = + AutomationTriggerSchema -export type ExecuteScriptStepOutputs = BaseAutomationOutputs & { - value?: string -} +export type CronTrigger = AutomationTriggerSchema -export type FilterStepInputs = { - field: any - condition: string - value: any -} +export type RowActionTrigger = + AutomationTriggerSchema -export type FilterStepOutputs = BaseAutomationOutputs & { - result: boolean - refValue?: any - comparisonValue?: any -} +export type RowDeletedTrigger = + AutomationTriggerSchema -export type LoopStepInputs = { - option: LoopStepType - binding: any - iterations?: number - failure?: string -} +export type RowSavedTrigger = + AutomationTriggerSchema -export type LoopStepOutputs = { - items: AutomationStepOutputs[] - success: boolean - iterations: number -} +export type RowUpdatedTrigger = + AutomationTriggerSchema -export type MakeIntegrationInputs = { - url: string - body: any -} - -export type n8nStepInputs = { - url: string - method: HttpMethod - authorization: string - body: any -} - -export type OpenAIStepInputs = { - prompt: string - model: Model -} - -enum Model { - GPT_35_TURBO = "gpt-3.5-turbo", - // will only work with api keys that have access to the GPT4 API - GPT_4 = "gpt-4", -} - -export type OpenAIStepOutputs = Omit & { - response?: string | null -} - -export type QueryRowsStepInputs = { - tableId: string - filters?: SearchFilters - "filters-def"?: any - sortColumn?: string - sortOrder?: SortOrder - limit?: number - onEmptyFilter?: EmptyFilterOption -} - -export type QueryRowsStepOutputs = BaseAutomationOutputs & { - rows?: Row[] -} - -export type SmtpEmailStepInputs = { - to: string - from: string - subject: string - contents: string - cc: string - bcc: string - addInvite?: boolean - startTime: Date - endTime: Date - summary: string - location?: string - url?: string - attachments?: EmailAttachment[] -} -export type ServerLogStepInputs = { - text: string -} - -export type ServerLogStepOutputs = BaseAutomationOutputs & { - message: string -} -export type SlackStepInputs = { - url: string - text: string -} - -export type TriggerAutomationStepInputs = { - automation: { - automationId: string - } - timeout: number -} - -export type TriggerAutomationStepOutputs = BaseAutomationOutputs & { - value?: AutomationResults["steps"] -} - -export type UpdateRowStepInputs = { - meta: Record - row: Row - rowId: string -} - -export type UpdateRowStepOutputs = BaseAutomationOutputs & { - row?: Row - id?: string - revision?: string -} - -export type ZapierStepInputs = { - url: string - body: any -} - -export type ZapierStepOutputs = Omit & { - response: string -} - -enum RequestType { - POST = "POST", - GET = "GET", - PUT = "PUT", - DELETE = "DELETE", - PATCH = "PATCH", -} - -export type OutgoingWebhookStepInputs = { - requestMethod: RequestType - url: string - requestBody: string - headers: string -} +export type WebhookTrigger = + AutomationTriggerSchema