301 lines
8.6 KiB
Svelte
301 lines
8.6 KiB
Svelte
<script>
|
|
import {
|
|
Button,
|
|
Body,
|
|
Icon,
|
|
DrawerContent,
|
|
Layout,
|
|
Select,
|
|
DatePicker,
|
|
} from "@budibase/bbui"
|
|
import { flip } from "svelte/animate"
|
|
import { dndzone } from "svelte-dnd-action"
|
|
import { generate } from "shortid"
|
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
|
import { LuceneUtils, Constants } from "@budibase/frontend-core"
|
|
import { selectedComponent } from "builderStore"
|
|
import { getComponentForSettingType } from "./componentSettings"
|
|
import PropertyControl from "./PropertyControl.svelte"
|
|
import { getComponentSettings } from "builderStore/componentUtils"
|
|
|
|
export let conditions = []
|
|
export let bindings = []
|
|
|
|
const flipDurationMs = 150
|
|
const actionOptions = [
|
|
{
|
|
label: "Hide component",
|
|
value: "hide",
|
|
},
|
|
{
|
|
label: "Show component",
|
|
value: "show",
|
|
},
|
|
{
|
|
label: "Update setting",
|
|
value: "update",
|
|
},
|
|
]
|
|
const valueTypeOptions = [
|
|
{
|
|
value: "string",
|
|
label: "Binding",
|
|
},
|
|
{
|
|
value: "number",
|
|
label: "Number",
|
|
},
|
|
{
|
|
value: "datetime",
|
|
label: "Date",
|
|
},
|
|
{
|
|
value: "boolean",
|
|
label: "Boolean",
|
|
},
|
|
]
|
|
|
|
let dragDisabled = true
|
|
$: settings = getComponentSettings($selectedComponent?._component)
|
|
$: settingOptions = settings.map(setting => ({
|
|
label: setting.label,
|
|
value: setting.key,
|
|
}))
|
|
$: conditions.forEach(link => {
|
|
if (!link.id) {
|
|
link.id = generate()
|
|
}
|
|
})
|
|
|
|
const getSettingDefinition = key => {
|
|
return settings.find(setting => setting.key === key)
|
|
}
|
|
|
|
const getComponentForSetting = key => {
|
|
const settingDefinition = getSettingDefinition(key)
|
|
return getComponentForSettingType(settingDefinition?.type || "text")
|
|
}
|
|
|
|
const addCondition = () => {
|
|
conditions = [
|
|
...conditions,
|
|
{
|
|
valueType: "string",
|
|
id: generate(),
|
|
action: "hide",
|
|
operator: Constants.OperatorOptions.Equals.value,
|
|
},
|
|
]
|
|
}
|
|
|
|
const removeCondition = id => {
|
|
conditions = conditions.filter(link => link.id !== id)
|
|
}
|
|
|
|
const duplicateCondition = id => {
|
|
const condition = conditions.find(link => link.id === id)
|
|
const duplicate = { ...condition, id: generate() }
|
|
conditions = [...conditions, duplicate]
|
|
}
|
|
|
|
const handleFinalize = e => {
|
|
updateConditions(e)
|
|
dragDisabled = true
|
|
}
|
|
|
|
const updateConditions = e => {
|
|
conditions = e.detail.items
|
|
}
|
|
|
|
const getOperatorOptions = condition => {
|
|
return LuceneUtils.getValidOperatorsForType(condition.valueType)
|
|
}
|
|
|
|
const onOperatorChange = (condition, newOperator) => {
|
|
const noValueOptions = [
|
|
Constants.OperatorOptions.Empty.value,
|
|
Constants.OperatorOptions.NotEmpty.value,
|
|
]
|
|
condition.noValue = noValueOptions.includes(newOperator)
|
|
if (condition.noValue) {
|
|
condition.referenceValue = null
|
|
condition.valueType = "string"
|
|
}
|
|
}
|
|
|
|
const onValueTypeChange = (condition, newType) => {
|
|
condition.referenceValue = null
|
|
|
|
// Ensure a valid operator is set
|
|
const validOperators = LuceneUtils.getValidOperatorsForType(newType).map(
|
|
x => x.value
|
|
)
|
|
if (!validOperators.includes(condition.operator)) {
|
|
condition.operator =
|
|
validOperators[0] ?? Constants.OperatorOptions.Equals.value
|
|
onOperatorChange(condition, condition.operator)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<DrawerContent>
|
|
<div class="container">
|
|
<Layout noPadding>
|
|
{#if conditions?.length}
|
|
<div
|
|
class="conditions"
|
|
use:dndzone={{
|
|
items: conditions,
|
|
flipDurationMs,
|
|
dropTargetStyle: { outline: "none" },
|
|
dragDisabled,
|
|
}}
|
|
on:finalize={handleFinalize}
|
|
on:consider={updateConditions}
|
|
>
|
|
{#each conditions as condition (condition.id)}
|
|
<div
|
|
class="condition"
|
|
class:update={condition.action === "update"}
|
|
animate:flip={{ duration: flipDurationMs }}
|
|
>
|
|
<div
|
|
class="handle"
|
|
aria-label="drag-handle"
|
|
style={dragDisabled ? "cursor: grab" : "cursor: grabbing"}
|
|
on:mousedown={() => (dragDisabled = false)}
|
|
>
|
|
<Icon name="DragHandle" size="XL" />
|
|
</div>
|
|
<Select
|
|
placeholder={null}
|
|
options={actionOptions}
|
|
bind:value={condition.action}
|
|
/>
|
|
{#if condition.action === "update"}
|
|
<Select
|
|
options={settingOptions}
|
|
bind:value={condition.setting}
|
|
/>
|
|
<div>TO</div>
|
|
{#if getSettingDefinition(condition.setting)}
|
|
<PropertyControl
|
|
type={getSettingDefinition(condition.setting).type}
|
|
control={getComponentForSetting(condition.setting)}
|
|
key={getSettingDefinition(condition.setting).key}
|
|
value={condition.settingValue}
|
|
componentInstance={$selectedComponent}
|
|
onChange={val => (condition.settingValue = val)}
|
|
props={{
|
|
options: getSettingDefinition(condition.setting).options,
|
|
placeholder: getSettingDefinition(condition.setting)
|
|
.placeholder,
|
|
}}
|
|
{bindings}
|
|
/>
|
|
{:else}
|
|
<Select disabled placeholder=" " />
|
|
{/if}
|
|
{/if}
|
|
<div>IF</div>
|
|
<DrawerBindableInput
|
|
{bindings}
|
|
placeholder="Value"
|
|
value={condition.newValue}
|
|
on:change={e => (condition.newValue = e.detail)}
|
|
/>
|
|
<Select
|
|
placeholder={null}
|
|
options={getOperatorOptions(condition)}
|
|
bind:value={condition.operator}
|
|
on:change={e => onOperatorChange(condition, e.detail)}
|
|
/>
|
|
<Select
|
|
disabled={condition.noValue}
|
|
options={valueTypeOptions}
|
|
bind:value={condition.valueType}
|
|
placeholder={null}
|
|
on:change={e => onValueTypeChange(condition, e.detail)}
|
|
/>
|
|
{#if ["string", "number"].includes(condition.valueType)}
|
|
<DrawerBindableInput
|
|
disabled={condition.noValue}
|
|
{bindings}
|
|
placeholder="Value"
|
|
value={condition.referenceValue}
|
|
on:change={e => (condition.referenceValue = e.detail)}
|
|
/>
|
|
{:else if condition.valueType === "datetime"}
|
|
<DatePicker
|
|
placeholder="Value"
|
|
disabled={condition.noValue}
|
|
bind:value={condition.referenceValue}
|
|
/>
|
|
{:else if condition.valueType === "boolean"}
|
|
<Select
|
|
placeholder="Value"
|
|
disabled={condition.noValue}
|
|
options={["True", "False"]}
|
|
bind:value={condition.referenceValue}
|
|
/>
|
|
{/if}
|
|
<Icon
|
|
name="Duplicate"
|
|
hoverable
|
|
size="S"
|
|
on:click={() => duplicateCondition(condition.id)}
|
|
/>
|
|
<Icon
|
|
name="Close"
|
|
hoverable
|
|
size="S"
|
|
on:click={() => removeCondition(condition.id)}
|
|
/>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
{:else}
|
|
<Body size="S">Add your first condition to get started.</Body>
|
|
{/if}
|
|
<div>
|
|
<Button secondary icon="Add" on:click={addCondition}>
|
|
Add condition
|
|
</Button>
|
|
</div>
|
|
</Layout>
|
|
</div>
|
|
</DrawerContent>
|
|
|
|
<style>
|
|
.container {
|
|
width: 100%;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
.conditions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: flex-start;
|
|
align-items: stretch;
|
|
gap: var(--spacing-m);
|
|
}
|
|
.condition {
|
|
gap: var(--spacing-l);
|
|
display: grid;
|
|
align-items: center;
|
|
grid-template-columns: auto 160px auto 1fr 130px 130px 1fr auto auto;
|
|
border-radius: var(--border-radius-s);
|
|
transition: background-color ease-in-out 130ms;
|
|
}
|
|
.condition.update {
|
|
grid-template-columns: auto 160px 1fr auto 1fr auto 1fr 130px 130px 1fr auto auto;
|
|
}
|
|
.condition:hover {
|
|
background-color: var(--spectrum-global-color-gray-100);
|
|
}
|
|
.handle {
|
|
display: grid;
|
|
place-items: center;
|
|
}
|
|
</style>
|