From ee5d19456e2b95121afe872226f4519d9358f6f8 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 30 Jan 2025 10:46:54 +0000 Subject: [PATCH] Lint and tidying --- .../common/bindings/CodeEditorField.svelte | 17 ---- .../builder/src/stores/builder/automations.ts | 86 ++++++++++--------- .../src/api/routes/tests/automation.spec.ts | 12 ++- .../tests/utilities/AutomationTestBuilder.ts | 9 +- packages/server/src/automations/triggers.ts | 2 + packages/types/src/api/web/app/automation.ts | 11 +++ .../app/automation/StepInputsOutputs.ts | 17 +++- .../documents/app/automation/automation.ts | 48 ++++++++--- packages/types/src/sdk/automations/index.ts | 10 --- 9 files changed, 125 insertions(+), 87 deletions(-) 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 -}