Refactor the binding generation to ensure types are processed correctly. Rows were being misrepresented as 'Multi Select'

This commit is contained in:
Dean 2025-02-03 09:06:51 +00:00
parent ef2a2b8bd0
commit a280039dcb
1 changed files with 63 additions and 63 deletions

View File

@ -1,4 +1,4 @@
import { derived, get, Readable } from "svelte/store"
import { derived, get, readable, Readable } from "svelte/store"
import { API } from "@/api"
import { cloneDeep } from "lodash/fp"
import { generate } from "shortid"
@ -39,9 +39,10 @@ import {
TriggerTestOutputs,
RowActionTriggerOutputs,
WebhookTriggerOutputs,
AutomationCustomIOType,
} from "@budibase/types"
import { ActionStepID, TriggerStepID } from "@/constants/backend/automations"
import { FIELDS } from "@/constants/backend"
import { FIELDS as COLUMNS } from "@/constants/backend"
import { sdk } from "@budibase/shared-core"
import { rowActions } from "./rowActions"
import { getNewStepName } from "@/helpers/automations/nameHelpers"
@ -101,11 +102,7 @@ const automationActions = (store: AutomationStore) => ({
*
* @returns {Readable<AutomationContext>}
*/
generateContext: (): Readable<AutomationContext> | undefined => {
if (!organisation || !store.selected || !environment || !tables) {
console.error("Automations: Required context stores are uninitialised")
return
}
generateContext: (): Readable<AutomationContext> => {
return derived(
[organisation, store.selected, environment, tables],
([$organisation, $selectedAutomation, $env, $tables]) => {
@ -653,7 +650,7 @@ const automationActions = (store: AutomationStore) => ({
let bindings: any[] = []
const addBinding = (
name: string,
value: any,
schema: any,
icon: string,
idx: number,
isLoopBlock: boolean,
@ -661,6 +658,7 @@ const automationActions = (store: AutomationStore) => ({
bindingName: string
) => {
if (!name) return
const runtimeBinding = store.actions.determineRuntimeBinding(
name,
idx,
@ -670,6 +668,11 @@ const automationActions = (store: AutomationStore) => ({
pathSteps
)
// Skip binding if its invalid
if (!runtimeBinding) {
return
}
const readableBinding = store.actions.determineReadableBinding(
name,
pathBlock
@ -681,20 +684,38 @@ const automationActions = (store: AutomationStore) => ({
bindingName,
loopBlockCount
)
bindings.push(
store.actions.createBindingObject(
name,
value,
icon,
idx,
loopBlockCount,
isLoopBlock,
runtimeBinding,
categoryName,
bindingName,
readableBinding
)
const isStep = !isLoopBlock && idx !== 0
const defaultReadable =
bindingName && isStep ? `steps.${bindingName}.${name}` : runtimeBinding
// Check if the schema matches any column types.
const column = Object.values(COLUMNS).find(
col =>
col.type === schema.type &&
("subtype" in col ? col.subtype === schema.subtype : true)
)
// Automation types and column types can collide e.g. "array"
// Exclude where necessary
const ignoreColumnType = schema.customType === AutomationCustomIOType.ROWS
// Shown in the bindable menus
const displayType = ignoreColumnType ? schema.type : column?.name
bindings.push({
readableBinding: readableBinding || defaultReadable,
runtimeBinding,
type: schema.type,
description: schema.description,
icon,
category: categoryName,
display: {
type: displayType,
name,
rank: isLoopBlock ? idx + 1 : idx - loopBlockCount,
},
})
}
let loopBlockCount = 0
@ -766,6 +787,7 @@ const automationActions = (store: AutomationStore) => ({
console.error("Loop block missing.")
}
}
Object.entries(schema).forEach(([name, value]) => {
addBinding(
name,
@ -826,7 +848,7 @@ const automationActions = (store: AutomationStore) => ({
currentBlock: AutomationStep | AutomationTrigger | undefined,
pathSteps: (AutomationStep | AutomationTrigger)[]
) => {
let runtimeName: string | null
let runtimeName: string
// Legacy support for EXECUTE_SCRIPT steps
const isJSScript =
@ -863,14 +885,14 @@ const automationActions = (store: AutomationStore) => ({
const stepId = pathSteps[idx].id
if (!stepId) {
notifications.error("Error generating binding: Step ID not found.")
return null
return
}
runtimeName = `steps["${stepId}"].${name}`
} else {
const stepId = pathSteps[idx].id
if (!stepId) {
notifications.error("Error generating binding: Step ID not found.")
return null
return
}
runtimeName = `steps.${stepId}.${name}`
}
@ -891,44 +913,6 @@ const automationActions = (store: AutomationStore) => ({
: `Step ${idx - loopBlockCount} outputs`
},
createBindingObject: (
name: string,
value: any,
icon: string,
idx: number,
loopBlockCount: number,
isLoopBlock: boolean,
runtimeBinding: string | null,
categoryName: string,
bindingName?: string,
readableBinding?: string
) => {
const field = Object.values(FIELDS).find(
field =>
field.type === value.type &&
("subtype" in field ? field.subtype === value.subtype : true)
)
const readableBindingDefault =
bindingName && !isLoopBlock && idx !== 0
? `steps.${bindingName}.${name}`
: runtimeBinding
return {
readableBinding: readableBinding || readableBindingDefault,
runtimeBinding,
type: value.type,
description: value.description,
icon,
category: categoryName,
display: {
type: field?.name || value.type,
name,
rank: isLoopBlock ? idx + 1 : idx - loopBlockCount,
},
}
},
processBlockInputs: async (
block: AutomationStep,
data: Record<string, any>
@ -1706,4 +1690,20 @@ export const automationStore = new AutomationStore()
export const automationHistoryStore = automationStore.history
export const selectedAutomation = automationStore.selected
export const evaluationContext = automationStore.context
// Define an empty evaluate context at the start
const emptyContext: AutomationContext = {
user: {},
steps: {},
env: {},
settings: {},
}
// Page layout kicks off initialisation, subscription happens within the page
export const evaluationContext: Readable<AutomationContext> = readable(
emptyContext,
set => {
const unsubscribe = automationStore.context?.subscribe(set) ?? (() => {})
return () => unsubscribe()
}
)