+
onChange(
@@ -129,16 +129,18 @@
},
field
)}
- object={handleAttachmentParams(value[field])}
+ object={handleAttachmentParams(value[field] || {})}
allowJS
{bindings}
keyBindings
- customButtonText={"Add attachment"}
+ customButtonText={schema.type === FieldType.SIGNATURE_SINGLE
+ ? "Add signature"
+ : "Add attachment"}
keyPlaceholder={"URL"}
valuePlaceholder={"Filename"}
actionButtonDisabled={(schema.type === FieldType.ATTACHMENT_SINGLE ||
- schema.type === FieldType.SIGNATURE) &&
- Object.keys(value[field]).length >= 1}
+ schema.type === FieldType.SIGNATURE_SINGLE) &&
+ Object.keys(value[field] || {}).length >= 1}
/>
{:else if ["string", "number", "bigint", "barcodeqr", "array"].includes(schema.type)}
@@ -152,12 +154,15 @@
allowJS={true}
updateOnChange={false}
title={schema.name}
+ autocomplete="off"
/>
{/if}
diff --git a/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte b/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte
index c278c7d0e3..74bfe27b29 100644
--- a/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte
@@ -8,6 +8,7 @@
export let value
export let isTrigger
+ export let disabled = false
$: filteredTables = $tables.list.filter(table => {
return !isTrigger || table._id !== TableNames.USERS
@@ -25,4 +26,5 @@
options={filteredTables}
getOptionLabel={table => table.name}
getOptionValue={table => table._id}
+ {disabled}
/>
diff --git a/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte b/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte
index 0cb10d1aa5..9c482dbc0a 100644
--- a/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte
+++ b/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte
@@ -23,6 +23,7 @@
export let disableBindings = false
export let forceModal = false
export let context = null
+ export let autocomplete
const dispatch = createEventDispatcher()
@@ -71,6 +72,7 @@
on:blur={onBlur}
{placeholder}
{updateOnChange}
+ {autocomplete}
/>
{#if !disabled && !disableBindings}
generateAttachmentRow(attachment))
diff --git a/packages/server/src/automations/steps/updateRow.ts b/packages/server/src/automations/steps/updateRow.ts
index 32c8addd7a..87edff93d0 100644
--- a/packages/server/src/automations/steps/updateRow.ts
+++ b/packages/server/src/automations/steps/updateRow.ts
@@ -82,39 +82,58 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
}
const tableId = inputs.row.tableId
- // clear any undefined, null or empty string properties so that they aren't updated
- for (let propKey of Object.keys(inputs.row)) {
- const clearRelationships =
- inputs.meta?.fields?.[propKey]?.clearRelationships
- if (
- (inputs.row[propKey] == null || inputs.row[propKey]?.length === 0) &&
- !clearRelationships
- ) {
- delete inputs.row[propKey]
+ // Base update
+ let rowUpdate: Record = {
+ tableId,
+ }
+
+ // Column checking - explicit clearing of empty fields
+ if (inputs?.meta?.columns) {
+ rowUpdate = inputs?.meta?.columns.reduce(
+ (acc: Record, key: string) => {
+ acc[key] =
+ !inputs.row[key] || inputs.row[key]?.length === 0
+ ? null
+ : inputs.row[key]
+ return acc
+ },
+ {}
+ )
+ } else {
+ // Legacy - clear any empty string column values so that they aren't updated
+ rowUpdate = {
+ ...inputs.row,
+ }
+ for (let propKey of Object.keys(rowUpdate)) {
+ const clearRelationships =
+ inputs.meta?.fields?.[propKey]?.clearRelationships
+ if (
+ (rowUpdate[propKey] == null || rowUpdate[propKey]?.length === 0) &&
+ !clearRelationships
+ ) {
+ delete rowUpdate[propKey]
+ }
}
}
try {
if (tableId) {
- inputs.row = await automationUtils.cleanUpRow(
- inputs.row.tableId,
- inputs.row
- )
+ rowUpdate = await automationUtils.cleanUpRow(tableId, rowUpdate)
- inputs.row = await automationUtils.sendAutomationAttachmentsToStorage(
- inputs.row.tableId,
- inputs.row
+ rowUpdate = await automationUtils.sendAutomationAttachmentsToStorage(
+ tableId,
+ rowUpdate
)
}
// have to clean up the row, remove the table from it
const ctx: any = buildCtx(appId, emitter, {
body: {
- ...inputs.row,
+ ...rowUpdate,
_id: inputs.rowId,
},
params: {
rowId: inputs.rowId,
- tableId: tableId,
+ tableId,
},
})
await rowController.patch(ctx)
diff --git a/packages/server/src/automations/triggerInfo/app.ts b/packages/server/src/automations/triggerInfo/app.ts
index abc1463f1a..bfd284cc53 100644
--- a/packages/server/src/automations/triggerInfo/app.ts
+++ b/packages/server/src/automations/triggerInfo/app.ts
@@ -4,11 +4,12 @@ import {
AutomationStepType,
AutomationTriggerSchema,
AutomationTriggerStepId,
+ AutomationEventType,
} from "@budibase/types"
export const definition: AutomationTriggerSchema = {
name: "App Action",
- event: "app:trigger",
+ event: AutomationEventType.APP_TRIGGER,
icon: "Apps",
tagline: "Automation fired from the frontend",
description: "Trigger an automation from an action inside your app",
diff --git a/packages/server/src/automations/triggerInfo/cron.ts b/packages/server/src/automations/triggerInfo/cron.ts
index 1c47aeaeec..be4b60cb27 100644
--- a/packages/server/src/automations/triggerInfo/cron.ts
+++ b/packages/server/src/automations/triggerInfo/cron.ts
@@ -4,11 +4,12 @@ import {
AutomationStepType,
AutomationTriggerSchema,
AutomationTriggerStepId,
+ AutomationEventType,
} from "@budibase/types"
export const definition: AutomationTriggerSchema = {
name: "Cron Trigger",
- event: "cron:trigger",
+ event: AutomationEventType.CRON_TRIGGER,
icon: "Clock",
tagline: "Cron Trigger ({{inputs.cron}})",
description: "Triggers automation on a cron schedule.",
diff --git a/packages/server/src/automations/triggerInfo/rowDeleted.ts b/packages/server/src/automations/triggerInfo/rowDeleted.ts
index e1014f3dbc..06e53ce63f 100644
--- a/packages/server/src/automations/triggerInfo/rowDeleted.ts
+++ b/packages/server/src/automations/triggerInfo/rowDeleted.ts
@@ -4,11 +4,12 @@ import {
AutomationStepType,
AutomationTriggerSchema,
AutomationTriggerStepId,
+ AutomationEventType,
} from "@budibase/types"
export const definition: AutomationTriggerSchema = {
name: "Row Deleted",
- event: "row:delete",
+ event: AutomationEventType.ROW_DELETE,
icon: "TableRowRemoveCenter",
tagline: "Row is deleted from {{inputs.enriched.table.name}}",
description: "Fired when a row is deleted from your database",
diff --git a/packages/server/src/automations/triggerInfo/rowSaved.ts b/packages/server/src/automations/triggerInfo/rowSaved.ts
index faa32ef96e..81cb098b69 100644
--- a/packages/server/src/automations/triggerInfo/rowSaved.ts
+++ b/packages/server/src/automations/triggerInfo/rowSaved.ts
@@ -4,11 +4,12 @@ import {
AutomationStepType,
AutomationTriggerSchema,
AutomationTriggerStepId,
+ AutomationEventType,
} from "@budibase/types"
export const definition: AutomationTriggerSchema = {
name: "Row Created",
- event: "row:save",
+ event: AutomationEventType.ROW_SAVE,
icon: "TableRowAddBottom",
tagline: "Row is added to {{inputs.enriched.table.name}}",
description: "Fired when a row is added to your database",
diff --git a/packages/server/src/automations/triggerInfo/rowUpdated.ts b/packages/server/src/automations/triggerInfo/rowUpdated.ts
index 5e60015808..3306077e98 100644
--- a/packages/server/src/automations/triggerInfo/rowUpdated.ts
+++ b/packages/server/src/automations/triggerInfo/rowUpdated.ts
@@ -4,11 +4,12 @@ import {
AutomationStepType,
AutomationTriggerSchema,
AutomationTriggerStepId,
+ AutomationEventType,
} from "@budibase/types"
export const definition: AutomationTriggerSchema = {
name: "Row Updated",
- event: "row:update",
+ event: AutomationEventType.ROW_UPDATE,
icon: "Refresh",
tagline: "Row is updated in {{inputs.enriched.table.name}}",
description: "Fired when a row is updated in your database",
diff --git a/packages/server/src/automations/triggerInfo/webhook.ts b/packages/server/src/automations/triggerInfo/webhook.ts
index 310dd66b41..b97c76ec61 100644
--- a/packages/server/src/automations/triggerInfo/webhook.ts
+++ b/packages/server/src/automations/triggerInfo/webhook.ts
@@ -4,11 +4,12 @@ import {
AutomationStepType,
AutomationTriggerSchema,
AutomationTriggerStepId,
+ AutomationEventType,
} from "@budibase/types"
export const definition: AutomationTriggerSchema = {
name: "Webhook",
- event: "web:trigger",
+ event: AutomationEventType.WEBHOOK_TRIGGER,
icon: "Send",
tagline: "Webhook endpoint is hit",
description: "Trigger an automation when a HTTP POST webhook is hit",
diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts
index 223b8d2eb6..dd886a2494 100644
--- a/packages/server/src/automations/triggers.ts
+++ b/packages/server/src/automations/triggers.ts
@@ -8,7 +8,13 @@ import { checkTestFlag } from "../utilities/redis"
import * as utils from "./utils"
import env from "../environment"
import { context, db as dbCore } from "@budibase/backend-core"
-import { Automation, Row, AutomationData, AutomationJob } from "@budibase/types"
+import {
+ Automation,
+ Row,
+ AutomationData,
+ AutomationJob,
+ AutomationEventType,
+} from "@budibase/types"
import { executeInThread } from "../threads/automation"
export const TRIGGER_DEFINITIONS = definitions
@@ -65,28 +71,28 @@ async function queueRelevantRowAutomations(
})
}
-emitter.on("row:save", async function (event) {
+emitter.on(AutomationEventType.ROW_SAVE, async function (event) {
/* istanbul ignore next */
if (!event || !event.row || !event.row.tableId) {
return
}
- await queueRelevantRowAutomations(event, "row:save")
+ await queueRelevantRowAutomations(event, AutomationEventType.ROW_SAVE)
})
-emitter.on("row:update", async function (event) {
+emitter.on(AutomationEventType.ROW_UPDATE, async function (event) {
/* istanbul ignore next */
if (!event || !event.row || !event.row.tableId) {
return
}
- await queueRelevantRowAutomations(event, "row:update")
+ await queueRelevantRowAutomations(event, AutomationEventType.ROW_UPDATE)
})
-emitter.on("row:delete", async function (event) {
+emitter.on(AutomationEventType.ROW_DELETE, async function (event) {
/* istanbul ignore next */
if (!event || !event.row || !event.row.tableId) {
return
}
- await queueRelevantRowAutomations(event, "row:delete")
+ await queueRelevantRowAutomations(event, AutomationEventType.ROW_DELETE)
})
export async function externalTrigger(
@@ -112,7 +118,6 @@ export async function externalTrigger(
}
params.fields = coercedFields
}
-
const data: AutomationData = { automation, event: params as any }
if (getResponses) {
data.event = {
diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts
index 7213cc66f1..ff550d0cb6 100644
--- a/packages/server/src/tests/utilities/structures.ts
+++ b/packages/server/src/tests/utilities/structures.ts
@@ -24,6 +24,7 @@ import {
Query,
Webhook,
WebhookActionType,
+ AutomationEventType,
} from "@budibase/types"
import { LoopInput, LoopStepType } from "../../definitions/automations"
import { merge } from "lodash"
@@ -305,7 +306,7 @@ export function loopAutomation(
trigger: {
id: "a",
type: "TRIGGER",
- event: "row:save",
+ event: AutomationEventType.ROW_SAVE,
stepId: AutomationTriggerStepId.ROW_SAVED,
inputs: {
tableId,
@@ -347,7 +348,7 @@ export function collectAutomation(tableId?: string): Automation {
trigger: {
id: "a",
type: "TRIGGER",
- event: "row:save",
+ event: AutomationEventType.ROW_SAVE,
stepId: AutomationTriggerStepId.ROW_SAVED,
inputs: {
tableId,
diff --git a/packages/types/src/documents/app/automation.ts b/packages/types/src/documents/app/automation.ts
index 63291fa3bb..00114f1ebd 100644
--- a/packages/types/src/documents/app/automation.ts
+++ b/packages/types/src/documents/app/automation.ts
@@ -252,3 +252,12 @@ export type BucketedContent = AutomationAttachmentContent & {
bucket: string
path: string
}
+
+export enum AutomationEventType {
+ ROW_SAVE = "row:save",
+ ROW_UPDATE = "row:update",
+ ROW_DELETE = "row:delete",
+ APP_TRIGGER = "app:trigger",
+ CRON_TRIGGER = "cron:trigger",
+ WEBHOOK_TRIGGER = "web:trigger",
+}