Lint and tidying

This commit is contained in:
Dean 2025-01-30 10:46:54 +00:00
parent 9f856d13c6
commit ee5d19456e
9 changed files with 125 additions and 87 deletions

View File

@ -40,8 +40,6 @@
export let autofocusEditor = false export let autofocusEditor = false
export let placeholder = null export let placeholder = null
let mode: BindingMode | null
let initialValueJS = value?.startsWith?.("{{ js ")
let getCaretPosition: CaretPositionFn | undefined let getCaretPosition: CaretPositionFn | undefined
let insertAtPos: InsertAtPositionFn | undefined let insertAtPos: InsertAtPositionFn | undefined
@ -141,9 +139,6 @@
} }
const onChangeJSValue = (e: { detail: string }) => { const onChangeJSValue = (e: { detail: string }) => {
// if(typeof onChange === "function"){
// }
if (!e.detail?.trim()) { if (!e.detail?.trim()) {
// Don't bother saving empty values as JS // Don't bother saving empty values as JS
updateValue(null) updateValue(null)
@ -151,18 +146,6 @@
updateValue(encodeJSBinding(e.detail)) 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]
}
})
</script> </script>
<div class="code-panel"> <div class="code-panel">

View File

@ -1,9 +1,9 @@
import { derived, get, Readable, Writable } from "svelte/store" import { derived, get, Readable } from "svelte/store"
import { API } from "@/api" import { API } from "@/api"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { generate } from "shortid" import { generate } from "shortid"
import { createHistoryStore } from "@/stores/builder/history" 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 { tables, appStore } from "@/stores/builder"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import { import {
@ -34,6 +34,11 @@ import {
GetAutomationActionDefinitionsResponse, GetAutomationActionDefinitionsResponse,
AppSelfResponse, AppSelfResponse,
TestAutomationResponse, TestAutomationResponse,
isAutomationResults,
AutomationTestTrigger,
TriggerTestOutputs,
RowActionTriggerOutputs,
WebhookTriggerOutputs,
} from "@budibase/types" } from "@budibase/types"
import { ActionStepID, TriggerStepID } from "@/constants/backend/automations" import { ActionStepID, TriggerStepID } from "@/constants/backend/automations"
import { FIELDS } from "@/constants/backend" import { FIELDS } from "@/constants/backend"
@ -100,7 +105,7 @@ const automationActions = (store: AutomationStore) => ({
const appSelfResponse = await API.fetchSelf() const appSelfResponse = await API.fetchSelf()
store.update(state => ({ store.update(state => ({
...state, ...state,
appSelf: appSelfResponse, ...(appSelfResponse ? { appSelf: appSelfResponse } : {}),
})) }))
return appSelfResponse return appSelfResponse
}, },
@ -882,12 +887,7 @@ const automationActions = (store: AutomationStore) => ({
const message = err.message || err.status || JSON.stringify(err) const message = err.message || err.status || JSON.stringify(err)
throw `Automation test failed - ${message}` 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 => { store.update(state => {
state.testResults = result state.testResults = result
return state return state
@ -1594,18 +1594,9 @@ export class SelectedAutomationStore extends DerivedBudiStore<
} }
export const selectedAutomation = new SelectedAutomationStore(automationStore) export const selectedAutomation = new SelectedAutomationStore(automationStore)
type TriggerContext = AutomationTrigger & {
meta?: Record<any, any>
table?: Table
body?: Record<any, any>
row?: Record<any, any>
oldRow?: Record<any, any>
outputs?: Record<any, any>
}
export interface AutomationContext { export interface AutomationContext {
user: AppSelfResponse user: AppSelfResponse
trigger: TriggerContext trigger?: TriggerTestOutputs
steps: Record<string, AutomationStep> steps: Record<string, AutomationStep>
env: Record<string, any> env: Record<string, any>
settings: Record<string, any> settings: Record<string, any>
@ -1619,7 +1610,8 @@ export const evaluationContext: Readable<AutomationContext> = derived(
const results: TestAutomationResponse | undefined = const results: TestAutomationResponse | undefined =
$selectedAutomation?.testResults $selectedAutomation?.testResults
const testData = $selectedAutomation.data?.testData || {} const testData: TriggerTestOutputs | undefined =
$selectedAutomation.data?.testData
const triggerDef = $selectedAutomation.data?.definition?.trigger const triggerDef = $selectedAutomation.data?.definition?.trigger
const isWebhook = triggerDef?.stepId! === TriggerStepID.WEBHOOK const isWebhook = triggerDef?.stepId! === TriggerStepID.WEBHOOK
@ -1629,36 +1621,50 @@ export const evaluationContext: Readable<AutomationContext> = derived(
? $tables.list.find(table => table._id === rowActionTableId) ? $tables.list.find(table => table._id === rowActionTableId)
: undefined : undefined
// Needs a clone to avoid state mutation. let triggerData: TriggerTestOutputs | undefined
const triggerData: TriggerContext = cloneDeep(
results?.trigger?.outputs || testData
)
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) { if (isRowAction && rowActionTable) {
const rowTrigger = triggerData as RowActionTriggerOutputs
// Row action table must always be retrieved as it is never // Row action table must always be retrieved as it is never
// returned in the test results // returned in the test results
triggerData.table = rowActionTable rowTrigger.table = rowActionTable
} else if (isWebhook) { } else if (isWebhook) {
const webhookTrigger = triggerData as WebhookTriggerOutputs
// Ensure it displays in the event that the configuration have been skipped // Ensure it displays in the event that the configuration have been skipped
triggerData.body = triggerData.body ?? {} webhookTrigger.body = webhookTrigger.body ?? {}
}
} }
// Clean up unnecessary data from the context // Clean up unnecessary data from the context
// Meta contains UI/UX config data. Non-bindable // Meta contains UI/UX config data. Non-bindable
delete triggerData?.meta delete triggerData?.meta
} else {
// Substitute test data in place of the trigger data if the test hasn't been run
triggerData = testData
}
// AppSelf context required to mirror server user context // AppSelf context required to mirror server user context
const userContext = $selectedAutomation.appSelf || {} const userContext = $selectedAutomation.appSelf || {}
// Extract step results from a valid response
const stepResults =
results && isAutomationResults(results) ? results?.steps : []
return { return {
user: userContext, user: userContext,
trigger: { // Merge in the trigger data.
...triggerData, ...(triggerData ? { trigger: { ...triggerData } } : {}),
},
// This will initially be empty for each step but will populate // This will initially be empty for each step but will populate
// upon running the test. // upon running the test.
steps: (results?.steps || []).reduce( steps: stepResults.reduce(
(acc: Record<string, any>, res: Record<string, any>) => { (acc: Record<string, any>, res: Record<string, any>) => {
acc[res.id] = res.outputs acc[res.id] = res.outputs
return acc return acc

View File

@ -11,6 +11,7 @@ import {
import { configs, context, events } from "@budibase/backend-core" import { configs, context, events } from "@budibase/backend-core"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import { import {
AutomationResults,
ConfigType, ConfigType,
FieldType, FieldType,
isDidNotTriggerResponse, 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: {}, fields: {},
oldRow: { oldRow: {
City: oldCity, City: oldCity,
@ -625,12 +626,14 @@ describe("/automations", () => {
}, },
}) })
if (isDidNotTriggerResponse(res)) { if (isDidNotTriggerResponse(response)) {
throw new Error("Automation did not trigger") throw new Error("Automation did not trigger")
} }
const results: AutomationResults = response as AutomationResults
const expectedResult = oldCity === newCity 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)) { if (isDidNotTriggerResponse(res)) {
expect(expectToRun).toEqual(false) expect(expectToRun).toEqual(false)
} else { } else {
expect(res.steps[1].outputs.success).toEqual(expectToRun) const results: AutomationResults = res as AutomationResults
expect(results.steps[1].outputs.success).toEqual(expectToRun)
} }
} }
) )

View File

@ -6,6 +6,7 @@ import {
AppActionTriggerOutputs, AppActionTriggerOutputs,
Automation, Automation,
AutomationActionStepId, AutomationActionStepId,
AutomationResults,
AutomationStep, AutomationStep,
AutomationStepInputs, AutomationStepInputs,
AutomationTrigger, AutomationTrigger,
@ -421,11 +422,11 @@ class AutomationBuilder extends BaseStepBuilder {
if (isDidNotTriggerResponse(response)) { if (isDidNotTriggerResponse(response)) {
throw new Error(response.message) throw new Error(response.message)
} }
const results: AutomationResults = response as AutomationResults
response.steps.shift() results.steps.shift()
return { return {
trigger: response.trigger, trigger: results.trigger,
steps: response.steps, steps: results.steps,
} }
} }
} }

View File

@ -22,6 +22,7 @@ import {
UserBindings, UserBindings,
AutomationResults, AutomationResults,
DidNotTriggerResponse, DidNotTriggerResponse,
Table,
} from "@budibase/types" } from "@budibase/types"
import { executeInThread } from "../threads/automation" import { executeInThread } from "../threads/automation"
import { dataFilters, sdk } from "@budibase/shared-core" import { dataFilters, sdk } from "@budibase/shared-core"
@ -154,6 +155,7 @@ interface AutomationTriggerParams {
timeout?: number timeout?: number
appId?: string appId?: string
user?: UserBindings user?: UserBindings
table?: Table
} }
export async function externalTrigger( export async function externalTrigger(

View File

@ -85,6 +85,17 @@ export function isDidNotTriggerResponse(
return !!("message" in response && response.message) 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 = export type TestAutomationResponse =
| AutomationResults | AutomationResults
| DidNotTriggerResponse | DidNotTriggerResponse

View File

@ -1,3 +1,4 @@
import { Table } from "@budibase/types"
import { SortOrder } from "../../../api" import { SortOrder } from "../../../api"
import { import {
SearchFilters, SearchFilters,
@ -296,6 +297,7 @@ export type RowUpdatedTriggerOutputs = {
row: Row row: Row
id: string id: string
revision?: string revision?: string
oldRow: Row
} }
export type WebhookTriggerInputs = { export type WebhookTriggerInputs = {
@ -303,6 +305,17 @@ export type WebhookTriggerInputs = {
triggerUrl: string triggerUrl: string
} }
export type WebhookTriggerOutputs = { export type WebhookTriggerOutputs = Record<string, any> & {
fields: Record<string, any> body: Record<string, any>
}
export type RowActionTriggerInputs = {
tableId: string
}
export type RowActionTriggerOutputs = {
row: Row
id: string
revision?: string
table: Table
} }

View File

@ -5,6 +5,16 @@ import { Row } from "../row"
import { Table } from "../table" import { Table } from "../table"
import { AutomationStep, AutomationTrigger } from "./schema" import { AutomationStep, AutomationTrigger } from "./schema"
import { ContextEmitter } from "../../../sdk" import { ContextEmitter } from "../../../sdk"
import {
AppActionTriggerOutputs,
AppSelfResponse,
CronTriggerOutputs,
RowActionTriggerOutputs,
RowCreatedTriggerInputs,
RowDeletedTriggerInputs,
RowUpdatedTriggerOutputs,
WebhookTriggerOutputs,
} from "@budibase/types"
export enum AutomationIOType { export enum AutomationIOType {
OBJECT = "object", OBJECT = "object",
@ -136,15 +146,7 @@ export interface Automation extends Document {
internal?: boolean internal?: boolean
type?: string type?: string
disabled?: boolean disabled?: boolean
testData?: { testData?: TriggerTestOutputs
row?: Row
meta: {
[key: string]: unknown
}
id: string
revision: string
oldRow?: Row
}
} }
interface BaseIOStructure { interface BaseIOStructure {
@ -191,10 +193,36 @@ export enum AutomationStoppedReason {
TRIGGER_FILTER_NOT_MET = "Automation did not run. Filter conditions in trigger were not met.", 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 { export interface AutomationResults {
automationId?: string automationId?: string
status?: AutomationStatus status?: AutomationStatus
trigger?: AutomationTrigger trigger?: AutomationTestTrigger
steps: { steps: {
stepId: AutomationTriggerStepId | AutomationActionStepId stepId: AutomationTriggerStepId | AutomationActionStepId
inputs: { inputs: {

View File

@ -1,8 +1,6 @@
import { import {
Automation, Automation,
AutomationMetadata, AutomationMetadata,
AutomationStatus,
AutomationStoppedReason,
Row, Row,
UserBindings, UserBindings,
} from "../../documents" } from "../../documents"
@ -31,11 +29,3 @@ export interface AutomationRowEvent {
} }
export type AutomationJob = Job<AutomationData> export type AutomationJob = Job<AutomationData>
export type DidNotTriggerResponse = {
outputs: {
success: false
status: AutomationStatus.STOPPED
}
message: AutomationStoppedReason.TRIGGER_FILTER_NOT_MET
}