Remove deprecated code around data binding
This commit is contained in:
parent
df89876cb4
commit
10f8e53305
|
@ -2,6 +2,9 @@ import { get } from "svelte/store"
|
||||||
import { backendUiStore, store } from "builderStore"
|
import { backendUiStore, store } from "builderStore"
|
||||||
import { findAllMatchingComponents, findComponentPath } from "./storeUtils"
|
import { findAllMatchingComponents, findComponentPath } from "./storeUtils"
|
||||||
|
|
||||||
|
// Regex to match mustache variables, for replacing bindings
|
||||||
|
const CAPTURE_VAR_INSIDE_MUSTACHE = /{{([^}]+)}}/g
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all bindable data context fields and instance fields.
|
* Gets all bindable data context fields and instance fields.
|
||||||
*/
|
*/
|
||||||
|
@ -20,22 +23,47 @@ export const getBindableContexts = (rootComponent, componentId) => {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the component tree leading up to this component
|
// Get the component tree leading up to this component, ignoring the component
|
||||||
|
// itself
|
||||||
const path = findComponentPath(rootComponent, componentId)
|
const path = findComponentPath(rootComponent, componentId)
|
||||||
path.pop()
|
path.pop()
|
||||||
|
|
||||||
// Extract any components which provide data contexts
|
// Enrich components with their definitions
|
||||||
const dataProviders = path.filter(component => {
|
const enriched = path.map(component => ({
|
||||||
const def = store.actions.components.getDefinition(component._component)
|
instance: component,
|
||||||
return def?.dataProvider
|
definition: store.actions.components.getDefinition(component._component),
|
||||||
})
|
}))
|
||||||
|
|
||||||
|
// Extract any components which provide data contexts
|
||||||
|
const providers = enriched.filter(comp => comp.definition?.dataProvider)
|
||||||
let contexts = []
|
let contexts = []
|
||||||
dataProviders.forEach(provider => {
|
providers.forEach(({ definition, instance }) => {
|
||||||
if (!provider.datasource) {
|
// Extract datasource from component instance
|
||||||
|
const datasourceSetting = definition.settings.find(setting => {
|
||||||
|
return setting.key === definition.datasourceSetting
|
||||||
|
})
|
||||||
|
if (!datasourceSetting) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { schema, table } = getSchemaForDatasource(provider.datasource)
|
|
||||||
|
// There are different types of setting which can be a datasource, for
|
||||||
|
// example an actual datasource object, or a table ID string.
|
||||||
|
// Convert the datasource setting into a proper datasource object so that
|
||||||
|
// we can use it properly
|
||||||
|
let datasource
|
||||||
|
if (datasourceSetting.type === "datasource") {
|
||||||
|
datasource = instance[datasourceSetting?.key]
|
||||||
|
} else if (datasourceSetting.type === "table") {
|
||||||
|
datasource = {
|
||||||
|
tableId: instance[datasourceSetting?.key],
|
||||||
|
type: "table",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!datasource) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { schema, table } = getSchemaForDatasource(datasource)
|
||||||
const keys = Object.keys(schema).sort()
|
const keys = Object.keys(schema).sort()
|
||||||
keys.forEach(key => {
|
keys.forEach(key => {
|
||||||
const fieldSchema = schema[key]
|
const fieldSchema = schema[key]
|
||||||
|
@ -49,11 +77,11 @@ export const getBindableContexts = (rootComponent, componentId) => {
|
||||||
|
|
||||||
contexts.push({
|
contexts.push({
|
||||||
type: "context",
|
type: "context",
|
||||||
runtimeBinding: `${provider._id}.${runtimeBoundKey}`,
|
runtimeBinding: `${instance._id}.${runtimeBoundKey}`,
|
||||||
readableBinding: `${provider._instanceName}.${table.name}.${key}`,
|
readableBinding: `${instance._instanceName}.${table.name}.${key}`,
|
||||||
fieldSchema,
|
fieldSchema,
|
||||||
providerId: provider._id,
|
providerId: instance._id,
|
||||||
tableId: provider.datasource.tableId,
|
tableId: datasource.tableId,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -110,3 +138,39 @@ const getSchemaForDatasource = datasource => {
|
||||||
}
|
}
|
||||||
return { schema, table }
|
return { schema, table }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a readable data binding into a runtime data binding
|
||||||
|
*/
|
||||||
|
export function readableToRuntimeBinding(bindableProperties, textWithBindings) {
|
||||||
|
const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE) || []
|
||||||
|
let result = textWithBindings
|
||||||
|
boundValues.forEach(boundValue => {
|
||||||
|
const binding = bindableProperties.find(({ readableBinding }) => {
|
||||||
|
return boundValue === `{{ ${readableBinding} }}`
|
||||||
|
})
|
||||||
|
if (binding) {
|
||||||
|
result = result.replace(boundValue, `{{ ${binding.runtimeBinding} }}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a runtime data binding into a readable data binding
|
||||||
|
*/
|
||||||
|
export function runtimeToReadableBinding(bindableProperties, textWithBindings) {
|
||||||
|
const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE) || []
|
||||||
|
let result = textWithBindings
|
||||||
|
boundValues.forEach(boundValue => {
|
||||||
|
const binding = bindableProperties.find(({ runtimeBinding }) => {
|
||||||
|
return boundValue === `{{ ${runtimeBinding} }}`
|
||||||
|
})
|
||||||
|
// Show invalid bindings as invalid rather than a long ID
|
||||||
|
result = result.replace(
|
||||||
|
boundValue,
|
||||||
|
`{{ ${binding?.readableBinding ?? "Invalid binding"} }}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
import { cloneDeep, difference } from "lodash/fp"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* parameter for fetchBindableProperties function
|
|
||||||
* @typedef {Object} fetchBindablePropertiesParameter
|
|
||||||
* @property {string} componentInstanceId - an _id of a component that has been added to a screen, which you want to fetch bindable props for
|
|
||||||
* @propperty {Object} screen - current screen - where componentInstanceId lives
|
|
||||||
* @property {Object} components - dictionary of component definitions
|
|
||||||
* @property {Array} tables - array of all tables
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @typedef {Object} BindableProperty
|
|
||||||
* @property {string} type - either "instance" (binding to a component instance) or "context" (binding to data in context e.g. List Item)
|
|
||||||
* @property {Object} instance - relevant component instance. If "context" type, this instance is the component that provides the context... e.g. the List
|
|
||||||
* @property {string} runtimeBinding - a binding string that is a) saved against the string, and b) used at runtime to read/write the value
|
|
||||||
* @property {string} readableBinding - a binding string that is displayed to the user, in the builder
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates all allowed bindings from within any particular component instance
|
|
||||||
* @param {fetchBindablePropertiesParameter} param
|
|
||||||
* @returns {Array.<BindableProperty>}
|
|
||||||
*/
|
|
||||||
export default function({ componentInstanceId, screen, components, tables }) {
|
|
||||||
const result = walk({
|
|
||||||
// cloning so we are free to mutate props (e.g. by adding _contexts)
|
|
||||||
instance: cloneDeep(screen.props),
|
|
||||||
targetId: componentInstanceId,
|
|
||||||
components,
|
|
||||||
tables,
|
|
||||||
})
|
|
||||||
|
|
||||||
return [
|
|
||||||
...result.bindableInstances
|
|
||||||
.filter(isInstanceInSharedContext(result))
|
|
||||||
.map(componentInstanceToBindable),
|
|
||||||
...(result.target?._contexts.map(contextToBindables(tables)).flat() ?? []),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const isInstanceInSharedContext = walkResult => i =>
|
|
||||||
// should cover
|
|
||||||
// - neither are in any context
|
|
||||||
// - both in same context
|
|
||||||
// - instance is in ancestor context of target
|
|
||||||
i.instance._contexts.length <= walkResult.target._contexts.length &&
|
|
||||||
difference(i.instance._contexts, walkResult.target._contexts).length === 0
|
|
||||||
|
|
||||||
// turns a component instance prop into binding expressions
|
|
||||||
// used by the UI
|
|
||||||
const componentInstanceToBindable = i => {
|
|
||||||
return {
|
|
||||||
type: "instance",
|
|
||||||
instance: i.instance,
|
|
||||||
// how the binding expression persists, and is used in the app at runtime
|
|
||||||
runtimeBinding: `${i.instance._id}`,
|
|
||||||
// how the binding exressions looks to the user of the builder
|
|
||||||
readableBinding: `${i.instance._instanceName}`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextToBindables = tables => context => {
|
|
||||||
const tableId = context.table?.tableId ?? context.table
|
|
||||||
const table = tables.find(table => table._id === tableId)
|
|
||||||
let schema =
|
|
||||||
context.table?.type === "view"
|
|
||||||
? table?.views?.[context.table.name]?.schema
|
|
||||||
: table?.schema
|
|
||||||
|
|
||||||
// Avoid crashing whenever no data source has been selected
|
|
||||||
if (!schema) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const newBindable = ([key, fieldSchema]) => {
|
|
||||||
// Replace certain bindings with a new property to help display components
|
|
||||||
let runtimeBoundKey = key
|
|
||||||
if (fieldSchema.type === "link") {
|
|
||||||
runtimeBoundKey = `${key}_count`
|
|
||||||
} else if (fieldSchema.type === "attachment") {
|
|
||||||
runtimeBoundKey = `${key}_first`
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: "context",
|
|
||||||
fieldSchema,
|
|
||||||
instance: context.instance,
|
|
||||||
// how the binding expression persists, and is used in the app at runtime
|
|
||||||
runtimeBinding: `${context.instance._id}.${runtimeBoundKey}`,
|
|
||||||
// how the binding expressions looks to the user of the builder
|
|
||||||
readableBinding: `${context.instance._instanceName}.${table.name}.${key}`,
|
|
||||||
// table / view info
|
|
||||||
table: context.table,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stringType = { type: "string" }
|
|
||||||
return (
|
|
||||||
Object.entries(schema)
|
|
||||||
.map(newBindable)
|
|
||||||
// add _id and _rev fields - not part of schema, but always valid
|
|
||||||
.concat([
|
|
||||||
newBindable(["_id", stringType]),
|
|
||||||
newBindable(["_rev", stringType]),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const walk = ({ instance, targetId, components, tables, result }) => {
|
|
||||||
if (!result) {
|
|
||||||
result = {
|
|
||||||
target: null,
|
|
||||||
bindableInstances: [],
|
|
||||||
allContexts: [],
|
|
||||||
currentContexts: [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!instance._contexts) instance._contexts = []
|
|
||||||
|
|
||||||
// "component" is the component definition (object in component.json)
|
|
||||||
const component = components[instance._component]
|
|
||||||
|
|
||||||
if (instance._id === targetId) {
|
|
||||||
// found it
|
|
||||||
result.target = instance
|
|
||||||
} else {
|
|
||||||
if (component && component.bindable) {
|
|
||||||
// pushing all components in here initially
|
|
||||||
// but this will not be correct, as some of
|
|
||||||
// these components will be in another context
|
|
||||||
// but we dont know this until the end of the walk
|
|
||||||
// so we will filter in another method
|
|
||||||
result.bindableInstances.push({
|
|
||||||
instance,
|
|
||||||
prop: component.bindable,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// a component that provides context to it's children
|
|
||||||
const contextualInstance =
|
|
||||||
component && component.context && instance[component.context]
|
|
||||||
|
|
||||||
if (contextualInstance) {
|
|
||||||
// add to currentContexts (ancestory of context)
|
|
||||||
// before walking children
|
|
||||||
const table = instance[component.context]
|
|
||||||
result.currentContexts.push({ instance, table })
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentContexts = [...result.currentContexts]
|
|
||||||
for (let child of instance._children || []) {
|
|
||||||
// attaching _contexts of components, for eas comparison later
|
|
||||||
// these have been deep cloned above, so shouln't modify the
|
|
||||||
// original component instances
|
|
||||||
child._contexts = currentContexts
|
|
||||||
walk({ instance: child, targetId, components, tables, result })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contextualInstance) {
|
|
||||||
// child walk done, remove from currentContexts
|
|
||||||
result.currentContexts.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
export const CAPTURE_VAR_INSIDE_MUSTACHE = /{{([^}]+)}}/g
|
|
||||||
|
|
||||||
export function readableToRuntimeBinding(bindableProperties, textWithBindings) {
|
|
||||||
// Find all instances of mustasche
|
|
||||||
const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE)
|
|
||||||
|
|
||||||
let result = textWithBindings
|
|
||||||
// Replace readableBindings with runtimeBindings
|
|
||||||
boundValues &&
|
|
||||||
boundValues.forEach(boundValue => {
|
|
||||||
const binding = bindableProperties.find(({ readableBinding }) => {
|
|
||||||
return boundValue === `{{ ${readableBinding} }}`
|
|
||||||
})
|
|
||||||
if (binding) {
|
|
||||||
result = result.replace(boundValue, `{{ ${binding.runtimeBinding} }}`)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export function runtimeToReadableBinding(bindableProperties, textWithBindings) {
|
|
||||||
let temp = textWithBindings
|
|
||||||
const boundValues =
|
|
||||||
(typeof textWithBindings === "string" &&
|
|
||||||
textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE)) ||
|
|
||||||
[]
|
|
||||||
|
|
||||||
// Replace runtimeBindings with readableBindings:
|
|
||||||
boundValues.forEach(v => {
|
|
||||||
const binding = bindableProperties.find(({ runtimeBinding }) => {
|
|
||||||
return v === `{{ ${runtimeBinding} }}`
|
|
||||||
})
|
|
||||||
temp = temp.replace(
|
|
||||||
v,
|
|
||||||
`{{ ${binding?.readableBinding ?? "Invalid binding"} }}`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return temp
|
|
||||||
}
|
|
|
@ -1,24 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Label } from "@budibase/bbui"
|
import { Select, Label } from "@budibase/bbui"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
|
||||||
import SaveFields from "./SaveFields.svelte"
|
import SaveFields from "./SaveFields.svelte"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
|
||||||
$: bindableProperties = fetchBindableProperties({
|
|
||||||
componentInstanceId: $store.selectedComponentId,
|
|
||||||
components: $store.components,
|
|
||||||
screen: $currentAsset,
|
|
||||||
tables: $backendUiStore.tables,
|
|
||||||
})
|
|
||||||
|
|
||||||
// just wraps binding in {{ ... }}
|
|
||||||
const toBindingExpression = bindingPath => `{{ ${bindingPath} }}`
|
|
||||||
|
|
||||||
const tableFields = tableId => {
|
const tableFields = tableId => {
|
||||||
const table = $backendUiStore.tables.find(m => m._id === tableId)
|
const table = $backendUiStore.tables.find(m => m._id === tableId)
|
||||||
|
|
||||||
return Object.keys(table.schema).map(k => ({
|
return Object.keys(table.schema).map(k => ({
|
||||||
name: k,
|
name: k,
|
||||||
type: table.schema[k].type,
|
type: table.schema[k].type,
|
||||||
|
@ -58,17 +46,8 @@
|
||||||
grid-template-columns: auto 1fr auto 1fr auto;
|
grid-template-columns: auto 1fr auto 1fr auto;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root :global(> div:nth-child(2)) {
|
.root :global(> div:nth-child(2)) {
|
||||||
grid-column-start: 2;
|
grid-column-start: 2;
|
||||||
grid-column-end: 6;
|
grid-column-end: 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cannot-use {
|
|
||||||
color: var(--red);
|
|
||||||
font-size: var(--font-size-s);
|
|
||||||
text-align: center;
|
|
||||||
width: 70%;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Label } from "@budibase/bbui"
|
import { Select, Label } from "@budibase/bbui"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
|
||||||
let idFields
|
let idFields
|
||||||
|
|
||||||
$: bindableProperties = fetchBindableProperties({
|
$: bindableProperties = getBindableProperties(
|
||||||
componentInstanceId: $store.selectedComponentId,
|
$currentAsset.props,
|
||||||
components: $store.components,
|
$store.selectedComponentId
|
||||||
screen: $currentAsset,
|
)
|
||||||
tables: $backendUiStore.tables,
|
|
||||||
})
|
|
||||||
|
|
||||||
$: idFields = bindableProperties.filter(
|
$: idFields = bindableProperties.filter(
|
||||||
bindable =>
|
bindable =>
|
||||||
bindable.type === "context" && bindable.runtimeBinding.endsWith("._id")
|
bindable.type === "context" && bindable.runtimeBinding.endsWith("._id")
|
||||||
)
|
)
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (parameters.rowId) {
|
if (parameters.rowId) {
|
||||||
// Set rev ID
|
// Set rev ID
|
||||||
|
|
|
@ -1,23 +1,34 @@
|
||||||
<script>
|
<script>
|
||||||
// accepts an array of field names, and outputs an object of { FieldName: value }
|
|
||||||
import { DataList, Label, TextButton, Spacer, Select, Input } from "@budibase/bbui"
|
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
|
||||||
import { CloseCircleIcon, AddIcon } from "components/common/Icons"
|
|
||||||
import {
|
import {
|
||||||
|
DataList,
|
||||||
|
Label,
|
||||||
|
TextButton,
|
||||||
|
Spacer,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import { store, currentAsset } from "builderStore"
|
||||||
|
import {
|
||||||
|
getBindableProperties,
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
runtimeToReadableBinding,
|
runtimeToReadableBinding,
|
||||||
} from "builderStore/replaceBindings"
|
} from "builderStore/dataBinding"
|
||||||
|
import { CloseCircleIcon, AddIcon } from "components/common/Icons"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let parameterFields
|
export let parameterFields
|
||||||
export let schemaFields
|
export let schemaFields
|
||||||
export let fieldLabel="Column"
|
export let fieldLabel = "Column"
|
||||||
|
|
||||||
const emptyField = () => ({ name: "", value: "" })
|
const emptyField = () => ({ name: "", value: "" })
|
||||||
|
|
||||||
|
$: bindableProperties = getBindableProperties(
|
||||||
|
$currentAsset.props,
|
||||||
|
$store.selectedComponentId
|
||||||
|
)
|
||||||
|
|
||||||
// this statement initialises fields from parameters.fields
|
// this statement initialises fields from parameters.fields
|
||||||
$: fields =
|
$: fields =
|
||||||
fields ||
|
fields ||
|
||||||
|
@ -32,13 +43,6 @@
|
||||||
"",
|
"",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
$: bindableProperties = fetchBindableProperties({
|
|
||||||
componentInstanceId: $store.selectedComponentId,
|
|
||||||
components: $store.components,
|
|
||||||
screen: $currentAsset,
|
|
||||||
tables: $backendUiStore.tables,
|
|
||||||
})
|
|
||||||
|
|
||||||
const addField = () => {
|
const addField = () => {
|
||||||
const newFields = fields.filter(f => f.name)
|
const newFields = fields.filter(f => f.name)
|
||||||
newFields.push(emptyField())
|
newFields.push(emptyField())
|
||||||
|
@ -60,7 +64,9 @@
|
||||||
// value and type is needed by the client, so it can parse
|
// value and type is needed by the client, so it can parse
|
||||||
// a string into a correct type
|
// a string into a correct type
|
||||||
newParameterFields[field.name] = {
|
newParameterFields[field.name] = {
|
||||||
type: schemaFields ? schemaFields.find(f => f.name === field.name).type : "string",
|
type: schemaFields
|
||||||
|
? schemaFields.find(f => f.name === field.name).type
|
||||||
|
: "string",
|
||||||
value: readableToRuntimeBinding(bindableProperties, field.value),
|
value: readableToRuntimeBinding(bindableProperties, field.value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +89,7 @@
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</Select>
|
||||||
{:else}
|
{:else}
|
||||||
<Input secondary bind:value={field.name} on:blur={rebuildParameters}/>
|
<Input secondary bind:value={field.name} on:blur={rebuildParameters} />
|
||||||
{/if}
|
{/if}
|
||||||
<Label size="m" color="dark">Value</Label>
|
<Label size="m" color="dark">Value</Label>
|
||||||
<DataList secondary bind:value={field.value} on:blur={rebuildParameters}>
|
<DataList secondary bind:value={field.value} on:blur={rebuildParameters}>
|
||||||
|
@ -105,7 +111,8 @@
|
||||||
<Spacer small />
|
<Spacer small />
|
||||||
|
|
||||||
<TextButton text small blue on:click={addField}>
|
<TextButton text small blue on:click={addField}>
|
||||||
Add {fieldLabel}
|
Add
|
||||||
|
{fieldLabel}
|
||||||
<div style="height: 20px; width: 20px;">
|
<div style="height: 20px; width: 20px;">
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Label } from "@budibase/bbui"
|
import { Select, Label } from "@budibase/bbui"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
import SaveFields from "./SaveFields.svelte"
|
import SaveFields from "./SaveFields.svelte"
|
||||||
import {
|
|
||||||
readableToRuntimeBinding,
|
|
||||||
runtimeToReadableBinding,
|
|
||||||
} from "builderStore/replaceBindings"
|
|
||||||
|
|
||||||
// parameters.contextPath used in the client handler to determine which row to save
|
// parameters.contextPath used in the client handler to determine which row to save
|
||||||
// this could be "data" or "data.parent", "data.parent.parent" etc
|
// this could be "data" or "data.parent", "data.parent.parent" etc
|
||||||
|
@ -15,12 +11,10 @@
|
||||||
let idFields
|
let idFields
|
||||||
let schemaFields
|
let schemaFields
|
||||||
|
|
||||||
$: bindableProperties = fetchBindableProperties({
|
$: bindableProperties = getBindableProperties(
|
||||||
componentInstanceId: $store.selectedComponentId,
|
$currentAsset.props,
|
||||||
components: $store.components,
|
$store.selectedComponentId
|
||||||
screen: $currentAsset,
|
)
|
||||||
tables: $backendUiStore.tables,
|
|
||||||
})
|
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (parameters && parameters.contextPath) {
|
if (parameters && parameters.contextPath) {
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Label } from "@budibase/bbui"
|
import { Select, Label } from "@budibase/bbui"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
import SaveFields from "./SaveFields.svelte"
|
import SaveFields from "./SaveFields.svelte"
|
||||||
import {
|
|
||||||
readableToRuntimeBinding,
|
|
||||||
runtimeToReadableBinding,
|
|
||||||
} from "builderStore/replaceBindings"
|
|
||||||
|
|
||||||
export let parameters
|
export let parameters
|
||||||
|
|
||||||
$: bindableProperties = fetchBindableProperties({
|
$: bindableProperties = getBindableProperties(
|
||||||
componentInstanceId: $store.selectedComponentId,
|
$currentAsset.props,
|
||||||
components: $store.components,
|
$store.selectedComponentId
|
||||||
screen: $currentAsset,
|
)
|
||||||
tables: $backendUiStore.tables,
|
|
||||||
})
|
|
||||||
|
|
||||||
let idFields
|
let idFields
|
||||||
let rowId
|
let rowId
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { Icon } from "@budibase/bbui"
|
import { Icon } from "@budibase/bbui"
|
||||||
import Input from "./Input.svelte"
|
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAsset } from "builderStore"
|
||||||
import { getBindableProperties } from "builderStore/dataBinding"
|
|
||||||
import {
|
import {
|
||||||
|
getBindableProperties,
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
runtimeToReadableBinding,
|
runtimeToReadableBinding,
|
||||||
} from "builderStore/replaceBindings"
|
} from "builderStore/dataBinding"
|
||||||
import { DropdownMenu } from "@budibase/bbui"
|
import { DropdownMenu } from "@budibase/bbui"
|
||||||
import BindingDropdown from "./BindingDropdown.svelte"
|
import BindingDropdown from "./BindingDropdown.svelte"
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
$: tables = $backendUiStore.tables.map(m => ({
|
$: tables = $backendUiStore.tables.map(m => ({
|
||||||
label: m.name,
|
label: m.name,
|
||||||
name: `all_${m._id}`,
|
|
||||||
tableId: m._id,
|
tableId: m._id,
|
||||||
type: "table",
|
type: "table",
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -106,6 +106,7 @@
|
||||||
"styleable": true,
|
"styleable": true,
|
||||||
"hasChildren": true,
|
"hasChildren": true,
|
||||||
"dataProvider": true,
|
"dataProvider": true,
|
||||||
|
"datasourceSetting": "datasource",
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"type": "datasource",
|
"type": "datasource",
|
||||||
|
@ -410,6 +411,7 @@
|
||||||
"styleable": true,
|
"styleable": true,
|
||||||
"hasChildren": true,
|
"hasChildren": true,
|
||||||
"dataProvider": true,
|
"dataProvider": true,
|
||||||
|
"datasourceSetting": "table",
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"type": "table",
|
"type": "table",
|
||||||
|
|
Loading…
Reference in New Issue