binding - backend initial
This commit is contained in:
parent
3a277ad0dc
commit
19bdabfaaf
|
@ -0,0 +1,111 @@
|
|||
export default function({ componentInstanceId, screen, components, models }) {
|
||||
const { target, targetAncestors, bindableInstances, bindableContexts } = walk(
|
||||
{
|
||||
instance: screen.props,
|
||||
targetId: componentInstanceId,
|
||||
components,
|
||||
models,
|
||||
}
|
||||
)
|
||||
|
||||
return [
|
||||
...bindableInstances
|
||||
.filter(isComponentInstanceAvailable)
|
||||
.map(componentInstanceToBindable),
|
||||
...bindableContexts.map(contextToBindables),
|
||||
]
|
||||
}
|
||||
|
||||
const isComponentInstanceAvailable = i => true
|
||||
|
||||
// turns a component instance prop into binding expressions
|
||||
// used by the UI
|
||||
const componentInstanceToBindable = i => ({
|
||||
type: "instance",
|
||||
instance: i.instance,
|
||||
// how the binding expression persists, and is used in the app at runtime
|
||||
runtimeBinding: `state.${i.instance._id}.${i.prop}`,
|
||||
// how the binding exressions looks to the user of the builder
|
||||
readableBinding: `${i.instance._instanceName}`,
|
||||
})
|
||||
|
||||
const contextToBindables = c => {
|
||||
const contextParentNumber = 0
|
||||
const contextParentPath = Array[contextParentNumber]
|
||||
.map(() => "_parent")
|
||||
.join(".")
|
||||
return Object.keys(c.schema).map(k => ({
|
||||
type: "context",
|
||||
instance: c.instance,
|
||||
// how the binding expression persists, and is used in the app at runtime
|
||||
runtimeBinding: `context.${contextParentPath}.${k}`,
|
||||
// how the binding exressions looks to the user of the builder
|
||||
readableBinding: `${c.instance._instanceName}.${c.schema.name}.${k}`,
|
||||
}))
|
||||
}
|
||||
|
||||
const walk = ({ instance, targetId, components, models, result }) => {
|
||||
if (!result) {
|
||||
result = {
|
||||
currentAncestors: [],
|
||||
currentContexts: [],
|
||||
target: null,
|
||||
targetAncestors: [],
|
||||
bindableInstances: [],
|
||||
bindableContexts: [],
|
||||
parentMap: {},
|
||||
}
|
||||
}
|
||||
|
||||
// "component" is the component definition (object in component.json)
|
||||
const component = components[instance._component]
|
||||
const parentInstance =
|
||||
result.currentAncestors.length > 0 &&
|
||||
result.currentAncestors[result.currentAncestors.length - 1]
|
||||
|
||||
if (instance._id === targetId) {
|
||||
// set currentParents to be result parents
|
||||
result.targetAncestors = result.currentAncestors
|
||||
result.bindableContexts = result.currentContexts
|
||||
// found it
|
||||
result.target = instance
|
||||
} else {
|
||||
if (instance.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 metod
|
||||
result.bindableInstances.push({
|
||||
instance,
|
||||
prop: instance.bindable,
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log(instance._component)
|
||||
console.debug(components)
|
||||
// a component that provides context to it's children
|
||||
const contextualInstance = component.context && instance[component.context]
|
||||
|
||||
if (contextualInstance) {
|
||||
// add to currentContexts (ancestory of context)
|
||||
// before walking children
|
||||
const schema = models.find(m => m._id === instance[component.context])
|
||||
.schema
|
||||
result.currentContexts.push({ instance, schema })
|
||||
}
|
||||
|
||||
for (let child of instance._children || []) {
|
||||
result.parentMap[child._id] = parentInstance._id
|
||||
result.currentAncestors.push(instance)
|
||||
walk({ instance, targetId, components, models, result })
|
||||
result.currentAncestors.pop()
|
||||
}
|
||||
|
||||
if (contextualInstance) {
|
||||
// child walk done, remove from currentContexts
|
||||
result.currentContexts.pop()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
import fetchbindableProperties from "../src/builderStore/fetchBindableProperties"
|
||||
|
||||
describe("fetch bindable properties", () => {
|
||||
|
||||
it("should return bindable properties from screen components", () => {
|
||||
const result = fetchbindableProperties({
|
||||
componentInstanceId: "heading-id",
|
||||
...testData()
|
||||
})
|
||||
const componentBinding = result.find(r => r.instance._id === "search-input-id")
|
||||
expect(componentBinding).toBeDefined()
|
||||
expect(componentBinding.type).toBe("instance")
|
||||
expect(componentBinding.runtimeBinding).toBe("state.search-input-id.value")
|
||||
})
|
||||
|
||||
it("should not return bindable components when not in their context", () => {
|
||||
|
||||
})
|
||||
|
||||
it("should return model schema, when inside a context", () => {
|
||||
|
||||
})
|
||||
|
||||
it("should return model schema, for grantparent context", () => {
|
||||
|
||||
})
|
||||
|
||||
it("should return bindable component props, from components in same context", () => {
|
||||
|
||||
})
|
||||
|
||||
it("should not return model props from child context", () => {
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
const testData = () => {
|
||||
|
||||
const screen = {
|
||||
instanceName: "test screen",
|
||||
name: "screen-id",
|
||||
route: "/",
|
||||
props: {
|
||||
_id:"screent-root-id",
|
||||
_component: "@budibase/standard-components/container",
|
||||
_children: [
|
||||
{
|
||||
_id: "heading-id",
|
||||
_instanceName: "list item heading",
|
||||
_component: "@budibase/standard-components/heading",
|
||||
text: "Screen Title"
|
||||
},
|
||||
{
|
||||
_id: "search-input-id",
|
||||
_instanceName: "Search Input",
|
||||
_component: "@budibase/standard-components/input",
|
||||
value: "search phrase"
|
||||
},
|
||||
{
|
||||
_id: "list-id",
|
||||
_component: "@budibase/standard-components/list",
|
||||
_instanceName: "list-name",
|
||||
model: "test-model-id",
|
||||
_children: [
|
||||
{
|
||||
_id: "list-item-heading-id",
|
||||
_instanceName: "list item heading",
|
||||
_component: "@budibase/standard-components/heading",
|
||||
text: "hello"
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const models = [{
|
||||
id: "test-model-id",
|
||||
name: "Test Model",
|
||||
schema: {
|
||||
name: {
|
||||
type: "string"
|
||||
},
|
||||
description: {
|
||||
type: "string"
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
const components = {
|
||||
"@budibase/standard-components/container" : {
|
||||
props: {},
|
||||
},
|
||||
"@budibase/standard-components/list" : {
|
||||
context: "model",
|
||||
props: {
|
||||
model: "string"
|
||||
},
|
||||
},
|
||||
"@budibase/standard-components/input" : {
|
||||
bindable: "value",
|
||||
props: {
|
||||
value: "string"
|
||||
},
|
||||
},
|
||||
"@budibase/standard-components/heading" : {
|
||||
props: {
|
||||
text: "string"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return { screen, models, components }
|
||||
|
||||
}
|
Loading…
Reference in New Issue