Merge pull request #4390 from Budibase/feature/automation-data-types

Adding ability to toggle between Automation input types.
This commit is contained in:
Peter Clement 2022-03-01 14:00:21 +00:00 committed by GitHub
commit 48d8aaea2a
8 changed files with 212 additions and 77 deletions

View File

@ -33,7 +33,7 @@ filterTests(['smoke', 'all'], () => {
cy.get(".spectrum-Button--cta").click() cy.get(".spectrum-Button--cta").click()
}) })
cy.contains("Setup").click() cy.contains("Setup").click()
cy.get(".spectrum-Picker-label").click() cy.get(".spectrum-Picker-label").eq(1).click()
cy.contains("dog").click() cy.contains("dog").click()
cy.get(".spectrum-Textfield-input") cy.get(".spectrum-Textfield-input")
.first() .first()

View File

@ -57,6 +57,7 @@ const automationActions = store => ({
return state return state
}) })
}, },
save: async automation => { save: async automation => {
const response = await API.updateAutomation(automation) const response = await API.updateAutomation(automation)
store.update(state => { store.update(state => {
@ -130,6 +131,12 @@ const automationActions = store => ({
name: block.name, name: block.name,
}) })
}, },
toggleFieldControl: value => {
store.update(state => {
state.selectedBlock.rowControl = value
return state
})
},
deleteAutomationBlock: block => { deleteAutomationBlock: block => {
store.update(state => { store.update(state => {
const idx = const idx =

View File

@ -3,14 +3,8 @@
import Flowchart from "./FlowChart/FlowChart.svelte" import Flowchart from "./FlowChart/FlowChart.svelte"
$: automation = $automationStore.selectedAutomation?.automation $: automation = $automationStore.selectedAutomation?.automation
function onSelect(block) {
automationStore.update(state => {
state.selectedBlock = block
return state
})
}
</script> </script>
{#if automation} {#if automation}
<Flowchart {automation} {onSelect} /> <Flowchart {automation} />
{/if} {/if}

View File

@ -14,7 +14,7 @@
} from "@budibase/bbui" } from "@budibase/bbui"
export let automation export let automation
export let onSelect
let testDataModal let testDataModal
let blocks let blocks
let confirmDeleteDialog let confirmDeleteDialog
@ -45,7 +45,7 @@
<div class="title"> <div class="title">
<div class="subtitle"> <div class="subtitle">
<Heading size="S">{automation.name}</Heading> <Heading size="S">{automation.name}</Heading>
<div style="display:flex;"> <div style="display:flex; align-items: center;">
<div class="iconPadding"> <div class="iconPadding">
<div class="icon"> <div class="icon">
<Icon <Icon
@ -72,7 +72,7 @@
animate:flip={{ duration: 500 }} animate:flip={{ duration: 500 }}
in:fly|local={{ x: 500, duration: 1500 }} in:fly|local={{ x: 500, duration: 1500 }}
> >
<FlowItem {testDataModal} {onSelect} {block} /> <FlowItem {testDataModal} {block} />
</div> </div>
{/each} {/each}
</div> </div>

View File

@ -10,6 +10,7 @@
Button, Button,
StatusLight, StatusLight,
ActionButton, ActionButton,
Select,
notifications, notifications,
} from "@budibase/bbui" } from "@budibase/bbui"
import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte" import AutomationBlockSetup from "../../SetupPanel/AutomationBlockSetup.svelte"
@ -18,7 +19,6 @@
import ActionModal from "./ActionModal.svelte" import ActionModal from "./ActionModal.svelte"
import { externalActions } from "./ExternalActions" import { externalActions } from "./ExternalActions"
export let onSelect
export let block export let block
export let testDataModal export let testDataModal
let selected let selected
@ -28,6 +28,10 @@
let setupToggled let setupToggled
let blockComplete let blockComplete
$: rowControl = $automationStore.selectedAutomation.automation.rowControl
$: showBindingPicker =
block.stepId === "CREATE_ROW" || block.stepId === "UPDATE_ROW"
$: testResult = $automationStore.selectedAutomation.testResults?.steps.filter( $: testResult = $automationStore.selectedAutomation.testResults?.steps.filter(
step => (block.id ? step.id === block.id : step.stepId === block.stepId) step => (block.id ? step.id === block.id : step.stepId === block.stepId)
) )
@ -44,12 +48,6 @@
$automationStore.selectedAutomation?.automation?.definition?.steps.length + $automationStore.selectedAutomation?.automation?.definition?.steps.length +
1 1
// Logic for hiding / showing the add button.first we check if it has a child
// then we check to see whether its inputs have been commpleted
$: disableAddButton = isTrigger
? $automationStore.selectedAutomation?.automation?.definition?.steps
.length > 0
: !isTrigger && steps.length - blockIdx > 1
$: hasCompletedInputs = Object.keys( $: hasCompletedInputs = Object.keys(
block.schema?.inputs?.properties || {} block.schema?.inputs?.properties || {}
).every(x => block?.inputs[x]) ).every(x => block?.inputs[x])
@ -64,6 +62,26 @@
notifications.error("Error saving notification") notifications.error("Error saving notification")
} }
} }
function toggleFieldControl(evt) {
onSelect(block)
let rowControl
if (evt.detail === "Use values") {
rowControl = false
} else {
rowControl = true
}
automationStore.actions.toggleFieldControl(rowControl)
automationStore.actions.save(
$automationStore.selectedAutomation?.automation
)
}
async function onSelect(block) {
await automationStore.update(state => {
state.selectedBlock = block
return state
})
}
</script> </script>
<div <div
@ -126,16 +144,34 @@
<Layout noPadding gap="S"> <Layout noPadding gap="S">
<div class="splitHeader"> <div class="splitHeader">
<ActionButton <ActionButton
on:click={() => (setupToggled = !setupToggled)} on:click={() => {
onSelect(block)
setupToggled = !setupToggled
}}
quiet quiet
icon={setupToggled ? "ChevronDown" : "ChevronRight"} icon={setupToggled ? "ChevronDown" : "ChevronRight"}
> >
<Detail size="S">Setup</Detail> <Detail size="S">Setup</Detail>
</ActionButton> </ActionButton>
{#if !isTrigger} {#if !isTrigger}
<div on:click={() => deleteStep()}> <div class="block-options">
{#if showBindingPicker}
<div>
<Select
on:change={toggleFieldControl}
quiet
defaultValue="Use values"
autoWidth
value={rowControl ? "Use bindings" : "Use values"}
options={["Use values", "Use bindings"]}
placeholder={null}
/>
</div>
{/if}
<div class="delete-padding" on:click={() => deleteStep()}>
<Icon name="DeleteOutline" /> <Icon name="DeleteOutline" />
</div> </div>
</div>
{/if} {/if}
</div> </div>
@ -180,6 +216,13 @@
{/if} {/if}
<style> <style>
.delete-padding {
padding-left: 30px;
}
.block-options {
display: flex;
align-items: center;
}
.center-items { .center-items {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -227,6 +227,7 @@
/> />
{:else if value.customType === "row"} {:else if value.customType === "row"}
<RowSelector <RowSelector
{block}
value={inputData[key]} value={inputData[key]}
on:change={e => onChange(e, key)} on:change={e => onChange(e, key)}
{bindings} {bindings}

View File

@ -1,26 +1,31 @@
<script> <script>
import { tables } from "stores/backend" import { tables } from "stores/backend"
import { import { Select } from "@budibase/bbui"
Select,
Toggle,
DatePicker,
Multiselect,
TextArea,
} from "@budibase/bbui"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte" import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte" import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
import { automationStore } from "builderStore" import { automationStore } from "builderStore"
import RowSelectorTypes from "./RowSelectorTypes.svelte"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
export let value export let value
export let bindings export let bindings
export let block
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 ?? {})
@ -37,18 +42,48 @@
dispatch("change", value) dispatch("change", value)
} }
const onChange = (e, field) => { const coerce = (value, type) => {
value[field] = e.detail if (type === "boolean") {
if (typeof value === "boolean") {
return value
}
return value === "true"
}
if (type === "number") {
if (typeof value === "number") {
return value
}
return Number(value)
}
if (type === "options") {
return [value]
}
if (type === "array") {
if (Array.isArray(value)) {
return value
}
return value.split(",").map(x => x.trim())
}
if (type === "link") {
if (Array.isArray(value)) {
return value
}
return [value]
}
return value
}
const onChange = (e, field, type) => {
value[field] = coerce(e.detail, type)
dispatch("change", value) dispatch("change", value)
} }
// Ensure any nullish tableId values get set to empty string so // Ensure any nullish tableId values get set to empty string so
// that the select works // that the select works
$: if (value?.tableId == null) value = { tableId: "" } $: if (value?.tableId == null) value = { tableId: "" }
function schemaHasOptions(schema) {
return !!schema.constraints?.inclusion?.length
}
</script> </script>
<Select <Select
@ -62,55 +97,46 @@
<div class="schema-fields"> <div class="schema-fields">
{#each schemaFields as [field, schema]} {#each schemaFields as [field, schema]}
{#if !schema.autocolumn} {#if !schema.autocolumn}
{#if schemaHasOptions(schema) && schema.type !== "array"} {#if schema.type !== "attachment"}
<Select
on:change={e => onChange(e, field)}
label={field}
value={value[field]}
options={schema.constraints.inclusion}
/>
{:else if schema.type === "datetime"}
<DatePicker
label={field}
value={value[field]}
on:change={e => onChange(e, field)}
/>
{:else if schema.type === "boolean"}
<Toggle
text={field}
value={value[field]}
on:change={e => onChange(e, field)}
/>
{:else if schema.type === "array"}
<Multiselect
bind:value={value[field]}
label={field}
options={schema.constraints.inclusion}
/>
{:else if schema.type === "longform"}
<TextArea label={field} bind:value={value[field]} />
{:else if schema.type === "link"}
<LinkedRowSelector bind:linkedRows={value[field]} {schema} />
{:else if schema.type === "string" || schema.type === "number"}
{#if $automationStore.selectedAutomation.automation.testData} {#if $automationStore.selectedAutomation.automation.testData}
<ModalBindableInput {#if !rowControl}
value={value[field]} <RowSelectorTypes
panel={AutomationBindingPanel} {field}
label={field} {schema}
type={value.customType}
on:change={e => onChange(e, field)}
{bindings} {bindings}
{value}
{onChange}
/> />
{:else} {:else}
<DrawerBindableInput <DrawerBindableInput
placeholder={placeholders[schema.type]}
panel={AutomationBindingPanel} panel={AutomationBindingPanel}
value={value[field]} value={Array.isArray(value[field])
on:change={e => onChange(e, field)} ? value[field].join(" ")
: value[field]}
on:change={e => onChange(e, field, schema.type)}
label={field} label={field}
type="string" type="string"
{bindings} {bindings}
fillWidth={true} fillWidth={true}
allowJS={false} allowJS={true}
/>
{/if}
{:else if !rowControl}
<RowSelectorTypes {field} {schema} {bindings} {value} {onChange} />
{:else}
<DrawerBindableInput
placeholder={placeholders[schema.type]}
panel={AutomationBindingPanel}
value={Array.isArray(value[field])
? value[field].join(" ")
: value[field]}
on:change={e => onChange(e, field, schema.type)}
label={field}
type="string"
{bindings}
fillWidth={true}
allowJS={true}
/> />
{/if} {/if}
{/if} {/if}

View File

@ -0,0 +1,64 @@
<script>
import {
Select,
Toggle,
DatePicker,
Multiselect,
TextArea,
} from "@budibase/bbui"
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
export let onChange
export let field
export let schema
export let value
export let bindings
function schemaHasOptions(schema) {
return !!schema.constraints?.inclusion?.length
}
</script>
{#if schemaHasOptions(schema) && schema.type !== "array"}
<Select
on:change={e => onChange(e, field)}
label={field}
value={value[field]}
options={schema.constraints.inclusion}
/>
{:else if schema.type === "datetime"}
<DatePicker
label={field}
value={value[field]}
on:change={e => onChange(e, field)}
/>
{:else if schema.type === "boolean"}
<Toggle
text={field}
value={value[field]}
on:change={e => onChange(e, field)}
/>
{:else if schema.type === "array"}
<Multiselect
bind:value={value[field]}
label={field}
options={schema.constraints.inclusion}
/>
{:else if schema.type === "longform"}
<TextArea label={field} bind:value={value[field]} />
{:else if schema.type === "link"}
<LinkedRowSelector bind:linkedRows={value[field]} {schema} />
{:else if schema.type === "string" || schema.type === "number"}
<DrawerBindableInput
panel={AutomationBindingPanel}
value={value[field]}
on:change={e => onChange(e, field)}
label={field}
type="string"
{bindings}
fillWidth={true}
allowJS={true}
/>
{/if}