Add initial work on evaluation of conditional UI conditions in client library

This commit is contained in:
Andrew Kingston 2021-07-21 14:03:49 +01:00
parent 4bdfb49742
commit 5e5332cd4f
4 changed files with 111 additions and 24 deletions

View File

@ -530,6 +530,11 @@ export const getFrontendStore = () => {
selected._styles = { normal: {}, hover: {}, active: {} }
await store.actions.preview.saveSelected()
},
updateConditions: async conditions => {
const selected = get(selectedComponent)
selected._conditions = conditions
await store.actions.preview.saveSelected()
},
updateProp: async (name, value) => {
let component = get(selectedComponent)
if (!name || !component) {

View File

@ -1,6 +1,6 @@
<script>
import { DetailSummary, ActionButton, Drawer, Button } from "@budibase/bbui"
// import { store } from "builderStore"
import { store } from "builderStore"
import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
export let componentInstance
@ -9,12 +9,12 @@
let drawer
const openDrawer = () => {
tempValue = componentInstance?._conditions
tempValue = JSON.parse(JSON.stringify(componentInstance?._conditions ?? []))
drawer.show()
}
const save = () => {
// store.actions.components.updateCustomStyle(tempValue)
store.actions.components.updateConditions(tempValue)
drawer.hide()
}
</script>

View File

@ -8,11 +8,18 @@
import { hashString } from "../utils/hash"
import Manifest from "@budibase/standard-components/manifest.json"
import { Placeholder } from "@budibase/standard-components"
import {
getActiveConditions,
reduceConditionActions,
} from "../utils/conditions"
export let instance = {}
// Props that will be passed to the component instance
let componentProps
// The enriched component settings
let enrichedSettings
// Any prop overrides that need to be applied due to conditional UI
let conditionalSettings
// Props are hashed when inside the builder preview and used as a key, so that
// components fully remount whenever any props change
@ -28,6 +35,9 @@
let lastContextKey
let lastInstanceKey
// Visibility flag used by conditional UI
let visible = true
// Get contexts
const context = getContext("context")
const insideScreenslot = !!getContext("screenslot")
@ -54,6 +64,8 @@
$builderStore.inBuilder &&
$builderStore.selectedComponentId === instance._id
$: interactive = $builderStore.previewType === "layout" || insideScreenslot
$: evaluateConditions(enrichedSettings?._conditions)
$: componentSettings = { ...enrichedSettings, ...conditionalSettings }
// Update component context
$: componentStore.set({
@ -62,14 +74,14 @@
styles: { ...instance._styles, id, empty, interactive },
empty,
selected,
props: componentProps,
props: componentSettings,
name,
})
const getRawProps = instance => {
let validProps = {}
Object.entries(instance)
.filter(([name]) => !name.startsWith("_"))
.filter(([name]) => name === "_conditions" || !name.startsWith("_"))
.forEach(([key, value]) => {
validProps[key] = value
})
@ -123,34 +135,63 @@
return
}
let propsChanged = false
if (!componentProps) {
componentProps = {}
if (!enrichedSettings) {
enrichedSettings = {}
propsChanged = true
}
Object.keys(enrichedProps).forEach(key => {
if (!propsAreSame(enrichedProps[key], componentProps[key])) {
if (!propsAreSame(enrichedProps[key], enrichedSettings[key])) {
propsChanged = true
componentProps[key] = enrichedProps[key]
enrichedSettings[key] = enrichedProps[key]
}
})
// Update the hash if we're in the builder so we can fully remount this
// component
if (get(builderStore).inBuilder && propsChanged) {
propsHash = hashString(JSON.stringify(componentProps))
propsHash = hashString(JSON.stringify(enrichedSettings))
}
}
const evaluateConditions = conditions => {
console.log("evaluating")
console.log(conditions)
if (!conditions?.length) {
return
}
// Default visible to false if there is a show condition
let nextVisible = true
for (let condition of conditions) {
if (condition.action === "show") {
nextVisible = false
}
}
const activeConditions = getActiveConditions(conditions)
console.log(activeConditions)
const result = reduceConditionActions(activeConditions)
conditionalSettings = result.settingUpdates
if (result.visible != null) {
nextVisible = result.visible
}
visible = nextVisible
}
</script>
{#key propsHash}
{#if constructor && componentSettings && visible}
<div
class={`component ${id}`}
data-type={interactive ? "component" : ""}
data-id={id}
data-name={name}
class:hidden={!visible}
>
{#key propsHash}
{#if constructor && componentProps}
<svelte:component this={constructor} {...componentProps}>
<svelte:component this={constructor} {...componentSettings}>
{#if children.length}
{#each children as child (child._id)}
<svelte:self instance={child} />
@ -159,9 +200,9 @@
<Placeholder />
{/if}
</svelte:component>
</div>
{/if}
{/key}
</div>
<style>
.component {

View File

@ -0,0 +1,41 @@
import {
buildLuceneQuery,
luceneQuery,
} from "../../../standard-components/src/lucene"
export const getActiveConditions = conditions => {
if (!conditions?.length) {
return []
}
const luceneCompatibleConditions = conditions.map(condition => {
return {
...condition,
type: "string",
field: "newValue",
value: condition.referenceValue,
}
})
const query = buildLuceneQuery(luceneCompatibleConditions)
console.log(luceneQuery)
return luceneQuery(luceneCompatibleConditions, query)
}
export const reduceConditionActions = conditions => {
let settingUpdates = {}
let visible = null
conditions?.forEach(condition => {
if (condition.action === "show") {
visible = true
} else if (condition.action === "hide") {
visible = false
} else if (condition.setting) {
settingUpdates[condition.setting] = condition.settingValue
}
})
return { settingUpdates, visible }
}