Add bindings support to meeting start / end dates (#11759)
* Deprecate zapier+make values1..5 * Allow dates in meeting invite to be bindable * Add DrawerBindableSlot component * Show calendar icon * refactor * Use cancel icon * Disable cancel for JS bindings * WIP * WIP * WIP * Fix linkedIds svelte binding * Label and icon update * Handle arrays * Support text area * Add reactivity to text area icon * Support boolean * JSON support * Remove rowControl * Allow boolean field to have three states * lint * Refactor --------- Co-authored-by: Michael Drury <me@michaeldrury.co.uk>
This commit is contained in:
parent
2868cd9b2b
commit
b4e0d98973
|
@ -221,18 +221,6 @@ const automationActions = store => ({
|
||||||
newAutomation.definition.steps.splice(blockIdx, 0, block)
|
newAutomation.definition.steps.splice(blockIdx, 0, block)
|
||||||
await store.actions.save(newAutomation)
|
await store.actions.save(newAutomation)
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* "rowControl" appears to be the name of the flag used to determine whether
|
|
||||||
* a certain automation block uses values or bindings as inputs
|
|
||||||
*/
|
|
||||||
toggleRowControl: async (block, rowControl) => {
|
|
||||||
const newBlock = { ...block, rowControl }
|
|
||||||
const newAutomation = store.actions.getUpdatedDefinition(
|
|
||||||
get(selectedAutomation),
|
|
||||||
newBlock
|
|
||||||
)
|
|
||||||
await store.actions.save(newAutomation)
|
|
||||||
},
|
|
||||||
deleteAutomationBlock: async block => {
|
deleteAutomationBlock: async block => {
|
||||||
const automation = get(selectedAutomation)
|
const automation = get(selectedAutomation)
|
||||||
let newAutomation = cloneDeep(automation)
|
let newAutomation = cloneDeep(automation)
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
Detail,
|
Detail,
|
||||||
Modal,
|
Modal,
|
||||||
Button,
|
Button,
|
||||||
Select,
|
|
||||||
ActionButton,
|
ActionButton,
|
||||||
notifications,
|
notifications,
|
||||||
Label,
|
Label,
|
||||||
|
@ -39,9 +38,6 @@
|
||||||
step => step.stepId === ActionStepID.COLLECT
|
step => step.stepId === ActionStepID.COLLECT
|
||||||
)
|
)
|
||||||
$: automationId = $selectedAutomation?._id
|
$: automationId = $selectedAutomation?._id
|
||||||
$: showBindingPicker =
|
|
||||||
block.stepId === ActionStepID.CREATE_ROW ||
|
|
||||||
block.stepId === ActionStepID.UPDATE_ROW
|
|
||||||
$: isTrigger = block.type === "TRIGGER"
|
$: isTrigger = block.type === "TRIGGER"
|
||||||
$: steps = $selectedAutomation?.definition?.steps ?? []
|
$: steps = $selectedAutomation?.definition?.steps ?? []
|
||||||
$: blockIdx = steps.findIndex(step => step.id === block.id)
|
$: blockIdx = steps.findIndex(step => step.id === block.id)
|
||||||
|
@ -96,15 +92,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* "rowControl" appears to be the name of the flag used to determine whether
|
|
||||||
* a certain automation block uses values or bindings as inputs
|
|
||||||
*/
|
|
||||||
function toggleRowControl(evt) {
|
|
||||||
const rowControl = evt.detail !== "Use values"
|
|
||||||
automationStore.actions.toggleRowControl(block, rowControl)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addLooping() {
|
async function addLooping() {
|
||||||
const loopDefinition = $automationStore.blockDefinitions.ACTION.LOOP
|
const loopDefinition = $automationStore.blockDefinitions.ACTION.LOOP
|
||||||
const loopBlock = automationStore.actions.constructBlock(
|
const loopBlock = automationStore.actions.constructBlock(
|
||||||
|
@ -189,16 +176,6 @@
|
||||||
Add Looping
|
Add Looping
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showBindingPicker}
|
|
||||||
<Select
|
|
||||||
on:change={toggleRowControl}
|
|
||||||
defaultValue="Use values"
|
|
||||||
autoWidth
|
|
||||||
value={block.rowControl ? "Use bindings" : "Use values"}
|
|
||||||
options={["Use values", "Use bindings"]}
|
|
||||||
placeholder={null}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
on:click={() => deleteStep()}
|
on:click={() => deleteStep()}
|
||||||
icon="DeleteOutline"
|
icon="DeleteOutline"
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
import { environment, licensing } from "stores/portal"
|
import { environment, licensing } from "stores/portal"
|
||||||
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
|
||||||
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
|
||||||
|
import DrawerBindableSlot from "../../common/bindings/DrawerBindableSlot.svelte"
|
||||||
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
||||||
import CodeEditorModal from "./CodeEditorModal.svelte"
|
import CodeEditorModal from "./CodeEditorModal.svelte"
|
||||||
import QuerySelector from "./QuerySelector.svelte"
|
import QuerySelector from "./QuerySelector.svelte"
|
||||||
|
@ -82,33 +83,6 @@
|
||||||
? [hbAutocomplete([...bindingsToCompletions(bindings, codeMode)])]
|
? [hbAutocomplete([...bindingsToCompletions(bindings, codeMode)])]
|
||||||
: []
|
: []
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO - Remove after November 2023
|
|
||||||
* *******************************
|
|
||||||
* Code added to provide backwards compatibility between Values 1,2,3,4,5
|
|
||||||
* and the new JSON body.
|
|
||||||
*/
|
|
||||||
let deprecatedSchemaProperties
|
|
||||||
$: {
|
|
||||||
if (block?.stepId === "integromat" || block?.stepId === "zapier") {
|
|
||||||
deprecatedSchemaProperties = schemaProperties.filter(
|
|
||||||
prop => !prop[0].startsWith("value")
|
|
||||||
)
|
|
||||||
if (!deprecatedSchemaProperties.map(entry => entry[0]).includes("body")) {
|
|
||||||
deprecatedSchemaProperties.push([
|
|
||||||
"body",
|
|
||||||
{
|
|
||||||
title: "Payload",
|
|
||||||
type: "json",
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deprecatedSchemaProperties = schemaProperties
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/****************************************************/
|
|
||||||
|
|
||||||
const getInputData = (testData, blockInputs) => {
|
const getInputData = (testData, blockInputs) => {
|
||||||
// Test data is not cloned for reactivity
|
// Test data is not cloned for reactivity
|
||||||
let newInputData = testData || cloneDeep(blockInputs)
|
let newInputData = testData || cloneDeep(blockInputs)
|
||||||
|
@ -118,30 +92,6 @@
|
||||||
newInputData = cloneDeep(blockInputs)
|
newInputData = cloneDeep(blockInputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO - Remove after November 2023
|
|
||||||
* *******************************
|
|
||||||
* Code added to provide backwards compatibility between Values 1,2,3,4,5
|
|
||||||
* and the new JSON body.
|
|
||||||
*/
|
|
||||||
if (
|
|
||||||
(block?.stepId === "integromat" || block?.stepId === "zapier") &&
|
|
||||||
!newInputData?.body?.value
|
|
||||||
) {
|
|
||||||
let deprecatedValues = {
|
|
||||||
...newInputData,
|
|
||||||
}
|
|
||||||
delete deprecatedValues.url
|
|
||||||
delete deprecatedValues.body
|
|
||||||
newInputData = {
|
|
||||||
url: newInputData.url,
|
|
||||||
body: {
|
|
||||||
value: JSON.stringify(deprecatedValues),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**********************************/
|
|
||||||
|
|
||||||
inputData = newInputData
|
inputData = newInputData
|
||||||
setDefaultEnumValues()
|
setDefaultEnumValues()
|
||||||
}
|
}
|
||||||
|
@ -337,7 +287,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="fields">
|
<div class="fields">
|
||||||
{#each deprecatedSchemaProperties as [key, value]}
|
{#each schemaProperties as [key, value]}
|
||||||
{#if canShowField(key, value)}
|
{#if canShowField(key, value)}
|
||||||
<div class="block-field">
|
<div class="block-field">
|
||||||
{#if key !== "fields" && value.type !== "boolean"}
|
{#if key !== "fields" && value.type !== "boolean"}
|
||||||
|
@ -362,18 +312,6 @@
|
||||||
mode="json"
|
mode="json"
|
||||||
value={inputData[key]?.value}
|
value={inputData[key]?.value}
|
||||||
on:change={e => {
|
on:change={e => {
|
||||||
/**
|
|
||||||
* TODO - Remove after November 2023
|
|
||||||
* *******************************
|
|
||||||
* Code added to provide backwards compatibility between Values 1,2,3,4,5
|
|
||||||
* and the new JSON body.
|
|
||||||
*/
|
|
||||||
delete inputData.value1
|
|
||||||
delete inputData.value2
|
|
||||||
delete inputData.value3
|
|
||||||
delete inputData.value4
|
|
||||||
delete inputData.value5
|
|
||||||
/***********************/
|
|
||||||
onChange(e, key)
|
onChange(e, key)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -386,10 +324,23 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else if value.type === "date"}
|
{:else if value.type === "date"}
|
||||||
<DatePicker
|
<DrawerBindableSlot
|
||||||
|
fillWidth
|
||||||
|
title={value.title}
|
||||||
|
panel={AutomationBindingPanel}
|
||||||
|
type={"date"}
|
||||||
value={inputData[key]}
|
value={inputData[key]}
|
||||||
on:change={e => onChange(e, key)}
|
on:change={e => onChange(e, key)}
|
||||||
/>
|
{bindings}
|
||||||
|
allowJS={true}
|
||||||
|
updateOnChange={false}
|
||||||
|
drawerLeft="260px"
|
||||||
|
>
|
||||||
|
<DatePicker
|
||||||
|
value={inputData[key]}
|
||||||
|
on:change={e => onChange(e, key)}
|
||||||
|
/>
|
||||||
|
</DrawerBindableSlot>
|
||||||
{:else if value.customType === "column"}
|
{:else if value.customType === "column"}
|
||||||
<Select
|
<Select
|
||||||
on:change={e => onChange(e, key)}
|
on:change={e => onChange(e, key)}
|
||||||
|
@ -469,7 +420,6 @@
|
||||||
/>
|
/>
|
||||||
{:else if value.customType === "row"}
|
{:else if value.customType === "row"}
|
||||||
<RowSelector
|
<RowSelector
|
||||||
{block}
|
|
||||||
value={inputData[key]}
|
value={inputData[key]}
|
||||||
meta={inputData["meta"] || {}}
|
meta={inputData["meta"] || {}}
|
||||||
on:change={e => {
|
on:change={e => {
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { tables } from "stores/backend"
|
import { tables } from "stores/backend"
|
||||||
import { Select, Checkbox } from "@budibase/bbui"
|
import { Select, Checkbox } from "@budibase/bbui"
|
||||||
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
|
|
||||||
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import RowSelectorTypes from "./RowSelectorTypes.svelte"
|
import RowSelectorTypes from "./RowSelectorTypes.svelte"
|
||||||
import ModalBindableInput from "../../common/bindings/ModalBindableInput.svelte"
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
export let meta
|
export let meta
|
||||||
export let bindings
|
export let bindings
|
||||||
export let block
|
|
||||||
export let isTestModal
|
export let isTestModal
|
||||||
export let isUpdateRow
|
export let isUpdateRow
|
||||||
|
|
||||||
|
@ -25,16 +21,6 @@
|
||||||
let table
|
let table
|
||||||
let schemaFields
|
let schemaFields
|
||||||
|
|
||||||
let placeholders = {
|
|
||||||
number: 10,
|
|
||||||
boolean: "true",
|
|
||||||
datetime: "2022-02-16T12:00:00.000Z ",
|
|
||||||
options: "1",
|
|
||||||
array: "1 2 3 4",
|
|
||||||
link: "ro_ta_123_456",
|
|
||||||
longform: "long form text",
|
|
||||||
}
|
|
||||||
$: rowControl = block.rowControl
|
|
||||||
$: {
|
$: {
|
||||||
table = $tables.list.find(table => table._id === value?.tableId)
|
table = $tables.list.find(table => table._id === value?.tableId)
|
||||||
schemaFields = Object.entries(table?.schema ?? {})
|
schemaFields = Object.entries(table?.schema ?? {})
|
||||||
|
@ -57,19 +43,13 @@
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "boolean") {
|
|
||||||
if (typeof value === "boolean") {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return value === "true"
|
|
||||||
}
|
|
||||||
if (type === "number") {
|
if (type === "number") {
|
||||||
if (typeof value === "number") {
|
if (typeof value === "number") {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
return Number(value)
|
return Number(value)
|
||||||
}
|
}
|
||||||
if (type === "options") {
|
if (type === "options" || type === "boolean") {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if (type === "array") {
|
if (type === "array") {
|
||||||
|
@ -127,47 +107,25 @@
|
||||||
{#if schemaFields.length}
|
{#if schemaFields.length}
|
||||||
<div class="schema-fields">
|
<div class="schema-fields">
|
||||||
{#each schemaFields as [field, schema]}
|
{#each schemaFields as [field, schema]}
|
||||||
{#if !schema.autocolumn}
|
{#if !schema.autocolumn && schema.type !== "attachment"}
|
||||||
{#if schema.type !== "attachment"}
|
<RowSelectorTypes
|
||||||
{#if !rowControl}
|
{isTestModal}
|
||||||
<RowSelectorTypes
|
{field}
|
||||||
{isTestModal}
|
{schema}
|
||||||
{field}
|
bindings={parsedBindings}
|
||||||
{schema}
|
{value}
|
||||||
bindings={parsedBindings}
|
{onChange}
|
||||||
{value}
|
/>
|
||||||
{onChange}
|
{/if}
|
||||||
/>
|
{#if isUpdateRow && schema.type === "link"}
|
||||||
{:else}
|
<div class="checkbox-field">
|
||||||
<div>
|
<Checkbox
|
||||||
<svelte:component
|
value={meta.fields?.[field]?.clearRelationships}
|
||||||
this={isTestModal ? ModalBindableInput : DrawerBindableInput}
|
text={"Clear relationships if empty?"}
|
||||||
placeholder={placeholders[schema.type]}
|
size={"S"}
|
||||||
panel={AutomationBindingPanel}
|
on:change={e => onChangeSetting(e, field)}
|
||||||
value={Array.isArray(value[field])
|
/>
|
||||||
? value[field].join(",")
|
</div>
|
||||||
: value[field]}
|
|
||||||
on:change={e => onChange(e, field, schema.type)}
|
|
||||||
label={field}
|
|
||||||
type="string"
|
|
||||||
bindings={parsedBindings}
|
|
||||||
fillWidth={true}
|
|
||||||
allowJS={true}
|
|
||||||
updateOnChange={false}
|
|
||||||
/>
|
|
||||||
{#if isUpdateRow && schema.type === "link"}
|
|
||||||
<div class="checkbox-field">
|
|
||||||
<Checkbox
|
|
||||||
value={meta.fields?.[field]?.clearRelationships}
|
|
||||||
text={"Clear relationships if empty?"}
|
|
||||||
size={"S"}
|
|
||||||
on:change={e => onChangeSetting(e, field)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
Toggle,
|
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Multiselect,
|
Multiselect,
|
||||||
TextArea,
|
TextArea,
|
||||||
|
@ -9,6 +8,7 @@
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
|
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
|
||||||
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
|
||||||
|
import DrawerBindableSlot from "../../common/bindings/DrawerBindableSlot.svelte"
|
||||||
import ModalBindableInput from "../../common/bindings/ModalBindableInput.svelte"
|
import ModalBindableInput from "../../common/bindings/ModalBindableInput.svelte"
|
||||||
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
||||||
import Editor from "components/integration/QueryEditor.svelte"
|
import Editor from "components/integration/QueryEditor.svelte"
|
||||||
|
@ -31,69 +31,88 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if schemaHasOptions(schema) && schema.type !== "array"}
|
<DrawerBindableSlot
|
||||||
<Select
|
fillWidth
|
||||||
on:change={e => onChange(e, field)}
|
title={value.title}
|
||||||
label={field}
|
label={field}
|
||||||
value={value[field]}
|
panel={AutomationBindingPanel}
|
||||||
options={schema.constraints.inclusion}
|
type={schema.type}
|
||||||
/>
|
{schema}
|
||||||
{:else if schema.type === "datetime"}
|
value={value[field]}
|
||||||
<DatePicker
|
on:change={e => onChange(e, field)}
|
||||||
label={field}
|
{bindings}
|
||||||
value={value[field]}
|
allowJS={true}
|
||||||
on:change={e => onChange(e, field)}
|
updateOnChange={false}
|
||||||
/>
|
drawerLeft="260px"
|
||||||
{:else if schema.type === "boolean"}
|
>
|
||||||
<Toggle
|
{#if schemaHasOptions(schema) && schema.type !== "array"}
|
||||||
text={field}
|
<Select
|
||||||
value={value[field]}
|
on:change={e => onChange(e, field)}
|
||||||
on:change={e => onChange(e, field)}
|
label={field}
|
||||||
/>
|
|
||||||
{:else if schema.type === "array"}
|
|
||||||
<Multiselect
|
|
||||||
bind:value={value[field]}
|
|
||||||
label={field}
|
|
||||||
options={schema.constraints.inclusion}
|
|
||||||
on:change={e => onChange(e, field)}
|
|
||||||
/>
|
|
||||||
{:else if schema.type === "longform"}
|
|
||||||
<TextArea
|
|
||||||
label={field}
|
|
||||||
bind:value={value[field]}
|
|
||||||
on:change={e => onChange(e, field)}
|
|
||||||
/>
|
|
||||||
{:else if schema.type === "json"}
|
|
||||||
<span>
|
|
||||||
<Label>{field}</Label>
|
|
||||||
<Editor
|
|
||||||
editorHeight="150"
|
|
||||||
mode="json"
|
|
||||||
on:change={e => {
|
|
||||||
if (e.detail?.value !== value[field]) {
|
|
||||||
onChange(e, field, schema.type)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={value[field]}
|
value={value[field]}
|
||||||
|
options={schema.constraints.inclusion}
|
||||||
/>
|
/>
|
||||||
</span>
|
{:else if schema.type === "datetime"}
|
||||||
{:else if schema.type === "link"}
|
<DatePicker
|
||||||
<LinkedRowSelector
|
label={field}
|
||||||
bind:linkedRows={value[field]}
|
value={value[field]}
|
||||||
{schema}
|
on:change={e => onChange(e, field)}
|
||||||
on:change={e => onChange(e, field)}
|
/>
|
||||||
/>
|
{:else if schema.type === "boolean"}
|
||||||
{:else if schema.type === "string" || schema.type === "number"}
|
<Select
|
||||||
<svelte:component
|
on:change={e => onChange(e, field)}
|
||||||
this={isTestModal ? ModalBindableInput : DrawerBindableInput}
|
label={field}
|
||||||
panel={AutomationBindingPanel}
|
value={value[field]}
|
||||||
value={value[field]}
|
options={[
|
||||||
on:change={e => onChange(e, field)}
|
{ label: "True", value: "true" },
|
||||||
label={field}
|
{ label: "False", value: "false" },
|
||||||
type="string"
|
]}
|
||||||
bindings={parsedBindings}
|
/>
|
||||||
fillWidth={true}
|
{:else if schema.type === "array"}
|
||||||
allowJS={true}
|
<Multiselect
|
||||||
updateOnChange={false}
|
bind:value={value[field]}
|
||||||
/>
|
label={field}
|
||||||
{/if}
|
options={schema.constraints.inclusion}
|
||||||
|
on:change={e => onChange(e, field)}
|
||||||
|
/>
|
||||||
|
{:else if schema.type === "longform"}
|
||||||
|
<TextArea
|
||||||
|
label={field}
|
||||||
|
bind:value={value[field]}
|
||||||
|
on:change={e => onChange(e, field)}
|
||||||
|
/>
|
||||||
|
{:else if schema.type === "json"}
|
||||||
|
<span>
|
||||||
|
<Label>{field}</Label>
|
||||||
|
<Editor
|
||||||
|
editorHeight="150"
|
||||||
|
mode="json"
|
||||||
|
on:change={e => {
|
||||||
|
if (e.detail?.value !== value[field]) {
|
||||||
|
onChange(e, field, schema.type)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={value[field]}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
{:else if schema.type === "link"}
|
||||||
|
<LinkedRowSelector
|
||||||
|
bind:linkedRows={value[field]}
|
||||||
|
{schema}
|
||||||
|
on:change={e => onChange(e, field)}
|
||||||
|
/>
|
||||||
|
{:else if schema.type === "string" || schema.type === "number"}
|
||||||
|
<svelte:component
|
||||||
|
this={isTestModal ? ModalBindableInput : DrawerBindableInput}
|
||||||
|
panel={AutomationBindingPanel}
|
||||||
|
value={value[field]}
|
||||||
|
on:change={e => onChange(e, field)}
|
||||||
|
label={field}
|
||||||
|
type="string"
|
||||||
|
bindings={parsedBindings}
|
||||||
|
fillWidth={true}
|
||||||
|
allowJS={true}
|
||||||
|
updateOnChange={false}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</DrawerBindableSlot>
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let rows = []
|
let rows = []
|
||||||
let linkedIds = (Array.isArray(linkedRows) ? linkedRows : [])?.map(
|
let linkedIds = []
|
||||||
|
|
||||||
|
$: linkedIds = (Array.isArray(linkedRows) ? linkedRows : [])?.map(
|
||||||
row => row?._id || row
|
row => row?._id || row
|
||||||
)
|
)
|
||||||
|
|
||||||
$: linkedRows = linkedIds
|
|
||||||
$: label = capitalise(schema.name)
|
$: label = capitalise(schema.name)
|
||||||
$: linkedTableId = schema.tableId
|
$: linkedTableId = schema.tableId
|
||||||
$: linkedTable = $tables.list.find(table => table._id === linkedTableId)
|
$: linkedTable = $tables.list.find(table => table._id === linkedTableId)
|
||||||
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
<script>
|
||||||
|
import { Icon, Input, Drawer, Button } from "@budibase/bbui"
|
||||||
|
import {
|
||||||
|
readableToRuntimeBinding,
|
||||||
|
runtimeToReadableBinding,
|
||||||
|
} from "builderStore/dataBinding"
|
||||||
|
|
||||||
|
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
|
||||||
|
import { createEventDispatcher, setContext } from "svelte"
|
||||||
|
import { isJSBinding } from "@budibase/string-templates"
|
||||||
|
|
||||||
|
export let panel = ClientBindingPanel
|
||||||
|
export let value = ""
|
||||||
|
export let bindings = []
|
||||||
|
export let title = "Bindings"
|
||||||
|
export let placeholder
|
||||||
|
export let label
|
||||||
|
export let disabled = false
|
||||||
|
export let fillWidth
|
||||||
|
export let allowJS = true
|
||||||
|
export let allowHelpers = true
|
||||||
|
export let updateOnChange = true
|
||||||
|
export let drawerLeft
|
||||||
|
export let type
|
||||||
|
export let schema
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let bindingDrawer
|
||||||
|
let valid = true
|
||||||
|
let currentVal = value
|
||||||
|
|
||||||
|
$: readableValue = runtimeToReadableBinding(bindings, value)
|
||||||
|
$: tempValue = readableValue
|
||||||
|
$: isJS = isJSBinding(value)
|
||||||
|
|
||||||
|
const saveBinding = () => {
|
||||||
|
onChange(tempValue)
|
||||||
|
onBlur()
|
||||||
|
bindingDrawer.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
setContext("binding-drawer-actions", {
|
||||||
|
save: saveBinding,
|
||||||
|
})
|
||||||
|
|
||||||
|
const onChange = value => {
|
||||||
|
if (type === "link" && value && hasValidLinks(value)) {
|
||||||
|
currentVal = value.split(",")
|
||||||
|
} else if (type === "array" && value && hasValidOptions(value)) {
|
||||||
|
currentVal = value.split(",")
|
||||||
|
} else {
|
||||||
|
currentVal = readableToRuntimeBinding(bindings, value)
|
||||||
|
}
|
||||||
|
dispatch("change", currentVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur = () => {
|
||||||
|
dispatch("blur", currentVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidDate = value => {
|
||||||
|
return !value || !isNaN(new Date(value).valueOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasValidLinks = value => {
|
||||||
|
let links = []
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
links = value
|
||||||
|
} else if (value && typeof value === "string") {
|
||||||
|
links = value.split(",")
|
||||||
|
} else {
|
||||||
|
return !value
|
||||||
|
}
|
||||||
|
|
||||||
|
return links.every(link => link.startsWith("ro_"))
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasValidOptions = value => {
|
||||||
|
let links = []
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
links = value
|
||||||
|
} else if (value && typeof value === "string") {
|
||||||
|
links = value.split(",")
|
||||||
|
} else {
|
||||||
|
return !value
|
||||||
|
}
|
||||||
|
return links.every(link => schema?.constraints?.inclusion?.includes(link))
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidBoolean = value => {
|
||||||
|
return value === "false" || value === "true" || value == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const validationMap = {
|
||||||
|
date: isValidDate,
|
||||||
|
datetime: isValidDate,
|
||||||
|
link: hasValidLinks,
|
||||||
|
array: hasValidOptions,
|
||||||
|
longform: value => !isJSBinding(value),
|
||||||
|
json: value => !isJSBinding(value),
|
||||||
|
boolean: isValidBoolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValid = value => {
|
||||||
|
const validate = validationMap[type]
|
||||||
|
return validate ? validate(value) : true
|
||||||
|
}
|
||||||
|
|
||||||
|
const getIconClass = (value, type) => {
|
||||||
|
if (type === "longform" && !isJSBinding(value)) {
|
||||||
|
return "text-area-slot-icon"
|
||||||
|
}
|
||||||
|
if (type === "json" && !isJSBinding(value)) {
|
||||||
|
return "json-slot-icon"
|
||||||
|
}
|
||||||
|
if (type !== "string" && type !== "number") {
|
||||||
|
return "slot-icon"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="control" class:disabled>
|
||||||
|
{#if !isValid(value)}
|
||||||
|
<Input
|
||||||
|
{label}
|
||||||
|
{disabled}
|
||||||
|
readonly={isJS}
|
||||||
|
value={isJS ? "(JavaScript function)" : readableValue}
|
||||||
|
on:change={event => onChange(event.detail)}
|
||||||
|
on:blur={onBlur}
|
||||||
|
{placeholder}
|
||||||
|
{updateOnChange}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="icon"
|
||||||
|
on:click={() => {
|
||||||
|
if (!isJS) {
|
||||||
|
dispatch("change", "")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon disabled={isJS} size="S" name="Close" />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<slot
|
||||||
|
{label}
|
||||||
|
{disabled}
|
||||||
|
readonly={isJS}
|
||||||
|
value={isJS ? "(JavaScript function)" : readableValue}
|
||||||
|
{placeholder}
|
||||||
|
{updateOnChange}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if !disabled}
|
||||||
|
<div
|
||||||
|
class={`icon ${getIconClass(value, type)}`}
|
||||||
|
on:click={() => {
|
||||||
|
bindingDrawer.show()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon size="S" name="FlashOn" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<Drawer
|
||||||
|
on:drawerHide
|
||||||
|
on:drawerShow
|
||||||
|
{fillWidth}
|
||||||
|
bind:this={bindingDrawer}
|
||||||
|
{title}
|
||||||
|
left={drawerLeft}
|
||||||
|
headless
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="description">
|
||||||
|
Add the objects on the left to enrich your text.
|
||||||
|
</svelte:fragment>
|
||||||
|
<Button cta slot="buttons" disabled={!valid} on:click={saveBinding}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<svelte:component
|
||||||
|
this={panel}
|
||||||
|
slot="body"
|
||||||
|
bind:valid
|
||||||
|
value={readableValue}
|
||||||
|
on:change={event => (tempValue = event.detail)}
|
||||||
|
{bindings}
|
||||||
|
{allowJS}
|
||||||
|
{allowHelpers}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.control {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slot-icon {
|
||||||
|
right: 31px !important;
|
||||||
|
border-right: 1px solid var(--spectrum-alias-border-color);
|
||||||
|
border-top-right-radius: 0px !important;
|
||||||
|
border-bottom-right-radius: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area-slot-icon {
|
||||||
|
border-bottom: 1px solid var(--spectrum-alias-border-color);
|
||||||
|
border-bottom-right-radius: 0px !important;
|
||||||
|
top: 26px !important;
|
||||||
|
}
|
||||||
|
.json-slot-icon {
|
||||||
|
border-bottom: 1px solid var(--spectrum-alias-border-color);
|
||||||
|
border-bottom-right-radius: 0px !important;
|
||||||
|
top: 23px !important;
|
||||||
|
right: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
right: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
position: absolute;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-left: 1px solid var(--spectrum-alias-border-color);
|
||||||
|
border-top-right-radius: var(--spectrum-alias-border-radius-regular);
|
||||||
|
border-bottom-right-radius: var(--spectrum-alias-border-radius-regular);
|
||||||
|
width: 31px;
|
||||||
|
color: var(--spectrum-alias-text-color);
|
||||||
|
background-color: var(--spectrum-global-color-gray-75);
|
||||||
|
transition: background-color
|
||||||
|
var(--spectrum-global-animation-duration-100, 130ms),
|
||||||
|
box-shadow var(--spectrum-global-animation-duration-100, 130ms),
|
||||||
|
border-color var(--spectrum-global-animation-duration-100, 130ms);
|
||||||
|
height: calc(var(--spectrum-alias-item-height-m) - 2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--spectrum-alias-text-color-hover);
|
||||||
|
background-color: var(--spectrum-global-color-gray-50);
|
||||||
|
border-color: var(--spectrum-alias-border-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control:not(.disabled) :global(.spectrum-Textfield-input) {
|
||||||
|
padding-right: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -78,8 +78,7 @@ export const definition: AutomationStepSchema = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function run({ inputs }: AutomationStepInput) {
|
export async function run({ inputs }: AutomationStepInput) {
|
||||||
//TODO - Remove deprecated values 1,2,3,4,5 after November 2023
|
const { url, body } = inputs
|
||||||
const { url, value1, value2, value3, value4, value5, body } = inputs
|
|
||||||
|
|
||||||
let payload = {}
|
let payload = {}
|
||||||
try {
|
try {
|
||||||
|
@ -104,11 +103,6 @@ export async function run({ inputs }: AutomationStepInput) {
|
||||||
response = await fetch(url, {
|
response = await fetch(url, {
|
||||||
method: "post",
|
method: "post",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
value1,
|
|
||||||
value2,
|
|
||||||
value3,
|
|
||||||
value4,
|
|
||||||
value5,
|
|
||||||
...payload,
|
...payload,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -71,8 +71,7 @@ export const definition: AutomationStepSchema = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function run({ inputs }: AutomationStepInput) {
|
export async function run({ inputs }: AutomationStepInput) {
|
||||||
//TODO - Remove deprecated values 1,2,3,4,5 after November 2023
|
const { url, body } = inputs
|
||||||
const { url, value1, value2, value3, value4, value5, body } = inputs
|
|
||||||
|
|
||||||
let payload = {}
|
let payload = {}
|
||||||
try {
|
try {
|
||||||
|
@ -100,11 +99,6 @@ export async function run({ inputs }: AutomationStepInput) {
|
||||||
method: "post",
|
method: "post",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
platform: "budibase",
|
platform: "budibase",
|
||||||
value1,
|
|
||||||
value2,
|
|
||||||
value3,
|
|
||||||
value4,
|
|
||||||
value5,
|
|
||||||
...payload,
|
...payload,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
|
|
Loading…
Reference in New Issue