Merge branch 'master' into BUDI-9038/validate-hbs

This commit is contained in:
Adria Navarro 2025-02-17 14:01:09 +01:00 committed by GitHub
commit 610bdc8d12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 119 additions and 31 deletions

View File

@ -43,7 +43,6 @@
<EditComponentPopover <EditComponentPopover
{anchor} {anchor}
componentInstance={item} componentInstance={item}
{componentBindings}
{bindings} {bindings}
on:change on:change
parseSettings={updatedNestedFlags} parseSettings={updatedNestedFlags}

View File

@ -1,13 +1,13 @@
<script> <script>
import { Icon, Popover, Layout } from "@budibase/bbui" import { Icon, Popover, Layout } from "@budibase/bbui"
import { componentStore } from "@/stores/builder" import { componentStore, selectedScreen } from "@/stores/builder"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { createEventDispatcher, getContext } from "svelte" import { createEventDispatcher, getContext } from "svelte"
import ComponentSettingsSection from "@/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte" import ComponentSettingsSection from "@/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte"
import { getComponentBindableProperties } from "@/dataBinding"
export let anchor export let anchor
export let componentInstance export let componentInstance
export let componentBindings
export let bindings export let bindings
export let parseSettings export let parseSettings
@ -28,6 +28,10 @@
} }
$: componentDef = componentStore.getDefinition(componentInstance._component) $: componentDef = componentStore.getDefinition(componentInstance._component)
$: parsedComponentDef = processComponentDefinitionSettings(componentDef) $: parsedComponentDef = processComponentDefinitionSettings(componentDef)
$: componentBindings = getComponentBindableProperties(
$selectedScreen,
$componentStore.selectedComponentId
)
const open = () => { const open = () => {
isOpen = true isOpen = true

View File

@ -45,7 +45,6 @@
<EditComponentPopover <EditComponentPopover
{anchor} {anchor}
componentInstance={item} componentInstance={item}
{componentBindings}
{bindings} {bindings}
{parseSettings} {parseSettings}
on:change on:change

View File

@ -22,25 +22,59 @@
export let propertyFocus = false export let propertyFocus = false
export let info = null export let info = null
export let disableBindings = false export let disableBindings = false
export let wide export let wide = false
export let contextAccess = null
let highlightType let highlightType
let domElement let domElement
$: highlightedProp = $builderStore.highlightedSetting $: highlightedProp = $builderStore.highlightedSetting
$: allBindings = getAllBindings(bindings, componentBindings, nested) $: allBindings = getAllBindings(
bindings,
componentBindings,
nested,
contextAccess
)
$: safeValue = getSafeValue(value, defaultValue, allBindings) $: safeValue = getSafeValue(value, defaultValue, allBindings)
$: replaceBindings = val => readableToRuntimeBinding(allBindings, val) $: replaceBindings = val => readableToRuntimeBinding(allBindings, val)
$: isHighlighted = highlightedProp?.key === key $: isHighlighted = highlightedProp?.key === key
$: highlightType = isHighlighted ? `highlighted-${highlightedProp?.type}` : "" $: highlightType = isHighlighted ? `highlighted-${highlightedProp?.type}` : ""
$: highlightedProp && isHighlighted && scrollToElement(domElement)
const getAllBindings = (bindings, componentBindings, nested) => { const getAllBindings = (
if (!nested) { bindings,
componentBindings,
nested,
contextAccess
) => {
// contextAccess is a bit of an escape hatch to get around how we render
// certain settings types by using a pseudo component definition, leading
// to problems with the nested flag
if (contextAccess != null) {
// Optionally include global bindings
let allBindings = contextAccess.global ? bindings : []
// Optionally include or exclude self (component) bindings.
// If this is a nested setting then we will already have our own context
// bindings mixed in, so if we don't want self context we need to filter
// them out.
if (contextAccess.self) {
return [...allBindings, ...componentBindings]
} else {
return allBindings.filter(binding => {
return !componentBindings.some(componentBinding => {
return componentBinding.runtimeBinding === binding.runtimeBinding
})
})
}
}
// Otherwise just honour the normal nested flag
if (nested) {
return [...bindings, ...componentBindings]
} else {
return bindings return bindings
} }
return [...(componentBindings || []), ...(bindings || [])]
} }
// Handle a value change of any type // Handle a value change of any type
@ -81,8 +115,6 @@
block: "center", block: "center",
}) })
} }
$: highlightedProp && isHighlighted && scrollToElement(domElement)
</script> </script>
<div <div

View File

@ -147,6 +147,7 @@
{componentInstance} {componentInstance}
{componentDefinition} {componentDefinition}
{bindings} {bindings}
{componentBindings}
/> />
{/if} {/if}
</Panel> </Panel>

View File

@ -151,6 +151,7 @@
propertyFocus={$builderStore.propertyFocus === setting.key} propertyFocus={$builderStore.propertyFocus === setting.key}
info={setting.info} info={setting.info}
disableBindings={setting.disableBindings} disableBindings={setting.disableBindings}
contextAccess={setting.contextAccess}
props={{ props={{
// Generic settings // Generic settings
placeholder: setting.placeholder || null, placeholder: setting.placeholder || null,

View File

@ -19,6 +19,7 @@
export let conditions = [] export let conditions = []
export let bindings = [] export let bindings = []
export let componentBindings = []
const flipDurationMs = 150 const flipDurationMs = 150
const actionOptions = [ const actionOptions = [
@ -55,6 +56,7 @@
] ]
let dragDisabled = true let dragDisabled = true
$: settings = componentStore $: settings = componentStore
.getComponentSettings($selectedComponent?._component) .getComponentSettings($selectedComponent?._component)
?.concat({ ?.concat({
@ -213,7 +215,10 @@
options: definition.options, options: definition.options,
placeholder: definition.placeholder, placeholder: definition.placeholder,
}} }}
nested={definition.nested}
contextAccess={definition.contextAccess}
{bindings} {bindings}
{componentBindings}
/> />
{:else} {:else}
<Select disabled placeholder=" " /> <Select disabled placeholder=" " />

View File

@ -64,7 +64,12 @@
Show, hide and update components in response to conditions being met. Show, hide and update components in response to conditions being met.
</svelte:fragment> </svelte:fragment>
<Button cta slot="buttons" on:click={() => save()}>Save</Button> <Button cta slot="buttons" on:click={() => save()}>Save</Button>
<ConditionalUIDrawer slot="body" bind:conditions={tempValue} {bindings} /> <ConditionalUIDrawer
slot="body"
bind:conditions={tempValue}
{bindings}
{componentBindings}
/>
</Drawer> </Drawer>
<style> <style>

View File

@ -3089,7 +3089,21 @@
{ {
"type": "tableConditions", "type": "tableConditions",
"label": "Conditions", "label": "Conditions",
"key": "conditions" "key": "conditions",
"contextAccess": {
"global": true,
"self": false
}
},
{
"type": "text",
"label": "Format",
"key": "format",
"info": "Changing format will display values as text",
"contextAccess": {
"global": false,
"self": true
}
} }
] ]
}, },
@ -7686,7 +7700,8 @@
{ {
"type": "columns/grid", "type": "columns/grid",
"key": "columns", "key": "columns",
"resetOn": "table" "resetOn": "table",
"nested": true
} }
] ]
}, },

View File

@ -5,7 +5,7 @@
import { get, derived, readable } from "svelte/store" import { get, derived, readable } from "svelte/store"
import { featuresStore } from "@/stores" import { featuresStore } from "@/stores"
import { Grid } from "@budibase/frontend-core" import { Grid } from "@budibase/frontend-core"
// import { processStringSync } from "@budibase/string-templates" import { processStringSync } from "@budibase/string-templates"
// table is actually any datasource, but called table for legacy compatibility // table is actually any datasource, but called table for legacy compatibility
export let table export let table
@ -47,8 +47,8 @@
$: currentTheme = $context?.device?.theme $: currentTheme = $context?.device?.theme
$: darkMode = !currentTheme?.includes("light") $: darkMode = !currentTheme?.includes("light")
$: parsedColumns = getParsedColumns(columns) $: parsedColumns = getParsedColumns(columns)
$: schemaOverrides = getSchemaOverrides(parsedColumns)
$: enrichedButtons = enrichButtons(buttons) $: enrichedButtons = enrichButtons(buttons)
$: schemaOverrides = getSchemaOverrides(parsedColumns, $context)
$: selectedRows = deriveSelectedRows(gridContext) $: selectedRows = deriveSelectedRows(gridContext)
$: styles = patchStyles($component.styles, minHeight) $: styles = patchStyles($component.styles, minHeight)
$: data = { selectedRows: $selectedRows } $: data = { selectedRows: $selectedRows }
@ -97,15 +97,19 @@
})) }))
} }
const getSchemaOverrides = columns => { const getSchemaOverrides = (columns, context) => {
let overrides = {} let overrides = {}
columns.forEach((column, idx) => { columns.forEach((column, idx) => {
overrides[column.field] = { overrides[column.field] = {
displayName: column.label, displayName: column.label,
order: idx, order: idx,
conditions: column.conditions,
visible: !!column.active, visible: !!column.active,
// format: createFormatter(column), conditions: enrichConditions(column.conditions, context),
format: createFormatter(column),
// Small hack to ensure we react to all changes, as our
// memoization cannot compare differences in functions
rand: column.conditions?.length ? Math.random() : null,
} }
if (column.width) { if (column.width) {
overrides[column.field].width = column.width overrides[column.field].width = column.width
@ -114,12 +118,24 @@
return overrides return overrides
} }
// const createFormatter = column => { const enrichConditions = (conditions, context) => {
// if (typeof column.format !== "string" || !column.format.trim().length) { return conditions?.map(condition => {
// return null return {
// } ...condition,
// return row => processStringSync(column.format, { [id]: row }) referenceValue: processStringSync(
// } condition.referenceValue || "",
context
),
}
})
}
const createFormatter = column => {
if (typeof column.format !== "string" || !column.format.trim().length) {
return null
}
return row => processStringSync(column.format, { [id]: row })
}
const enrichButtons = buttons => { const enrichButtons = buttons => {
if (!buttons?.length) { if (!buttons?.length) {

View File

@ -31,7 +31,7 @@ export const deriveStores = (context: StoreContext): ConditionDerivedStore => {
// Derive and memoize the cell conditions present in our columns so that we // Derive and memoize the cell conditions present in our columns so that we
// only recompute condition metadata when absolutely necessary // only recompute condition metadata when absolutely necessary
const conditions = derivedMemo(columns, $columns => { const conditions = derivedMemo(columns, $columns => {
let newConditions = [] let newConditions: UICondition[] = []
for (let column of $columns) { for (let column of $columns) {
for (let condition of column.conditions || []) { for (let condition of column.conditions || []) {
newConditions.push({ newConditions.push({

View File

@ -48,6 +48,11 @@ export interface ComponentSetting {
selectAllFields?: boolean selectAllFields?: boolean
resetOn?: string | string[] resetOn?: string | string[]
settings?: ComponentSetting[] settings?: ComponentSetting[]
nested?: boolean
dependsOn?: DependsOnComponentSetting dependsOn?: DependsOnComponentSetting
sectionDependsOn?: DependsOnComponentSetting sectionDependsOn?: DependsOnComponentSetting
contextAccess?: {
global: boolean
self: boolean
}
} }

View File

@ -1,9 +1,15 @@
import { CalculationType, FieldSchema, FieldType, UIRow } from "@budibase/types" import {
CalculationType,
FieldSchema,
FieldType,
UICondition,
UIRow,
} from "@budibase/types"
export type UIColumn = FieldSchema & { export type UIColumn = FieldSchema & {
label: string label: string
readonly: boolean readonly: boolean
conditions: any conditions?: UICondition[]
format?: (row: UIRow) => any format?: (row: UIRow) => any
related?: { related?: {
field: string field: string

View File

@ -3,7 +3,7 @@ import { FieldType, SearchFilter } from "@budibase/types"
export interface UICondition { export interface UICondition {
column: string column: string
type: FieldType type: FieldType
referenceValue: string referenceValue: any
operator: SearchFilter["operator"] operator: SearchFilter["operator"]
metadataKey: string metadataKey: string
metadataValue: string metadataValue: string