forked from tsai/budibase
15 changed files with 359 additions and 55 deletions
@ -0,0 +1,75 @@ |
|||
import { FIELDS } from "constants/backend" |
|||
import { tables } from "stores/backend" |
|||
import { get as svelteGet } from "svelte/store" |
|||
|
|||
// currently supported level of relationship depth (server side)
|
|||
const MAX_DEPTH = 1 |
|||
const TYPES_TO_SKIP = [ |
|||
FIELDS.FORMULA.type, |
|||
FIELDS.LONGFORM.type, |
|||
FIELDS.ATTACHMENT.type, |
|||
] |
|||
|
|||
export function getBindings({ |
|||
table, |
|||
path = null, |
|||
category = null, |
|||
depth = 0, |
|||
}) { |
|||
let bindings = [] |
|||
if (!table) { |
|||
return bindings |
|||
} |
|||
for (let [column, schema] of Object.entries(table.schema)) { |
|||
const isRelationship = schema.type === FIELDS.LINK.type |
|||
// skip relationships after a certain depth and types which
|
|||
// can't bind to
|
|||
if ( |
|||
TYPES_TO_SKIP.includes(schema.type) || |
|||
(isRelationship && depth >= MAX_DEPTH) |
|||
) { |
|||
continue |
|||
} |
|||
category = category == null ? `${table.name} Fields` : category |
|||
if (isRelationship && depth < MAX_DEPTH) { |
|||
const relatedTable = svelteGet(tables).list.find( |
|||
table => table._id === schema.tableId |
|||
) |
|||
const relatedBindings = bindings.concat( |
|||
getBindings({ |
|||
table: relatedTable, |
|||
path: column, |
|||
category: `${column} Relationships`, |
|||
depth: depth + 1, |
|||
}) |
|||
) |
|||
// remove the ones that have already been found
|
|||
bindings = bindings.concat( |
|||
relatedBindings.filter( |
|||
related => !bindings.find(binding => binding.path === related.path) |
|||
) |
|||
) |
|||
} |
|||
const field = Object.values(FIELDS).find( |
|||
field => field.type === schema.type |
|||
) |
|||
const label = path == null ? column : `${path}.0.${column}` |
|||
// only supply a description for relationship paths
|
|||
const description = |
|||
path == null |
|||
? undefined |
|||
: `Update the "0" with the index of relationships or use array helpers` |
|||
bindings.push({ |
|||
label: label, |
|||
type: field.name === FIELDS.LINK.name ? "Array" : field.name, |
|||
category, |
|||
path: label, |
|||
description, |
|||
// don't include path, it messes things up, relationship path
|
|||
// will be replaced by the main array binding
|
|||
readableBinding: column, |
|||
runtimeBinding: `[${column}]`, |
|||
}) |
|||
} |
|||
return bindings |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
<script> |
|||
import { Icon, Input, Modal, Body, ModalContent } from "@budibase/bbui" |
|||
import { |
|||
readableToRuntimeBinding, |
|||
runtimeToReadableBinding, |
|||
} from "builderStore/dataBinding" |
|||
import ServerBindingPanel from "components/common/ServerBindingPanel.svelte" |
|||
import { createEventDispatcher } from "svelte" |
|||
const dispatch = createEventDispatcher() |
|||
|
|||
export let panel = ServerBindingPanel |
|||
export let value = "" |
|||
export let bindings = [] |
|||
export let thin = true |
|||
export let title = "Bindings" |
|||
export let placeholder |
|||
export let label |
|||
|
|||
let bindingModal |
|||
let validity = true |
|||
|
|||
$: readableValue = runtimeToReadableBinding(bindings, value) |
|||
$: tempValue = readableValue |
|||
$: invalid = !validity |
|||
|
|||
const saveBinding = () => { |
|||
onChange(tempValue) |
|||
bindingModal.hide() |
|||
} |
|||
|
|||
const onChange = input => { |
|||
dispatch("change", readableToRuntimeBinding(bindings, input)) |
|||
} |
|||
</script> |
|||
|
|||
<div class="control"> |
|||
<Input |
|||
{label} |
|||
{thin} |
|||
value={readableValue} |
|||
on:change={event => onChange(event.target.value)} |
|||
{placeholder} /> |
|||
<div class="icon" on:click={bindingModal.show}> |
|||
<Icon name="lightning" /> |
|||
</div> |
|||
</div> |
|||
<Modal bind:this={bindingModal} width="50%"> |
|||
<ModalContent |
|||
{title} |
|||
onConfirm={saveBinding} |
|||
bind:disabled={invalid}> |
|||
<Body extraSmall grey> |
|||
Add the objects on the left to enrich your text. |
|||
</Body> |
|||
<svelte:component |
|||
this={panel} |
|||
serverSide |
|||
value={readableValue} |
|||
bind:validity={validity} |
|||
on:update={event => (tempValue = event.detail)} |
|||
bindableProperties={bindings} /> |
|||
</ModalContent> |
|||
</Modal> |
|||
|
|||
<style> |
|||
.control { |
|||
flex: 1; |
|||
position: relative; |
|||
} |
|||
|
|||
.icon { |
|||
right: 2px; |
|||
bottom: 2px; |
|||
position: absolute; |
|||
align-items: center; |
|||
display: flex; |
|||
box-sizing: border-box; |
|||
padding-left: 7px; |
|||
border-left: 1px solid var(--grey-4); |
|||
background-color: var(--grey-2); |
|||
border-top-right-radius: var(--border-radius-m); |
|||
border-bottom-right-radius: var(--border-radius-m); |
|||
color: var(--grey-7); |
|||
font-size: 14px; |
|||
height: 40px; |
|||
} |
|||
|
|||
.icon:hover { |
|||
color: var(--ink); |
|||
cursor: pointer; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue