Add initial work on evaluation of conditional UI conditions in client library
This commit is contained in:
parent
4bdfb49742
commit
5e5332cd4f
|
@ -530,6 +530,11 @@ export const getFrontendStore = () => {
|
||||||
selected._styles = { normal: {}, hover: {}, active: {} }
|
selected._styles = { normal: {}, hover: {}, active: {} }
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
},
|
},
|
||||||
|
updateConditions: async conditions => {
|
||||||
|
const selected = get(selectedComponent)
|
||||||
|
selected._conditions = conditions
|
||||||
|
await store.actions.preview.saveSelected()
|
||||||
|
},
|
||||||
updateProp: async (name, value) => {
|
updateProp: async (name, value) => {
|
||||||
let component = get(selectedComponent)
|
let component = get(selectedComponent)
|
||||||
if (!name || !component) {
|
if (!name || !component) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { DetailSummary, ActionButton, Drawer, Button } from "@budibase/bbui"
|
import { DetailSummary, ActionButton, Drawer, Button } from "@budibase/bbui"
|
||||||
// import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
|
import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
|
||||||
|
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
@ -9,12 +9,12 @@
|
||||||
let drawer
|
let drawer
|
||||||
|
|
||||||
const openDrawer = () => {
|
const openDrawer = () => {
|
||||||
tempValue = componentInstance?._conditions
|
tempValue = JSON.parse(JSON.stringify(componentInstance?._conditions ?? []))
|
||||||
drawer.show()
|
drawer.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
// store.actions.components.updateCustomStyle(tempValue)
|
store.actions.components.updateConditions(tempValue)
|
||||||
drawer.hide()
|
drawer.hide()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,11 +8,18 @@
|
||||||
import { hashString } from "../utils/hash"
|
import { hashString } from "../utils/hash"
|
||||||
import Manifest from "@budibase/standard-components/manifest.json"
|
import Manifest from "@budibase/standard-components/manifest.json"
|
||||||
import { Placeholder } from "@budibase/standard-components"
|
import { Placeholder } from "@budibase/standard-components"
|
||||||
|
import {
|
||||||
|
getActiveConditions,
|
||||||
|
reduceConditionActions,
|
||||||
|
} from "../utils/conditions"
|
||||||
|
|
||||||
export let instance = {}
|
export let instance = {}
|
||||||
|
|
||||||
// Props that will be passed to the component instance
|
// The enriched component settings
|
||||||
let componentProps
|
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
|
// Props are hashed when inside the builder preview and used as a key, so that
|
||||||
// components fully remount whenever any props change
|
// components fully remount whenever any props change
|
||||||
|
@ -28,6 +35,9 @@
|
||||||
let lastContextKey
|
let lastContextKey
|
||||||
let lastInstanceKey
|
let lastInstanceKey
|
||||||
|
|
||||||
|
// Visibility flag used by conditional UI
|
||||||
|
let visible = true
|
||||||
|
|
||||||
// Get contexts
|
// Get contexts
|
||||||
const context = getContext("context")
|
const context = getContext("context")
|
||||||
const insideScreenslot = !!getContext("screenslot")
|
const insideScreenslot = !!getContext("screenslot")
|
||||||
|
@ -54,6 +64,8 @@
|
||||||
$builderStore.inBuilder &&
|
$builderStore.inBuilder &&
|
||||||
$builderStore.selectedComponentId === instance._id
|
$builderStore.selectedComponentId === instance._id
|
||||||
$: interactive = $builderStore.previewType === "layout" || insideScreenslot
|
$: interactive = $builderStore.previewType === "layout" || insideScreenslot
|
||||||
|
$: evaluateConditions(enrichedSettings?._conditions)
|
||||||
|
$: componentSettings = { ...enrichedSettings, ...conditionalSettings }
|
||||||
|
|
||||||
// Update component context
|
// Update component context
|
||||||
$: componentStore.set({
|
$: componentStore.set({
|
||||||
|
@ -62,14 +74,14 @@
|
||||||
styles: { ...instance._styles, id, empty, interactive },
|
styles: { ...instance._styles, id, empty, interactive },
|
||||||
empty,
|
empty,
|
||||||
selected,
|
selected,
|
||||||
props: componentProps,
|
props: componentSettings,
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
|
|
||||||
const getRawProps = instance => {
|
const getRawProps = instance => {
|
||||||
let validProps = {}
|
let validProps = {}
|
||||||
Object.entries(instance)
|
Object.entries(instance)
|
||||||
.filter(([name]) => !name.startsWith("_"))
|
.filter(([name]) => name === "_conditions" || !name.startsWith("_"))
|
||||||
.forEach(([key, value]) => {
|
.forEach(([key, value]) => {
|
||||||
validProps[key] = value
|
validProps[key] = value
|
||||||
})
|
})
|
||||||
|
@ -123,34 +135,63 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let propsChanged = false
|
let propsChanged = false
|
||||||
if (!componentProps) {
|
if (!enrichedSettings) {
|
||||||
componentProps = {}
|
enrichedSettings = {}
|
||||||
propsChanged = true
|
propsChanged = true
|
||||||
}
|
}
|
||||||
Object.keys(enrichedProps).forEach(key => {
|
Object.keys(enrichedProps).forEach(key => {
|
||||||
if (!propsAreSame(enrichedProps[key], componentProps[key])) {
|
if (!propsAreSame(enrichedProps[key], enrichedSettings[key])) {
|
||||||
propsChanged = true
|
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
|
// Update the hash if we're in the builder so we can fully remount this
|
||||||
// component
|
// component
|
||||||
if (get(builderStore).inBuilder && propsChanged) {
|
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>
|
</script>
|
||||||
|
|
||||||
<div
|
{#key propsHash}
|
||||||
class={`component ${id}`}
|
{#if constructor && componentSettings && visible}
|
||||||
data-type={interactive ? "component" : ""}
|
<div
|
||||||
data-id={id}
|
class={`component ${id}`}
|
||||||
data-name={name}
|
data-type={interactive ? "component" : ""}
|
||||||
>
|
data-id={id}
|
||||||
{#key propsHash}
|
data-name={name}
|
||||||
{#if constructor && componentProps}
|
class:hidden={!visible}
|
||||||
<svelte:component this={constructor} {...componentProps}>
|
>
|
||||||
|
<svelte:component this={constructor} {...componentSettings}>
|
||||||
{#if children.length}
|
{#if children.length}
|
||||||
{#each children as child (child._id)}
|
{#each children as child (child._id)}
|
||||||
<svelte:self instance={child} />
|
<svelte:self instance={child} />
|
||||||
|
@ -159,9 +200,9 @@
|
||||||
<Placeholder />
|
<Placeholder />
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:component>
|
</svelte:component>
|
||||||
{/if}
|
</div>
|
||||||
{/key}
|
{/if}
|
||||||
</div>
|
{/key}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.component {
|
.component {
|
||||||
|
|
|
@ -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 }
|
||||||
|
}
|
Loading…
Reference in New Issue