Add binding eval for non relationship fields when editing formula columns

This commit is contained in:
Andrew Kingston 2024-02-27 14:44:25 +00:00
parent 334c6de304
commit 08ad9d9c4e
7 changed files with 65 additions and 52 deletions

View File

@ -36,6 +36,8 @@
import { ValidColumnNameRegex } from "@budibase/shared-core" import { ValidColumnNameRegex } from "@budibase/shared-core"
import { FieldType, FieldSubtype, SourceName } from "@budibase/types" import { FieldType, FieldSubtype, SourceName } from "@budibase/types"
import RelationshipSelector from "components/common/RelationshipSelector.svelte" import RelationshipSelector from "components/common/RelationshipSelector.svelte"
import { RowUtils } from "@budibase/frontend-core"
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
const AUTO_TYPE = FIELDS.AUTO.type const AUTO_TYPE = FIELDS.AUTO.type
const FORMULA_TYPE = FIELDS.FORMULA.type const FORMULA_TYPE = FIELDS.FORMULA.type
@ -93,6 +95,7 @@
} }
let autoColumnInfo = getAutoColumnInformation() let autoColumnInfo = getAutoColumnInformation()
$: rowGoldenSample = RowUtils.generateGoldenSample($rows)
$: if (primaryDisplay) { $: if (primaryDisplay) {
editableColumn.constraints.presence = { allowEmpty: false } editableColumn.constraints.presence = { allowEmpty: false }
} }
@ -667,6 +670,7 @@
</div> </div>
<div class="input-length"> <div class="input-length">
<ModalBindableInput <ModalBindableInput
panel={ServerBindingPanel}
title="Formula" title="Formula"
value={editableColumn.formula} value={editableColumn.formula}
on:change={e => { on:change={e => {
@ -677,6 +681,7 @@
}} }}
bindings={getBindings({ table })} bindings={getBindings({ table })}
allowJS allowJS
context={rowGoldenSample}
/> />
</div> </div>
</div> </div>

View File

@ -23,6 +23,7 @@
export let key export let key
export let disableBindings = false export let disableBindings = false
export let forceModal = false export let forceModal = false
export let context = null
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -102,6 +103,7 @@
{bindings} {bindings}
{allowJS} {allowJS}
{allowHelpers} {allowHelpers}
{context}
/> />
</Drawer> </Drawer>

View File

@ -5,6 +5,7 @@
export let valid export let valid
export let value = "" export let value = ""
export let allowJS = false export let allowJS = false
export let context = null
$: enrichedBindings = enrichBindings(bindings) $: enrichedBindings = enrichBindings(bindings)
@ -23,5 +24,6 @@
bindings={enrichedBindings} bindings={enrichedBindings}
{value} {value}
{allowJS} {allowJS}
{context}
on:change on:change
/> />

View File

@ -28,9 +28,13 @@ import { ActionTypes } from "./constants"
import { fetchDatasourceSchema } from "./utils/schema.js" import { fetchDatasourceSchema } from "./utils/schema.js"
import { getAPIKey } from "./utils/api.js" import { getAPIKey } from "./utils/api.js"
import { enrichButtonActions } from "./utils/buttonActions.js" import { enrichButtonActions } from "./utils/buttonActions.js"
import { generateGoldenSample } from "./utils/components.js"
import { processStringSync, makePropSafe } from "@budibase/string-templates" import { processStringSync, makePropSafe } from "@budibase/string-templates"
import { fetchData, LuceneUtils, Constants } from "@budibase/frontend-core" import {
fetchData,
LuceneUtils,
Constants,
RowUtils,
} from "@budibase/frontend-core"
export default { export default {
API, API,
@ -66,7 +70,7 @@ export default {
processStringSync, processStringSync,
makePropSafe, makePropSafe,
createContextStore, createContextStore,
generateGoldenSample, generateGoldenSample: RowUtils.generateGoldenSample,
// Components // Components
Provider, Provider,

View File

@ -82,52 +82,3 @@ export const findComponentParent = (rootComponent, id, parentComponent) => {
} }
return null return null
} }
/**
* Util to check is a given value is "better" than another. "Betterness" is
* defined as presence and length.
*/
const isBetterSample = (newValue, oldValue) => {
// Prefer non-null values
if (oldValue == null && newValue != null) {
return true
}
// Don't change type
const oldType = typeof oldValue
const newType = typeof newValue
if (oldType !== newType) {
return false
}
// Prefer longer values
if (newType === "string" && newValue.length > oldValue.length) {
return true
}
if (
newType === "object" &&
Object.keys(newValue).length > Object.keys(oldValue).length
) {
return true
}
return false
}
/**
* Generates a best-case example object of the provided samples.
* The generated sample does not necessarily exist - it simply is a sample that
* contains "good" examples for every property of all the samples.
* The generate sample will have a value for all keys across all samples.
*/
export const generateGoldenSample = samples => {
let goldenSample = {}
samples?.forEach(sample => {
Object.keys(sample).forEach(key => {
if (isBetterSample(sample[key], goldenSample[key])) {
goldenSample[key] = sample[key]
}
})
})
return goldenSample
}

View File

@ -3,6 +3,7 @@ export * as JSONUtils from "./json"
export * as CookieUtils from "./cookies" export * as CookieUtils from "./cookies"
export * as RoleUtils from "./roles" export * as RoleUtils from "./roles"
export * as Utils from "./utils" export * as Utils from "./utils"
export * as RowUtils from "./rows"
export { memo, derivedMemo } from "./memo" export { memo, derivedMemo } from "./memo"
export { createWebsocket } from "./websocket" export { createWebsocket } from "./websocket"
export * from "./download" export * from "./download"

View File

@ -0,0 +1,48 @@
/**
* Util to check is a given value is "better" than another. "Betterness" is
* defined as presence and length.
*/
const isBetterSample = (newValue, oldValue) => {
// Prefer non-null values
if (oldValue == null && newValue != null) {
return true
}
// Don't change type
const oldType = typeof oldValue
const newType = typeof newValue
if (oldType !== newType) {
return false
}
// Prefer longer values
if (newType === "string" && newValue.length > oldValue.length) {
return true
}
if (
newType === "object" &&
Object.keys(newValue).length > Object.keys(oldValue).length
) {
return true
}
return false
}
/**
* Generates a best-case example object of the provided samples.
* The generated sample does not necessarily exist - it simply is a sample that
* contains "good" examples for every property of all the samples.
* The generate sample will have a value for all keys across all samples.
*/
export const generateGoldenSample = samples => {
let goldenSample = {}
samples?.slice(0, 100).forEach(sample => {
Object.keys(sample).forEach(key => {
if (isBetterSample(sample[key], goldenSample[key])) {
goldenSample[key] = sample[key]
}
})
})
return goldenSample
}