diff --git a/packages/builder/src/components/common/bindings/CodeEditorField.svelte b/packages/builder/src/components/common/bindings/CodeEditorField.svelte
index f9713095c8..217e691b19 100644
--- a/packages/builder/src/components/common/bindings/CodeEditorField.svelte
+++ b/packages/builder/src/components/common/bindings/CodeEditorField.svelte
@@ -40,8 +40,6 @@
export let autofocusEditor = false
export let placeholder = null
- let mode: BindingMode | null
- let initialValueJS = value?.startsWith?.("{{ js ")
let getCaretPosition: CaretPositionFn | undefined
let insertAtPos: InsertAtPositionFn | undefined
@@ -141,9 +139,6 @@
}
const onChangeJSValue = (e: { detail: string }) => {
- // if(typeof onChange === "function"){
-
- // }
if (!e.detail?.trim()) {
// Don't bother saving empty values as JS
updateValue(null)
@@ -151,18 +146,6 @@
updateValue(encodeJSBinding(e.detail))
}
}
-
- onMount(() => {
- // Set the initial mode appropriately
- const initialValueMode = initialValueJS
- ? BindingMode.JavaScript
- : BindingMode.Text
- if (editorModeOptions.includes(initialValueMode)) {
- mode = initialValueMode
- } else {
- mode = editorModeOptions[0]
- }
- })
diff --git a/packages/builder/src/stores/builder/automations.ts b/packages/builder/src/stores/builder/automations.ts
index 5488749331..1510bb7acd 100644
--- a/packages/builder/src/stores/builder/automations.ts
+++ b/packages/builder/src/stores/builder/automations.ts
@@ -1,9 +1,9 @@
-import { derived, get, Readable, Writable } from "svelte/store"
+import { derived, get, Readable } from "svelte/store"
import { API } from "@/api"
import { cloneDeep } from "lodash/fp"
import { generate } from "shortid"
import { createHistoryStore } from "@/stores/builder/history"
-import { licensing, organisation, environment, auth } from "@/stores/portal"
+import { licensing, organisation, environment } from "@/stores/portal"
import { tables, appStore } from "@/stores/builder"
import { notifications } from "@budibase/bbui"
import {
@@ -34,6 +34,11 @@ import {
GetAutomationActionDefinitionsResponse,
AppSelfResponse,
TestAutomationResponse,
+ isAutomationResults,
+ AutomationTestTrigger,
+ TriggerTestOutputs,
+ RowActionTriggerOutputs,
+ WebhookTriggerOutputs,
} from "@budibase/types"
import { ActionStepID, TriggerStepID } from "@/constants/backend/automations"
import { FIELDS } from "@/constants/backend"
@@ -100,7 +105,7 @@ const automationActions = (store: AutomationStore) => ({
const appSelfResponse = await API.fetchSelf()
store.update(state => ({
...state,
- appSelf: appSelfResponse,
+ ...(appSelfResponse ? { appSelf: appSelfResponse } : {}),
}))
return appSelfResponse
},
@@ -882,12 +887,7 @@ const automationActions = (store: AutomationStore) => ({
const message = err.message || err.status || JSON.stringify(err)
throw `Automation test failed - ${message}`
}
- if (!result?.trigger && !result?.steps?.length && !result?.message) {
- if (result?.err?.code === "usage_limit_exceeded") {
- throw "You have exceeded your automation quota"
- }
- throw "Something went wrong testing your automation"
- }
+
store.update(state => {
state.testResults = result
return state
@@ -1594,18 +1594,9 @@ export class SelectedAutomationStore extends DerivedBudiStore<
}
export const selectedAutomation = new SelectedAutomationStore(automationStore)
-type TriggerContext = AutomationTrigger & {
- meta?: Record
- table?: Table
- body?: Record
- row?: Record
- oldRow?: Record
- outputs?: Record
-}
-
export interface AutomationContext {
user: AppSelfResponse
- trigger: TriggerContext
+ trigger?: TriggerTestOutputs
steps: Record
env: Record
settings: Record
@@ -1619,7 +1610,8 @@ export const evaluationContext: Readable = derived(
const results: TestAutomationResponse | undefined =
$selectedAutomation?.testResults
- const testData = $selectedAutomation.data?.testData || {}
+ const testData: TriggerTestOutputs | undefined =
+ $selectedAutomation.data?.testData
const triggerDef = $selectedAutomation.data?.definition?.trigger
const isWebhook = triggerDef?.stepId! === TriggerStepID.WEBHOOK
@@ -1629,36 +1621,50 @@ export const evaluationContext: Readable = derived(
? $tables.list.find(table => table._id === rowActionTableId)
: undefined
- // Needs a clone to avoid state mutation.
- const triggerData: TriggerContext = cloneDeep(
- results?.trigger?.outputs || testData
- )
+ let triggerData: TriggerTestOutputs | undefined
- if (isRowAction && rowActionTable) {
- // Row action table must always be retrieved as it is never
- // returned in the test results
- triggerData.table = rowActionTable
- } else if (isWebhook) {
- // Ensure it displays in the event that the configuration have been skipped
- triggerData.body = triggerData.body ?? {}
+ if (results && isAutomationResults(results)) {
+ const automationTrigger: AutomationTestTrigger | undefined =
+ results?.trigger
+
+ const outputs: TriggerTestOutputs | undefined = automationTrigger?.outputs
+ triggerData = outputs ? outputs : undefined
+
+ if (triggerData) {
+ if (isRowAction && rowActionTable) {
+ const rowTrigger = triggerData as RowActionTriggerOutputs
+ // Row action table must always be retrieved as it is never
+ // returned in the test results
+ rowTrigger.table = rowActionTable
+ } else if (isWebhook) {
+ const webhookTrigger = triggerData as WebhookTriggerOutputs
+ // Ensure it displays in the event that the configuration have been skipped
+ webhookTrigger.body = webhookTrigger.body ?? {}
+ }
+ }
+
+ // Clean up unnecessary data from the context
+ // Meta contains UI/UX config data. Non-bindable
+ delete triggerData?.meta
+ } else {
+ // Substitute test data in place of the trigger data if the test hasn't been run
+ triggerData = testData
}
- // Clean up unnecessary data from the context
- // Meta contains UI/UX config data. Non-bindable
- delete triggerData?.meta
-
// AppSelf context required to mirror server user context
const userContext = $selectedAutomation.appSelf || {}
+ // Extract step results from a valid response
+ const stepResults =
+ results && isAutomationResults(results) ? results?.steps : []
+
return {
user: userContext,
- trigger: {
- ...triggerData,
- },
-
+ // Merge in the trigger data.
+ ...(triggerData ? { trigger: { ...triggerData } } : {}),
// This will initially be empty for each step but will populate
// upon running the test.
- steps: (results?.steps || []).reduce(
+ steps: stepResults.reduce(
(acc: Record, res: Record) => {
acc[res.id] = res.outputs
return acc
diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts
index b4c1fa9854..85ec351b72 100644
--- a/packages/server/src/api/routes/tests/automation.spec.ts
+++ b/packages/server/src/api/routes/tests/automation.spec.ts
@@ -11,6 +11,7 @@ import {
import { configs, context, events } from "@budibase/backend-core"
import sdk from "../../../sdk"
import {
+ AutomationResults,
ConfigType,
FieldType,
isDidNotTriggerResponse,
@@ -615,7 +616,7 @@ describe("/automations", () => {
})
)
- const res = await config.api.automation.test(automation._id!, {
+ const response = await config.api.automation.test(automation._id!, {
fields: {},
oldRow: {
City: oldCity,
@@ -625,12 +626,14 @@ describe("/automations", () => {
},
})
- if (isDidNotTriggerResponse(res)) {
+ if (isDidNotTriggerResponse(response)) {
throw new Error("Automation did not trigger")
}
+ const results: AutomationResults = response as AutomationResults
+
const expectedResult = oldCity === newCity
- expect(res.steps[1].outputs.result).toEqual(expectedResult)
+ expect(results.steps[1].outputs.result).toEqual(expectedResult)
}
)
})
@@ -717,7 +720,8 @@ describe("/automations", () => {
if (isDidNotTriggerResponse(res)) {
expect(expectToRun).toEqual(false)
} else {
- expect(res.steps[1].outputs.success).toEqual(expectToRun)
+ const results: AutomationResults = res as AutomationResults
+ expect(results.steps[1].outputs.success).toEqual(expectToRun)
}
}
)
diff --git a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts
index 151caab519..058c71dfc0 100644
--- a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts
+++ b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts
@@ -6,6 +6,7 @@ import {
AppActionTriggerOutputs,
Automation,
AutomationActionStepId,
+ AutomationResults,
AutomationStep,
AutomationStepInputs,
AutomationTrigger,
@@ -421,11 +422,11 @@ class AutomationBuilder extends BaseStepBuilder {
if (isDidNotTriggerResponse(response)) {
throw new Error(response.message)
}
-
- response.steps.shift()
+ const results: AutomationResults = response as AutomationResults
+ results.steps.shift()
return {
- trigger: response.trigger,
- steps: response.steps,
+ trigger: results.trigger,
+ steps: results.steps,
}
}
}
diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts
index a9317772d9..451c5add64 100644
--- a/packages/server/src/automations/triggers.ts
+++ b/packages/server/src/automations/triggers.ts
@@ -22,6 +22,7 @@ import {
UserBindings,
AutomationResults,
DidNotTriggerResponse,
+ Table,
} from "@budibase/types"
import { executeInThread } from "../threads/automation"
import { dataFilters, sdk } from "@budibase/shared-core"
@@ -154,6 +155,7 @@ interface AutomationTriggerParams {
timeout?: number
appId?: string
user?: UserBindings
+ table?: Table
}
export async function externalTrigger(
diff --git a/packages/types/src/api/web/app/automation.ts b/packages/types/src/api/web/app/automation.ts
index bbfe11a8e5..f7b0792cb2 100644
--- a/packages/types/src/api/web/app/automation.ts
+++ b/packages/types/src/api/web/app/automation.ts
@@ -85,6 +85,17 @@ export function isDidNotTriggerResponse(
return !!("message" in response && response.message)
}
+export function isAutomationResults(
+ response: TestAutomationResponse
+): response is AutomationResults {
+ return !!(
+ "steps" in response &&
+ response.steps &&
+ "trigger" in response &&
+ response.trigger
+ )
+}
+
export type TestAutomationResponse =
| AutomationResults
| DidNotTriggerResponse
diff --git a/packages/types/src/documents/app/automation/StepInputsOutputs.ts b/packages/types/src/documents/app/automation/StepInputsOutputs.ts
index 6f7223300d..2c8203d8b8 100644
--- a/packages/types/src/documents/app/automation/StepInputsOutputs.ts
+++ b/packages/types/src/documents/app/automation/StepInputsOutputs.ts
@@ -1,3 +1,4 @@
+import { Table } from "@budibase/types"
import { SortOrder } from "../../../api"
import {
SearchFilters,
@@ -296,6 +297,7 @@ export type RowUpdatedTriggerOutputs = {
row: Row
id: string
revision?: string
+ oldRow: Row
}
export type WebhookTriggerInputs = {
@@ -303,6 +305,17 @@ export type WebhookTriggerInputs = {
triggerUrl: string
}
-export type WebhookTriggerOutputs = {
- fields: Record
+export type WebhookTriggerOutputs = Record & {
+ body: Record
+}
+
+export type RowActionTriggerInputs = {
+ tableId: string
+}
+
+export type RowActionTriggerOutputs = {
+ row: Row
+ id: string
+ revision?: string
+ table: Table
}
diff --git a/packages/types/src/documents/app/automation/automation.ts b/packages/types/src/documents/app/automation/automation.ts
index 56654b10ca..389cd9b583 100644
--- a/packages/types/src/documents/app/automation/automation.ts
+++ b/packages/types/src/documents/app/automation/automation.ts
@@ -5,6 +5,16 @@ import { Row } from "../row"
import { Table } from "../table"
import { AutomationStep, AutomationTrigger } from "./schema"
import { ContextEmitter } from "../../../sdk"
+import {
+ AppActionTriggerOutputs,
+ AppSelfResponse,
+ CronTriggerOutputs,
+ RowActionTriggerOutputs,
+ RowCreatedTriggerInputs,
+ RowDeletedTriggerInputs,
+ RowUpdatedTriggerOutputs,
+ WebhookTriggerOutputs,
+} from "@budibase/types"
export enum AutomationIOType {
OBJECT = "object",
@@ -136,15 +146,7 @@ export interface Automation extends Document {
internal?: boolean
type?: string
disabled?: boolean
- testData?: {
- row?: Row
- meta: {
- [key: string]: unknown
- }
- id: string
- revision: string
- oldRow?: Row
- }
+ testData?: TriggerTestOutputs
}
interface BaseIOStructure {
@@ -191,10 +193,36 @@ export enum AutomationStoppedReason {
TRIGGER_FILTER_NOT_MET = "Automation did not run. Filter conditions in trigger were not met.",
}
+// UI and context fields
+export type AutomationResultFields = {
+ meta?: {
+ [key: string]: unknown
+ }
+ user?: AppSelfResponse
+ automation?: Automation
+}
+
+// Base types for Trigger outputs combined with UI and context fields
+export type TriggerTestOutputs =
+ | (WebhookTriggerOutputs & AutomationResultFields)
+ | (AppActionTriggerOutputs & AutomationResultFields)
+ | (CronTriggerOutputs & AutomationResultFields)
+ | (RowActionTriggerOutputs & AutomationResultFields)
+ | (RowDeletedTriggerInputs & AutomationResultFields)
+ | (RowCreatedTriggerInputs & AutomationResultFields)
+ | (RowUpdatedTriggerOutputs & AutomationResultFields)
+
+export type AutomationTestTrigger = {
+ id: string
+ inputs: null
+ stepId: AutomationTriggerStepId
+ outputs: TriggerTestOutputs
+}
+
export interface AutomationResults {
automationId?: string
status?: AutomationStatus
- trigger?: AutomationTrigger
+ trigger?: AutomationTestTrigger
steps: {
stepId: AutomationTriggerStepId | AutomationActionStepId
inputs: {
diff --git a/packages/types/src/sdk/automations/index.ts b/packages/types/src/sdk/automations/index.ts
index 605bbd5069..ba79d47021 100644
--- a/packages/types/src/sdk/automations/index.ts
+++ b/packages/types/src/sdk/automations/index.ts
@@ -1,8 +1,6 @@
import {
Automation,
AutomationMetadata,
- AutomationStatus,
- AutomationStoppedReason,
Row,
UserBindings,
} from "../../documents"
@@ -31,11 +29,3 @@ export interface AutomationRowEvent {
}
export type AutomationJob = Job
-
-export type DidNotTriggerResponse = {
- outputs: {
- success: false
- status: AutomationStatus.STOPPED
- }
- message: AutomationStoppedReason.TRIGGER_FILTER_NOT_MET
-}