Move lucene options into common file and add initial work on conditional UI components

This commit is contained in:
Andrew Kingston 2021-07-21 08:46:02 +01:00
parent 616f4c1e45
commit 0c80e8c5b5
5 changed files with 277 additions and 80 deletions

View File

@ -0,0 +1,38 @@
<script>
import { DetailSummary, ActionButton, Drawer, Button } from "@budibase/bbui"
// import { store } from "builderStore"
import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
export let componentInstance
let tempValue
let drawer
const openDrawer = () => {
tempValue = componentInstance?._conditions
drawer.show()
}
const save = () => {
// store.actions.components.updateCustomStyle(tempValue)
drawer.hide()
}
</script>
<DetailSummary
name={`Conditions${componentInstance?._conditions ? " *" : ""}`}
collapsible={false}
>
<div>
<ActionButton on:click={openDrawer}>Configure conditions</ActionButton>
</div>
</DetailSummary>
{#key componentInstance?._id}
<Drawer bind:this={drawer} title="Conditions">
<svelte:fragment slot="description">
Show, hide and update components in response to conditions being met.
</svelte:fragment>
<Button cta slot="buttons" on:click={save}>Save</Button>
<ConditionalUIDrawer slot="body" bind:conditions={tempValue} />
</Drawer>
{/key}

View File

@ -5,6 +5,7 @@
import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
import DesignSection from "./DesignSection.svelte"
import CustomStylesSection from "./CustomStylesSection.svelte"
import ConditionalUISection from "./ConditionalUISection.svelte"
$: componentInstance = $selectedComponent
$: componentDefinition = store.actions.components.getDefinition(
@ -19,6 +20,7 @@
<ComponentSettingsSection {componentInstance} {componentDefinition} />
<DesignSection {componentInstance} {componentDefinition} />
<CustomStylesSection {componentInstance} {componentDefinition} />
<ConditionalUISection {componentInstance} {componentDefinition} />
</div>
</Tab>
</Tabs>

View File

@ -0,0 +1,156 @@
<script>
import { Button, Icon, DrawerContent, Layout, Select } from "@budibase/bbui"
import { flip } from "svelte/animate"
import { dndzone } from "svelte-dnd-action"
import { generate } from "shortid"
import DrawerBindableInput from "../../../common/bindings/DrawerBindableInput.svelte"
import ColorPicker from "./ColorPicker.svelte"
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
import { getBindableProperties } from "../../../../builderStore/dataBinding"
import { currentAsset, store } from "../../../../builderStore"
export let conditions = []
const flipDurationMs = 150
const actionOptions = [
{
label: "Show component",
value: "show",
},
{
label: "Hide component",
value: "hide",
},
{
label: "Update component setting",
value: "update",
},
]
$: operatorOptions = getValidOperatorsForType("string")
$: bindableProperties = getBindableProperties(
$currentAsset,
$store.selectedComponentId
)
$: conditions.forEach(link => {
if (!link.id) {
link.id = generate()
}
})
const addCondition = () => {
conditions = [
...conditions,
{
action: "show",
operator: OperatorOptions.Equals.value,
},
]
}
const removeLink = id => {
conditions = conditions.filter(link => link.id !== id)
}
const updateLinks = e => {
conditions = e.detail.items
}
</script>
<DrawerContent>
<div class="container">
<Layout noPadding>
{#if conditions?.length}
<div
class="conditions"
use:dndzone={{
items: conditions,
flipDurationMs,
dropTargetStyle: { outline: "none" },
}}
on:finalize={updateLinks}
on:consider={updateLinks}
>
{#each conditions as condition (condition.id)}
<div class="condition" animate:flip={{ duration: flipDurationMs }}>
<Select
placeholder={null}
options={actionOptions}
bind:value={condition.action}
/>
{#if condition.action === "update"}
<Select options={["Color"]} bind:value={condition.setting} />
<div>TO</div>
<ColorPicker
on:change={e => (condition.settingValue = e.detail)}
value={condition.settingValue}
/>
{/if}
<div>IF</div>
<DrawerBindableInput
bindings={bindableProperties}
placeholder="Value"
value={condition.newValue}
on:change={e => (condition.newValue = e.detail)}
/>
<Select
placeholder={null}
options={operatorOptions}
bind:value={condition.operator}
/>
<DrawerBindableInput
bindings={bindableProperties}
placeholder="Value"
value={condition.referenceValue}
on:change={e => (condition.referenceValue = e.detail)}
/>
<Icon
name="Close"
hoverable
size="S"
on:click={() => removeLink(condition.id)}
/>
</div>
{/each}
</div>
{/if}
<div class="button-container">
<Button secondary icon="Add" on:click={addCondition}>
Add condition
</Button>
</div>
</Layout>
</div>
</DrawerContent>
<style>
.container {
width: 100%;
max-width: 1200px;
}
.conditions {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: var(--spacing-s);
}
.condition {
gap: var(--spacing-l);
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-radius: var(--border-radius-s);
transition: background-color ease-in-out 130ms;
}
.condition:hover {
background-color: var(--spectrum-global-color-gray-100);
}
.condition > :global(.spectrum-Form-item) {
flex: 1 1 auto;
width: 0;
}
.button-container {
}
</style>

View File

@ -11,44 +11,11 @@
import { getBindableProperties } from "builderStore/dataBinding"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
import { generate } from "shortid"
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
export let schemaFields
export let value
const OperatorOptions = {
Equals: {
value: "equal",
label: "Equals",
},
NotEquals: {
value: "notEqual",
label: "Not equals",
},
Empty: {
value: "empty",
label: "Is empty",
},
NotEmpty: {
value: "notEmpty",
label: "Is not empty",
},
StartsWith: {
value: "string",
label: "Starts with",
},
Like: {
value: "fuzzy",
label: "Like",
},
MoreThan: {
value: "rangeLow",
label: "More than",
},
LessThan: {
value: "rangeHigh",
label: "Less than",
},
}
const BannedTypes = ["link", "attachment"]
$: bindableProperties = getBindableProperties(
$currentAsset,
@ -75,52 +42,6 @@
value = value.filter(field => field.id !== id)
}
const getValidOperatorsForType = type => {
const Op = OperatorOptions
if (type === "string") {
return [
Op.Equals,
Op.NotEquals,
Op.StartsWith,
Op.Like,
Op.Empty,
Op.NotEmpty,
]
} else if (type === "number") {
return [
Op.Equals,
Op.NotEquals,
Op.MoreThan,
Op.LessThan,
Op.Empty,
Op.NotEmpty,
]
} else if (type === "options") {
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
} else if (type === "boolean") {
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
} else if (type === "longform") {
return [
Op.Equals,
Op.NotEquals,
Op.StartsWith,
Op.Like,
Op.Empty,
Op.NotEmpty,
]
} else if (type === "datetime") {
return [
Op.Equals,
Op.NotEquals,
Op.MoreThan,
Op.LessThan,
Op.Empty,
Op.NotEmpty,
]
}
return []
}
const onFieldChange = (expression, field) => {
// Update the field type
expression.type = schemaFields.find(x => x.name === field)?.type

View File

@ -0,0 +1,80 @@
export const OperatorOptions = {
Equals: {
value: "equal",
label: "Equals",
},
NotEquals: {
value: "notEqual",
label: "Not equals",
},
Empty: {
value: "empty",
label: "Is empty",
},
NotEmpty: {
value: "notEmpty",
label: "Is not empty",
},
StartsWith: {
value: "string",
label: "Starts with",
},
Like: {
value: "fuzzy",
label: "Like",
},
MoreThan: {
value: "rangeLow",
label: "More than",
},
LessThan: {
value: "rangeHigh",
label: "Less than",
},
}
export const getValidOperatorsForType = type => {
const Op = OperatorOptions
if (type === "string") {
return [
Op.Equals,
Op.NotEquals,
Op.StartsWith,
Op.Like,
Op.Empty,
Op.NotEmpty,
]
} else if (type === "number") {
return [
Op.Equals,
Op.NotEquals,
Op.MoreThan,
Op.LessThan,
Op.Empty,
Op.NotEmpty,
]
} else if (type === "options") {
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
} else if (type === "boolean") {
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
} else if (type === "longform") {
return [
Op.Equals,
Op.NotEquals,
Op.StartsWith,
Op.Like,
Op.Empty,
Op.NotEmpty,
]
} else if (type === "datetime") {
return [
Op.Equals,
Op.NotEquals,
Op.MoreThan,
Op.LessThan,
Op.Empty,
Op.NotEmpty,
]
}
return []
}