Move lucene options into common file and add initial work on conditional UI components
This commit is contained in:
parent
616f4c1e45
commit
0c80e8c5b5
|
@ -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}
|
|
@ -5,6 +5,7 @@
|
||||||
import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
|
import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
|
||||||
import DesignSection from "./DesignSection.svelte"
|
import DesignSection from "./DesignSection.svelte"
|
||||||
import CustomStylesSection from "./CustomStylesSection.svelte"
|
import CustomStylesSection from "./CustomStylesSection.svelte"
|
||||||
|
import ConditionalUISection from "./ConditionalUISection.svelte"
|
||||||
|
|
||||||
$: componentInstance = $selectedComponent
|
$: componentInstance = $selectedComponent
|
||||||
$: componentDefinition = store.actions.components.getDefinition(
|
$: componentDefinition = store.actions.components.getDefinition(
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
<ComponentSettingsSection {componentInstance} {componentDefinition} />
|
<ComponentSettingsSection {componentInstance} {componentDefinition} />
|
||||||
<DesignSection {componentInstance} {componentDefinition} />
|
<DesignSection {componentInstance} {componentDefinition} />
|
||||||
<CustomStylesSection {componentInstance} {componentDefinition} />
|
<CustomStylesSection {componentInstance} {componentDefinition} />
|
||||||
|
<ConditionalUISection {componentInstance} {componentDefinition} />
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
|
@ -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>
|
|
@ -11,44 +11,11 @@
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
|
import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
|
||||||
|
|
||||||
export let schemaFields
|
export let schemaFields
|
||||||
export let value
|
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"]
|
const BannedTypes = ["link", "attachment"]
|
||||||
$: bindableProperties = getBindableProperties(
|
$: bindableProperties = getBindableProperties(
|
||||||
$currentAsset,
|
$currentAsset,
|
||||||
|
@ -75,52 +42,6 @@
|
||||||
value = value.filter(field => field.id !== id)
|
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) => {
|
const onFieldChange = (expression, field) => {
|
||||||
// Update the field type
|
// Update the field type
|
||||||
expression.type = schemaFields.find(x => x.name === field)?.type
|
expression.type = schemaFields.find(x => x.name === field)?.type
|
||||||
|
|
|
@ -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 []
|
||||||
|
}
|
Loading…
Reference in New Issue