diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte
index ac1c4f91cb..7898e13ec8 100644
--- a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte
+++ b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte
@@ -61,6 +61,7 @@
selected={automation._id === selectedAutomationId}
on:click={() => selectAutomation(automation._id)}
selectedBy={$userSelectedResourceMap[automation._id]}
+ disabled={automation.disabled}
>
diff --git a/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte b/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte
index 1bc4b0f18e..9465374ae2 100644
--- a/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte
+++ b/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte
@@ -39,6 +39,15 @@
>Duplicate
Edit
+
+ {automation.disabled ? "Activate" : "Pause"}
+
Delete
diff --git a/packages/builder/src/components/backend/DataTable/formula.js b/packages/builder/src/components/backend/DataTable/formula.js
index a179a7c6e1..7220a5ba4f 100644
--- a/packages/builder/src/components/backend/DataTable/formula.js
+++ b/packages/builder/src/components/backend/DataTable/formula.js
@@ -56,7 +56,7 @@ export function getBindings({
)
}
const field = Object.values(FIELDS).find(
- field => field.type === schema.type && field.subtype === schema.subtype
+ field => field.type === schema.type
)
const label = path == null ? column : `${path}.0.${column}`
diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte
index ba5f75083a..0102d8f7a9 100644
--- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte
+++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte
@@ -54,6 +54,7 @@
export let autofocus = false
export let jsBindingWrapping = true
export let readonly = false
+ export let readonlyLineNumbers = false
const dispatch = createEventDispatcher()
@@ -240,6 +241,9 @@
if (readonly) {
complete.push(EditorState.readOnly.of(true))
+ if (readonlyLineNumbers) {
+ complete.push(lineNumbers())
+ }
} else {
complete = [
...complete,
diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte
index 66b21e95a1..5cc6db65a0 100644
--- a/packages/builder/src/components/common/NavItem.svelte
+++ b/packages/builder/src/components/common/NavItem.svelte
@@ -25,6 +25,7 @@
export let selectedBy = null
export let compact = false
export let hovering = false
+ export let disabled = false
const scrollApi = getContext("scroll")
const dispatch = createEventDispatcher()
@@ -74,6 +75,7 @@
class:scrollable
class:highlighted
class:selectedBy
+ class:disabled
on:dragend
on:dragstart
on:dragover
@@ -165,6 +167,9 @@
--avatars-background: var(--spectrum-global-color-gray-300);
color: var(--ink);
}
+ .nav-item.disabled span {
+ color: var(--spectrum-global-color-gray-700);
+ }
.nav-item:hover,
.hovering {
background-color: var(--spectrum-global-color-gray-200);
diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/TriggerAutomation.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/TriggerAutomation.svelte
index 0a52a693c3..5cd5658063 100644
--- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/TriggerAutomation.svelte
+++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/TriggerAutomation.svelte
@@ -24,7 +24,9 @@
parameters
}
$: automations = $automationStore.automations
- .filter(a => a.definition.trigger?.stepId === TriggerStepID.APP)
+ .filter(
+ a => a.definition.trigger?.stepId === TriggerStepID.APP && !a.disabled
+ )
.map(automation => {
const schema = Object.entries(
automation.definition.trigger.inputs.fields || {}
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/index.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/index.svelte
new file mode 100644
index 0000000000..d9714c2e7a
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/index.svelte
@@ -0,0 +1,48 @@
+
+
+
+
+ {#if subject === subjects.column}
+
+ {:else if subject === subjects.support}
+
+ {:else if subject === subjects.stringsAsNumbers}
+
+ {:else if subject === subjects.notRequired}
+
+ {:else if subject === subjects.datesAsNumbers}
+
+ {:else if subject === subjects.scalarJsonOnly}
+
+ {:else if subject === subjects.numbersAsDates}
+
+ {:else if subject === subjects.stringsAsDates}
+
+ {/if}
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Column.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Column.svelte
new file mode 100644
index 0000000000..7fbac09827
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Column.svelte
@@ -0,0 +1,147 @@
+
+
+
+
+ Column Overview for {columnName}
+
+
+ {#if schema.type === "string"}
+
+ {:else if schema.type === "datetime"}
+
+
+
+
+ {:else if schema.type === "number"}
+
+
+ {:else if schema.type === "array"}
+ {#each schema?.constraints?.inclusion ?? [] as option, index}
+
+ {option}
+
+ {/each}
+ {:else if schema.type === "options"}
+ {#each schema?.constraints?.inclusion ?? [] as option, index}
+
+ {option}
+
+ {/each}
+ {:else if schema.type === "json"}
+
+
+
+ {:else if schema.type === "formula"}
+
+
+
+
+ {:else if schema.type === "link"}
+
+ table._id === schema?.tableId)
+ ?.name}
+ />
+
+ {:else if schema.type === "bb_reference"}
+
+ {/if}
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/DatesAsNumbers.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/DatesAsNumbers.svelte
new file mode 100644
index 0000000000..e5cab5dc15
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/DatesAsNumbers.svelte
@@ -0,0 +1,63 @@
+
+
+
+
+ A datetime value can be used in place of a numeric value, but it will be
+ converted to a UNIX time timestamp, which is the number of milliseconds
+ since Jan 1st 1970. A more recent moment in time will be a higher number.
+
+
+
+
+
+ {new Date(946684800000).toLocaleString()}
+
+ {"->"} 946684800000
+
+
+
+ {new Date(1577836800000).toLocaleString()}
+
+ {"->"} 1577836800000
+
+
+ Now {"->"} {timestamp}
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NotRequired.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NotRequired.svelte
new file mode 100644
index 0000000000..f28e9a227e
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NotRequired.svelte
@@ -0,0 +1,11 @@
+
+
+
+
+ A required constraint can be applied to columns to ensure a value
+ is always present. If a column doesn't have this constraint, then its value for
+ a particular row could he missing.
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NumbersAsDates.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NumbersAsDates.svelte
new file mode 100644
index 0000000000..d69228544e
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NumbersAsDates.svelte
@@ -0,0 +1,65 @@
+
+
+
+
+ A number value can be used in place of a datetime value, but it will be
+ parsed as a UNIX time timestamp, which is the number of milliseconds
+ since Jan 1st 1970. A more recent moment in time will be a higher number.
+
+
+
+
+ 946684800000
+ {"->"}
+
+ {new Date(946684800000).toLocaleString()}
+
+
+
+ 1577836800000
+ {"->"}
+
+ {new Date(1577836800000).toLocaleString()}
+
+
+
+ {timestamp}
+ {"->"}
+ Now
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/ScalarJsonOnly.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/ScalarJsonOnly.svelte
new file mode 100644
index 0000000000..11fe3c7838
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/ScalarJsonOnly.svelte
@@ -0,0 +1,71 @@
+
+
+
+
+ JSON objects can't be used here, but any number , string or boolean values nested within said
+ object can be if they are otherwise compatible with the input. These scalar values
+ can be selected from the same menu as this parent and take the form parent.child .
+
+
+ {#if scalarDescendants.length > 0}
+
+ {#each scalarDescendants as descendant}
+
+ {descendant.name} - {descendant.type}
+
+ {/each}
+
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsDates.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsDates.svelte
new file mode 100644
index 0000000000..7303eac7cb
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsDates.svelte
@@ -0,0 +1,107 @@
+
+
+
+
+ A string value can be used in place of a datetime value, but it will be
+ parsed as:
+
+
+ A UNIX time timestamp, which is the number of milliseconds since
+ Jan 1st 1970. A more recent moment in time will be a higher number.
+
+
+
+
+ 946684800000
+ {"->"}
+
+ {new Date(946684800000).toLocaleString()}
+
+
+
+ 1577836800000
+ {"->"}
+
+ {new Date(1577836800000).toLocaleString()}
+
+
+
+ {timestamp}
+ {"->"}
+ Now
+
+
+
+ An ISO 8601 datetime string, which represents an exact moment
+ in time as well as the potentional to store the timezone it occured in.
+
+
+
+
+ 2000-01-01T00:00:00.000Z
+ ↓
+
+ {new Date(946684800000).toLocaleString()}
+
+
+
+ 2000-01-01T00:00:00.000Z
+ ↓
+
+ {new Date(1577836800000).toLocaleString()}
+
+
+
+ {iso}
+ ↓
+ Now
+
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsNumbers.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsNumbers.svelte
new file mode 100644
index 0000000000..e30a450d80
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsNumbers.svelte
@@ -0,0 +1,56 @@
+
+
+
+
+ Text can be used in place of numbers in certain scenarios, but care needs to
+ be taken; if the value isn't purely numerical it may be converted in an
+ unexpected way.
+
+
+
+
+ "100" {"->"} 100
+
+
+ "100k" {"->"} 100
+
+
+ "100,000" {"->"} 100
+
+
+ "100 million" {"->"} 100
+
+
+ "100.9" {"->"} 100.9
+
+
+ "One hundred" {"->"} Error
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Support.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Support.svelte
new file mode 100644
index 0000000000..0419c0ad16
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Support.svelte
@@ -0,0 +1,35 @@
+
+
+
+
+
+ Fully compatible with the input as long as the data is present.
+
+
+
+ Partially compatible with the input, but beware of other caveats
+ mentioned.
+
+
+
+ Incompatible with the component.
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/BindingValue.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/BindingValue.svelte
new file mode 100644
index 0000000000..811283ba51
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/BindingValue.svelte
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Block.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Block.svelte
new file mode 100644
index 0000000000..449b40304d
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Block.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleLine.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleLine.svelte
new file mode 100644
index 0000000000..6dd3e10a39
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleLine.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleSection.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleSection.svelte
new file mode 100644
index 0000000000..4da4f5141b
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleSection.svelte
@@ -0,0 +1,32 @@
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/JSONValue.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/JSONValue.svelte
new file mode 100644
index 0000000000..4703398b2d
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/JSONValue.svelte
@@ -0,0 +1,22 @@
+
+
+
+ {value}
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Property.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Property.svelte
new file mode 100644
index 0000000000..8d6e853ab4
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Property.svelte
@@ -0,0 +1,49 @@
+
+
+
+
+
+ {name}
+
+
+ -
+
+
+ {value}
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Section.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Section.svelte
new file mode 100644
index 0000000000..486e111725
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Section.svelte
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Subject.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Subject.svelte
new file mode 100644
index 0000000000..4e21160cae
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Subject.svelte
@@ -0,0 +1,51 @@
+
+
+
+
+
+ {heading}
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/index.js b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/index.js
new file mode 100644
index 0000000000..d174f4d6cc
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/index.js
@@ -0,0 +1,8 @@
+export { default as Subject } from "./Subject.svelte"
+export { default as Property } from "./Property.svelte"
+export { default as JSONValue } from "./JSONValue.svelte"
+export { default as BindingValue } from "./BindingValue.svelte"
+export { default as Section } from "./Section.svelte"
+export { default as Block } from "./Block.svelte"
+export { default as ExampleSection } from "./ExampleSection.svelte"
+export { default as ExampleLine } from "./ExampleLine.svelte"
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/index.js b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/index.js
new file mode 100644
index 0000000000..c7f54d6415
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/index.js
@@ -0,0 +1,8 @@
+export { default as Column } from "./Column.svelte"
+export { default as NotRequired } from "./NotRequired.svelte"
+export { default as StringsAsNumbers } from "./StringsAsNumbers.svelte"
+export { default as Support } from "./Support.svelte"
+export { default as DatesAsNumbers } from "./DatesAsNumbers.svelte"
+export { default as ScalarJsonOnly } from "./ScalarJsonOnly.svelte"
+export { default as StringsAsDates } from "./StringsAsDates.svelte"
+export { default as NumbersAsDates } from "./NumbersAsDates.svelte"
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/Explanation.svelte b/packages/builder/src/components/design/settings/controls/Explanation/Explanation.svelte
new file mode 100644
index 0000000000..bc45e410c9
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/Explanation.svelte
@@ -0,0 +1,102 @@
+
+
+
+
+
+ {#if messages.includes(messageConstants.stringAsNumber)}
+
+ {/if}
+ {#if messages.includes(messageConstants.notRequired)}
+
+ {/if}
+ {#if messages.includes(messageConstants.jsonPrimitivesOnly)}
+
+ {/if}
+ {#if messages.includes(messageConstants.dateAsNumber)}
+
+ {/if}
+ {#if messages.includes(messageConstants.numberAsDate)}
+
+ {/if}
+ {#if messages.includes(messageConstants.stringAsDate)}
+
+ {/if}
+
+
+{#if detailsModalSubject !== subjects.none}
+
+{/if}
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/explanation.js b/packages/builder/src/components/design/settings/controls/Explanation/explanation.js
new file mode 100644
index 0000000000..4e024c67fc
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/explanation.js
@@ -0,0 +1,100 @@
+export const messages = {
+ jsonPrimitivesOnly: Symbol("explanation-json-primitives-only"),
+ stringAsNumber: Symbol("explanation-string-as-number"),
+ dateAsNumber: Symbol("explanation-date-as-number"),
+ numberAsDate: Symbol("explanation-number-as-date"),
+ stringAsDate: Symbol("explanation-string-as-date"),
+ notRequired: Symbol("explanation-not-required"),
+ contextError: Symbol("explanation-context-error"),
+}
+
+export const support = {
+ unsupported: Symbol("explanation-unsupported"),
+ partialSupport: Symbol("explanation-partialSupport"),
+ supported: Symbol("explanation-supported"),
+}
+
+const getSupport = (type, explanation) => {
+ if (!explanation?.typeSupport) {
+ return support.supported
+ }
+
+ if (
+ explanation?.typeSupport?.supported?.find(
+ mapping => mapping === type || mapping?.type === type
+ )
+ ) {
+ return support.supported
+ }
+
+ if (
+ explanation?.typeSupport?.partialSupport?.find(
+ mapping => mapping === type || mapping?.type === type
+ )
+ ) {
+ return support.partialSupport
+ }
+
+ return support.unsupported
+}
+
+const getSupportMessage = (type, explanation) => {
+ if (!explanation?.typeSupport) {
+ return null
+ }
+
+ const supported = explanation?.typeSupport?.supported?.find(
+ mapping => mapping?.type === type
+ )
+ if (supported) {
+ return messages[supported?.message]
+ }
+
+ const partialSupport = explanation?.typeSupport?.partialSupport?.find(
+ mapping => mapping?.type === type
+ )
+ if (partialSupport) {
+ return messages[partialSupport?.message]
+ }
+
+ const unsupported = explanation?.typeSupport?.unsupported?.find(
+ mapping => mapping?.type === type
+ )
+ if (unsupported) {
+ return messages[unsupported?.message]
+ }
+
+ return null
+}
+
+export const getExplanationMessagesAndSupport = (fieldSchema, explanation) => {
+ try {
+ const explanationMessagesAndSupport = {
+ support: getSupport(fieldSchema.type, explanation),
+ messages: [getSupportMessage(fieldSchema.type, explanation)],
+ }
+
+ const isRequired = fieldSchema?.constraints?.presence?.allowEmpty === false
+ if (!isRequired) {
+ explanationMessagesAndSupport.messages.push(messages.notRequired)
+ }
+
+ return explanationMessagesAndSupport
+ } catch (e) {
+ return {
+ support: support.partialSupport,
+ messages: [messages.contextError],
+ }
+ }
+}
+
+export const getExplanationWithPresets = (explanation, presets) => {
+ if (explanation?.typeSupport?.preset) {
+ return {
+ ...explanation,
+ typeSupport: presets[explanation?.typeSupport?.preset],
+ }
+ }
+
+ return explanation
+}
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/index.js b/packages/builder/src/components/design/settings/controls/Explanation/index.js
new file mode 100644
index 0000000000..5780c1de14
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/index.js
@@ -0,0 +1 @@
+export { default as Explanation } from "./Explanation.svelte"
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/Column.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/Column.svelte
new file mode 100644
index 0000000000..9c3b87f8b9
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/Column.svelte
@@ -0,0 +1,84 @@
+
+
+
+ setExplanationSubject(subjects.column)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ href={tableHref}
+ text={columnName}
+ />
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/DateAsNumber.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/DateAsNumber.svelte
new file mode 100644
index 0000000000..ba5eb9b0e1
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/DateAsNumber.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+ setExplanationSubject(subjects.datesAsNumbers)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ text="UNIX time value"
+ />
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/JSONPrimitivesOnly.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/JSONPrimitivesOnly.svelte
new file mode 100644
index 0000000000..2286c09044
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/JSONPrimitivesOnly.svelte
@@ -0,0 +1,21 @@
+
+
+
+ setExplanationSubject(subjects.scalarJsonOnly)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ >Scalar JSON values
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/NotRequired.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/NotRequired.svelte
new file mode 100644
index 0000000000..e705bd68e6
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/NotRequired.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+ setExplanationSubject(subjects.notRequired)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ text="required"
+ />
+
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/NumberAsDate.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/NumberAsDate.svelte
new file mode 100644
index 0000000000..c6413c13a5
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/NumberAsDate.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+ setExplanationSubject(subjects.numbersAsDates)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ text="UNIX time value"
+ />
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsDate.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsDate.svelte
new file mode 100644
index 0000000000..72267b6f47
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsDate.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+ setExplanationSubject(subjects.stringsAsDates)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ text="UNIX time or ISO 8601 value"
+ />
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsNumber.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsNumber.svelte
new file mode 100644
index 0000000000..937545c1c3
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsNumber.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+ setExplanationSubject(subjects.stringsAsNumbers)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ text="non-numerical values"
+ />
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/Support.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/Support.svelte
new file mode 100644
index 0000000000..848ab208fb
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/Support.svelte
@@ -0,0 +1,59 @@
+
+
+
+ setExplanationSubject(subjects.support)}
+ on:mouseleave={() => setExplanationSubject(subjects.none)}
+ {icon}
+ {color}
+ {text}
+ />
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/index.js b/packages/builder/src/components/design/settings/controls/Explanation/lines/index.js
new file mode 100644
index 0000000000..beff239398
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/index.js
@@ -0,0 +1,8 @@
+export { default as Column } from "./Column.svelte"
+export { default as NotRequired } from "./NotRequired.svelte"
+export { default as StringAsNumber } from "./StringAsNumber.svelte"
+export { default as Support } from "./Support.svelte"
+export { default as JSONPrimitivesOnly } from "./JSONPrimitivesOnly.svelte"
+export { default as DateAsNumber } from "./DateAsNumber.svelte"
+export { default as NumberAsDate } from "./NumberAsDate.svelte"
+export { default as StringAsDate } from "./StringAsDate.svelte"
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/subjects.js b/packages/builder/src/components/design/settings/controls/Explanation/subjects.js
new file mode 100644
index 0000000000..1f94fa6fd0
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/subjects.js
@@ -0,0 +1,13 @@
+const subjects = {
+ column: Symbol("details-modal-column"),
+ support: Symbol("details-modal-support"),
+ stringsAsNumbers: Symbol("details-modal-strings-as-numbers"),
+ datesAsNumbers: Symbol("details-modal-dates-as-numbers"),
+ numbersAsDates: Symbol("explanation-numbers-as-dates"),
+ stringsAsDates: Symbol("explanation-strings-as-dates"),
+ notRequired: Symbol("details-modal-not-required"),
+ scalarJsonOnly: Symbol("explanation-scalar-json-only"),
+ none: Symbol("details-modal-none"),
+}
+
+export default subjects
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Comma.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Comma.svelte
new file mode 100644
index 0000000000..f16bd16054
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Comma.svelte
@@ -0,0 +1,14 @@
+
,
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/DocumentationLink.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/DocumentationLink.svelte
new file mode 100644
index 0000000000..55b9732d4a
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/DocumentationLink.svelte
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+ {text}
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/InfoWord.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/InfoWord.svelte
new file mode 100644
index 0000000000..cac12cbfb5
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/InfoWord.svelte
@@ -0,0 +1,78 @@
+
+
+{#if href !== null}
+
+ {#if icon}
+
+ {/if}
+
+
+ {text}
+
+
+
+{:else}
+
+ {#if icon}
+
+ {/if}
+
+
+ {text}
+
+
+
+{/if}
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Line.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Line.svelte
new file mode 100644
index 0000000000..5d28ba0423
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Line.svelte
@@ -0,0 +1,41 @@
+
+
+
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Period.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Period.svelte
new file mode 100644
index 0000000000..d1bbafe6a6
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Period.svelte
@@ -0,0 +1,13 @@
+
.
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Space.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Space.svelte
new file mode 100644
index 0000000000..b88831d760
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Space.svelte
@@ -0,0 +1,9 @@
+
{" "}
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Text.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Text.svelte
new file mode 100644
index 0000000000..6562c9e864
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Text.svelte
@@ -0,0 +1,64 @@
+
+
+{#each words as word}
+ {#if word === " "}
+
+ {:else if word === ","}
+
+ {:else if word === "."}
+
+ {:else}
+
+ {word}
+
+ {/if}
+{/each}
+
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/index.js b/packages/builder/src/components/design/settings/controls/Explanation/typography/index.js
new file mode 100644
index 0000000000..102b65190d
--- /dev/null
+++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/index.js
@@ -0,0 +1,7 @@
+export { default as Space } from "./Space.svelte"
+export { default as Comma } from "./Comma.svelte"
+export { default as Period } from "./Period.svelte"
+export { default as Text } from "./Text.svelte"
+export { default as InfoWord } from "./InfoWord.svelte"
+export { default as DocumentationLink } from "./DocumentationLink.svelte"
+export { default as Line } from "./Line.svelte"
diff --git a/packages/builder/src/components/design/settings/controls/FieldSelect.svelte b/packages/builder/src/components/design/settings/controls/FieldSelect.svelte
index e50a0e8030..15b67ded18 100644
--- a/packages/builder/src/components/design/settings/controls/FieldSelect.svelte
+++ b/packages/builder/src/components/design/settings/controls/FieldSelect.svelte
@@ -1,12 +1,22 @@
-
+
+
+{#if explanation}
+
+
+
+{/if}
diff --git a/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte b/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte
index d0224fb1db..d6c9a0b1e3 100644
--- a/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte
+++ b/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte
@@ -1,12 +1,22 @@
-
+
+
+{#if explanation}
+
+
+
+{/if}
diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
index 6094c93a26..cd62a97340 100644
--- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
@@ -21,7 +21,7 @@
} from "@budibase/bbui"
import AppActions from "components/deploy/AppActions.svelte"
import { API } from "api"
- import { isActive, goto, layout, redirect } from "@roxi/routify"
+ import { isActive, url, goto, layout, redirect } from "@roxi/routify"
import { capitalise } from "helpers"
import { onMount, onDestroy } from "svelte"
import VerificationPromptBanner from "components/common/VerificationPromptBanner.svelte"
@@ -69,7 +69,7 @@
// e.g. if one of your screens is selected on front end, then
// you browse to backend, when you click frontend, you will be
// brought back to the same screen.
- const topItemNavigate = path => () => {
+ const topItemNavigate = path => {
const activeTopNav = $layout.children.find(c => $isActive(c.path))
if (activeTopNav) {
builderStore.setPreviousTopNavPath(
@@ -136,21 +136,18 @@
{#if $appStore.initialised}
-
- $goto("../../portal/apps")}
- />
-
+
+
+
{#each $layout.children as { path, title }}
topItemNavigate(path)}
title={capitalise(title)}
id={`builder-${title}-tab`}
/>
@@ -201,6 +198,11 @@
diff --git a/packages/client/src/components/app/charts/ApexOptionsBuilder.js b/packages/client/src/components/app/charts/ApexOptionsBuilder.js
deleted file mode 100644
index 04b5805df3..0000000000
--- a/packages/client/src/components/app/charts/ApexOptionsBuilder.js
+++ /dev/null
@@ -1,195 +0,0 @@
-export class ApexOptionsBuilder {
- constructor() {
- this.formatters = {
- ["Default"]: val => (isNaN(val) ? val : Math.round(val * 100) / 100),
- ["Thousands"]: val => `${Math.round(val / 1000)}K`,
- ["Millions"]: val => `${Math.round(val / 1000000)}M`,
- }
- this.options = {
- series: [],
- legend: {
- show: false,
- position: "top",
- horizontalAlign: "right",
- showForSingleSeries: true,
- showForNullSeries: true,
- showForZeroSeries: true,
- },
- chart: {
- toolbar: {
- show: false,
- },
- zoom: {
- enabled: false,
- },
- },
- xaxis: {
- labels: {
- formatter: this.formatters.Default,
- },
- },
- yaxis: {
- labels: {
- formatter: this.formatters.Default,
- },
- },
- }
- }
-
- setOption(path, value) {
- if (value == null || value === "") {
- return this
- }
- let tmp = this.options
- for (let i = 0; i < path.length - 1; i++) {
- const step = path[i]
- if (!tmp[step]) {
- tmp[step] = {}
- }
- tmp = tmp[step]
- }
- tmp[path[path.length - 1]] = value
- return this
- }
-
- getOptions() {
- return this.options
- }
-
- type(type) {
- return this.setOption(["chart", "type"], type)
- }
-
- title(title) {
- return this.setOption(["title", "text"], title)
- }
-
- colors(colors) {
- if (!colors) {
- delete this.options.colors
- this.options["customColor"] = false
- return this
- }
- this.options["customColor"] = true
- return this.setOption(["colors"], colors)
- }
-
- width(width) {
- return this.setOption(["chart", "width"], width || undefined)
- }
-
- height(height) {
- return this.setOption(["chart", "height"], height || undefined)
- }
-
- xLabel(label) {
- return this.setOption(["xaxis", "title", "text"], label)
- }
-
- yLabel(label) {
- return this.setOption(["yaxis", "title", "text"], label)
- }
-
- xCategories(categories) {
- return this.setOption(["xaxis", "categories"], categories)
- }
-
- yCategories(categories) {
- return this.setOption(["yaxis", "categories"], categories)
- }
-
- series(series) {
- return this.setOption(["series"], series)
- }
-
- horizontal(horizontal) {
- return this.setOption(["plotOptions", "bar", "horizontal"], horizontal)
- }
-
- dataLabels(dataLabels) {
- return this.setOption(["dataLabels", "enabled"], dataLabels)
- }
-
- animate(animate) {
- return this.setOption(["chart", "animations", "enabled"], animate)
- }
-
- curve(curve) {
- return this.setOption(["stroke", "curve"], curve)
- }
-
- gradient(gradient) {
- const fill = {
- type: "gradient",
- gradient: {
- shadeIntensity: 1,
- opacityFrom: 0.7,
- opacityTo: 0.9,
- stops: [0, 90, 100],
- },
- }
- return this.setOption(["fill"], gradient ? fill : undefined)
- }
-
- legend(legend) {
- return this.setOption(["legend", "show"], legend)
- }
-
- legendPosition(position) {
- return this.setOption(["legend", "position"], position)
- }
-
- stacked(stacked) {
- return this.setOption(["chart", "stacked"], stacked)
- }
-
- labels(labels) {
- return this.setOption(["labels"], labels)
- }
-
- xUnits(units) {
- return this.setOption(
- ["xaxis", "labels", "formatter"],
- this.formatters[units || "Default"]
- )
- }
-
- yUnits(units) {
- return this.setOption(
- ["yaxis", "labels", "formatter"],
- this.formatters[units || "Default"]
- )
- }
-
- clearXFormatter() {
- delete this.options.xaxis.labels
- return this
- }
-
- clearYFormatter() {
- delete this.options.yaxis.labels
- return this
- }
-
- xType(type) {
- return this.setOption(["xaxis", "type"], type)
- }
-
- yType(type) {
- return this.setOption(["yaxis", "type"], type)
- }
-
- yTooltip(yTooltip) {
- return this.setOption(["yaxis", "tooltip", "enabled"], yTooltip)
- }
-
- palette(palette) {
- if (!palette) {
- return this
- }
- return this.setOption(
- ["theme", "palette"],
- palette.toLowerCase().replace(/[\W]/g, "")
- )
- }
-}
diff --git a/packages/client/src/components/app/charts/AreaChart.svelte b/packages/client/src/components/app/charts/AreaChart.svelte
index dc80b2b9da..a9a61e59f6 100644
--- a/packages/client/src/components/app/charts/AreaChart.svelte
+++ b/packages/client/src/components/app/charts/AreaChart.svelte
@@ -1,5 +1,159 @@
-
+
diff --git a/packages/client/src/components/app/charts/BarChart.svelte b/packages/client/src/components/app/charts/BarChart.svelte
index fd8443e2d6..aeebfe9461 100644
--- a/packages/client/src/components/app/charts/BarChart.svelte
+++ b/packages/client/src/components/app/charts/BarChart.svelte
@@ -1,11 +1,12 @@
diff --git a/packages/client/src/components/app/charts/CandleStickChart.svelte b/packages/client/src/components/app/charts/CandleStickChart.svelte
index b2760b005e..61cdef180b 100644
--- a/packages/client/src/components/app/charts/CandleStickChart.svelte
+++ b/packages/client/src/components/app/charts/CandleStickChart.svelte
@@ -1,6 +1,6 @@
diff --git a/packages/client/src/components/app/charts/DonutChart.svelte b/packages/client/src/components/app/charts/DonutChart.svelte
index 721a09053a..dad9edfd67 100644
--- a/packages/client/src/components/app/charts/DonutChart.svelte
+++ b/packages/client/src/components/app/charts/DonutChart.svelte
@@ -1,5 +1,99 @@
-
+
diff --git a/packages/client/src/components/app/charts/HistogramChart.svelte b/packages/client/src/components/app/charts/HistogramChart.svelte
index 26b9028550..37c395d45f 100644
--- a/packages/client/src/components/app/charts/HistogramChart.svelte
+++ b/packages/client/src/components/app/charts/HistogramChart.svelte
@@ -1,135 +1,154 @@
diff --git a/packages/client/src/components/app/charts/LineChart.svelte b/packages/client/src/components/app/charts/LineChart.svelte
index 7f82a833d2..c2dac189e1 100644
--- a/packages/client/src/components/app/charts/LineChart.svelte
+++ b/packages/client/src/components/app/charts/LineChart.svelte
@@ -1,8 +1,7 @@
diff --git a/packages/client/src/components/app/charts/PieChart.svelte b/packages/client/src/components/app/charts/PieChart.svelte
index 8cb7317d94..3250a2ca95 100644
--- a/packages/client/src/components/app/charts/PieChart.svelte
+++ b/packages/client/src/components/app/charts/PieChart.svelte
@@ -1,6 +1,6 @@
diff --git a/packages/client/src/components/app/charts/utils.js b/packages/client/src/components/app/charts/utils.js
new file mode 100644
index 0000000000..1aea22c991
--- /dev/null
+++ b/packages/client/src/components/app/charts/utils.js
@@ -0,0 +1,51 @@
+export const formatters = {
+ ["Default"]: val => val,
+ ["Thousands"]: val => `${Math.round(val / 1000)}K`,
+ ["Millions"]: val => `${Math.round(val / 1000000)}M`,
+ ["Datetime"]: val => new Date(val).toLocaleString(),
+}
+
+export const parsePalette = paletteName => {
+ if (paletteName === "Custom") {
+ // return null in this case so that the palette option doesn't get consumed by Apex Charts
+ return null
+ }
+
+ const [_, number] = paletteName.split(" ")
+
+ return `palette${number}`
+}
+
+// Deep clone which copies function references
+export const cloneDeep = value => {
+ const typesToNaiveCopy = ["string", "boolean", "number", "function", "symbol"]
+
+ if (value === null) {
+ return null
+ }
+
+ if (value === undefined) {
+ return undefined
+ }
+
+ if (typesToNaiveCopy.includes(typeof value)) {
+ return value
+ }
+
+ if (Array.isArray(value)) {
+ return value.map(element => cloneDeep(element))
+ }
+
+ // Only copy "pure" objects, we want to error on stuff like Maps or Sets
+ if (typeof value === "object" && value.constructor.name === "Object") {
+ const cloneObject = {}
+
+ Object.entries(value).forEach(([key, childValue]) => {
+ cloneObject[key] = cloneDeep(childValue)
+ })
+
+ return cloneObject
+ }
+
+ throw `Unsupported value: "${value}" of type: "${typeof value}"`
+}
diff --git a/packages/client/src/components/app/charts/utils.test.js b/packages/client/src/components/app/charts/utils.test.js
new file mode 100644
index 0000000000..1b065e2fae
--- /dev/null
+++ b/packages/client/src/components/app/charts/utils.test.js
@@ -0,0 +1,31 @@
+import { expect, describe, it, vi } from "vitest"
+import { cloneDeep } from "./utils"
+
+describe("utils", () => {
+ let context
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+ context = {}
+ })
+
+ describe("cloneDeep", () => {
+ beforeEach(() => {
+ context.value = {
+ obj: { one: 1, two: 2 },
+ arr: [1, { first: null, second: undefined }, 2],
+ str: "test",
+ num: 123,
+ bool: true,
+ sym: Symbol("test"),
+ func: () => "some value",
+ }
+ context.cloneValue = cloneDeep(context.value)
+ })
+
+ it("to clone the object and not copy object references", () => {
+ expect(context.cloneValue.obj.one).toEqual(1)
+ expect(context.cloneValue.obj.two).toEqual(2)
+ })
+ })
+})
diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js
index efe69938e7..bdf74c8014 100644
--- a/packages/client/src/utils/componentProps.js
+++ b/packages/client/src/utils/componentProps.js
@@ -108,7 +108,12 @@ export const getSettingsDefinition = definition => {
let settings = []
definition.settings?.forEach(setting => {
if (setting.section) {
- settings = settings.concat(setting.settings || [])
+ settings = settings.concat(
+ (setting.settings || [])?.map(childSetting => ({
+ ...childSetting,
+ sectionDependsOn: setting.dependsOn,
+ }))
+ )
} else {
settings.push(setting)
}
diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts
index 5b199341b1..a49fe834d3 100644
--- a/packages/server/src/api/controllers/automation.ts
+++ b/packages/server/src/api/controllers/automation.ts
@@ -274,20 +274,28 @@ export async function trigger(ctx: UserCtx) {
let hasCollectStep = sdk.automations.utils.checkForCollectStep(automation)
if (hasCollectStep && (await features.isSyncAutomationsEnabled())) {
- const response: AutomationResults = await triggers.externalTrigger(
- automation,
- {
- fields: ctx.request.body.fields,
- timeout:
- ctx.request.body.timeout * 1000 || env.AUTOMATION_THREAD_TIMEOUT,
- },
- { getResponses: true }
- )
+ try {
+ const response: AutomationResults = await triggers.externalTrigger(
+ automation,
+ {
+ fields: ctx.request.body.fields,
+ timeout:
+ ctx.request.body.timeout * 1000 || env.AUTOMATION_THREAD_TIMEOUT,
+ },
+ { getResponses: true }
+ )
- let collectedValue = response.steps.find(
- step => step.stepId === AutomationActionStepId.COLLECT
- )
- ctx.body = collectedValue?.outputs
+ let collectedValue = response.steps.find(
+ step => step.stepId === AutomationActionStepId.COLLECT
+ )
+ ctx.body = collectedValue?.outputs
+ } catch (err: any) {
+ if (err.message) {
+ ctx.throw(400, err.message)
+ } else {
+ throw err
+ }
+ }
} else {
if (ctx.appId && !dbCore.isProdAppID(ctx.appId)) {
ctx.throw(400, "Only apps in production support this endpoint")
diff --git a/packages/server/src/api/controllers/component.ts b/packages/server/src/api/controllers/component.ts
index 12051be770..6d4d3e2d21 100644
--- a/packages/server/src/api/controllers/component.ts
+++ b/packages/server/src/api/controllers/component.ts
@@ -20,7 +20,8 @@ export async function fetchAppComponentDefinitions(ctx: UserCtx) {
const definitions: { [key: string]: any } = {}
for (let { manifest, library } of componentManifests) {
for (let key of Object.keys(manifest)) {
- if (key === "features") {
+ // These keys are not components, and should not be preprended with the `@budibase/` prefix
+ if (key === "features" || key === "typeSupportPresets") {
definitions[key] = manifest[key]
} else {
const fullComponentName = `${library}/${key}`.toLowerCase()
diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts
index 7885e97fbf..711cfb8d4f 100644
--- a/packages/server/src/api/routes/tests/automation.spec.ts
+++ b/packages/server/src/api/routes/tests/automation.spec.ts
@@ -206,6 +206,23 @@ describe("/automations", () => {
expect(res.body.value).toEqual([1, 2, 3])
})
+ it("should throw an error when attempting to trigger a disabled automation", async () => {
+ mocks.licenses.useSyncAutomations()
+ let automation = collectAutomation()
+ automation = await config.createAutomation({
+ ...automation,
+ disabled: true,
+ })
+
+ const res = await request
+ .post(`/api/automations/${automation._id}/trigger`)
+ .set(config.defaultHeaders())
+ .expect("Content-Type", /json/)
+ .expect(400)
+
+ expect(res.body.message).toEqual("Automation is disabled")
+ })
+
it("triggers an asynchronous automation", async () => {
let automation = newAutomation()
automation = await config.createAutomation(automation)
diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts
index 08e3199a11..223b8d2eb6 100644
--- a/packages/server/src/automations/triggers.ts
+++ b/packages/server/src/automations/triggers.ts
@@ -36,10 +36,10 @@ async function queueRelevantRowAutomations(
await context.doInAppContext(event.appId, async () => {
let automations = await getAllAutomations()
- // filter down to the correct event type
+ // filter down to the correct event type and enabled automations
automations = automations.filter(automation => {
const trigger = automation.definition.trigger
- return trigger && trigger.event === eventType
+ return trigger && trigger.event === eventType && !automation.disabled
})
for (let automation of automations) {
@@ -94,6 +94,9 @@ export async function externalTrigger(
params: { fields: Record; timeout?: number },
{ getResponses }: { getResponses?: boolean } = {}
): Promise {
+ if (automation.disabled) {
+ throw new Error("Automation is disabled")
+ }
if (
automation.definition != null &&
automation.definition.trigger != null &&
diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts
index 360802df6a..4d7e169f52 100644
--- a/packages/server/src/automations/utils.ts
+++ b/packages/server/src/automations/utils.ts
@@ -196,6 +196,7 @@ export async function enableCronTrigger(appId: any, automation: Automation) {
if (
isCronTrigger(automation) &&
!isRebootTrigger(automation) &&
+ !automation.disabled &&
trigger?.inputs.cron
) {
const cronExp = trigger.inputs.cron
diff --git a/packages/types/src/documents/app/automation.ts b/packages/types/src/documents/app/automation.ts
index 481a051e1c..6d1753dc28 100644
--- a/packages/types/src/documents/app/automation.ts
+++ b/packages/types/src/documents/app/automation.ts
@@ -125,6 +125,7 @@ export interface Automation extends Document {
name: string
internal?: boolean
type?: string
+ disabled?: boolean
}
interface BaseIOStructure {
diff --git a/yarn.lock b/yarn.lock
index 71ab88e601..f26876dc16 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6450,6 +6450,11 @@
js-yaml "^3.10.0"
tslib "^2.4.0"
+"@yr/monotone-cubic-spline@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz#7272d89f8e4f6fb7a1600c28c378cc18d3b577b9"
+ integrity sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==
+
"@zerodevx/svelte-json-view@^1.0.7":
version "1.0.7"
resolved "https://registry.yarnpkg.com/@zerodevx/svelte-json-view/-/svelte-json-view-1.0.7.tgz#abf3efa71dedcb3e9d16bc9cc61d5ea98c8d00b1"
@@ -6748,11 +6753,12 @@ anymatch@^3.0.3, anymatch@~3.1.2:
normalize-path "^3.0.0"
picomatch "^2.0.4"
-apexcharts@^3.19.2, apexcharts@^3.22.1:
- version "3.37.1"
- resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.37.1.tgz#50443d302fc7fc72aace9c6c4074baae017c6950"
- integrity sha512-fmQ5Updeb/LASl+S1+mIxXUFxzY0Fa7gexfCs4o+OPP9f2NEBNjvybOtPrah44N4roK7U5o5Jis906QeEQu0cA==
+apexcharts@^3.48.0:
+ version "3.49.1"
+ resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.49.1.tgz#837d1d4fd80f2c092f0587e8fb6bbc31ad57a0f3"
+ integrity sha512-MqGtlq/KQuO8j0BBsUJYlRG8VBctKwYdwuBtajHgHTmSgUU3Oai+8oYN/rKCXwXzrUlYA+GiMgotAIbXY2BCGw==
dependencies:
+ "@yr/monotone-cubic-spline" "^1.0.3"
svg.draggable.js "^2.2.2"
svg.easing.js "^2.0.0"
svg.filter.js "^2.0.2"
@@ -20360,13 +20366,6 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-svelte-apexcharts@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/svelte-apexcharts/-/svelte-apexcharts-1.0.2.tgz#4e000f8b8f7c901c05658c845457dfc8314d54c1"
- integrity sha512-6qlx4rE+XsonZ0FZudfwqOQ34Pq+3wpxgAD75zgEmGoYhYBJcwmikTuTf3o8ZBsZue9U/pAwhNy3ed1Bkq1gmA==
- dependencies:
- apexcharts "^3.19.2"
-
svelte-dnd-action@^0.9.8:
version "0.9.22"
resolved "https://registry.yarnpkg.com/svelte-dnd-action/-/svelte-dnd-action-0.9.22.tgz#003eee9dddb31d8c782f6832aec8b1507fff194d"