Update URL settigns to be bindable inputs and update navigate action
This commit is contained in:
parent
47dc6e8598
commit
37b9ba4f6a
|
@ -11,21 +11,24 @@ const CAPTURE_VAR_INSIDE_TEMPLATE = /{{([^}]+)}}/g
|
|||
/**
|
||||
* Gets all bindable data context fields and instance fields.
|
||||
*/
|
||||
export const getBindableProperties = (rootComponent, componentId) => {
|
||||
return getContextBindings(rootComponent, componentId)
|
||||
export const getBindableProperties = (asset, componentId) => {
|
||||
const contextBindings = getContextBindings(asset, componentId)
|
||||
const userBindings = getUserBindings()
|
||||
const urlBindings = getUrlBindings(asset, componentId)
|
||||
return [...contextBindings, ...userBindings, ...urlBindings]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all data provider components above a component.
|
||||
*/
|
||||
export const getDataProviderComponents = (rootComponent, componentId) => {
|
||||
if (!rootComponent || !componentId) {
|
||||
export const getDataProviderComponents = (asset, componentId) => {
|
||||
if (!asset || !componentId) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Get the component tree leading up to this component, ignoring the component
|
||||
// itself
|
||||
const path = findComponentPath(rootComponent, componentId)
|
||||
const path = findComponentPath(asset.props, componentId)
|
||||
path.pop()
|
||||
|
||||
// Filter by only data provider components
|
||||
|
@ -38,18 +41,14 @@ export const getDataProviderComponents = (rootComponent, componentId) => {
|
|||
/**
|
||||
* Gets all data provider components above a component.
|
||||
*/
|
||||
export const getActionProviderComponents = (
|
||||
rootComponent,
|
||||
componentId,
|
||||
actionType
|
||||
) => {
|
||||
if (!rootComponent || !componentId) {
|
||||
export const getActionProviderComponents = (asset, componentId, actionType) => {
|
||||
if (!asset || !componentId) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Get the component tree leading up to this component, ignoring the component
|
||||
// itself
|
||||
const path = findComponentPath(rootComponent, componentId)
|
||||
const path = findComponentPath(asset.props, componentId)
|
||||
path.pop()
|
||||
|
||||
// Filter by only data provider components
|
||||
|
@ -92,13 +91,12 @@ export const getDatasourceForProvider = component => {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets all bindable data contexts. These are fields of schemas of data contexts
|
||||
* provided by data provider components, such as lists or row detail components.
|
||||
* Gets all bindable data properties from component data contexts.
|
||||
*/
|
||||
export const getContextBindings = (rootComponent, componentId) => {
|
||||
const getContextBindings = (asset, componentId) => {
|
||||
// Extract any components which provide data contexts
|
||||
const dataProviders = getDataProviderComponents(rootComponent, componentId)
|
||||
let contextBindings = []
|
||||
const dataProviders = getDataProviderComponents(asset, componentId)
|
||||
let bindings = []
|
||||
|
||||
// Create bindings for each data provider
|
||||
dataProviders.forEach(component => {
|
||||
|
@ -143,7 +141,7 @@ export const getContextBindings = (rootComponent, componentId) => {
|
|||
runtimeBoundKey = `${key}_first`
|
||||
}
|
||||
|
||||
contextBindings.push({
|
||||
bindings.push({
|
||||
type: "context",
|
||||
runtimeBinding: `${makePropSafe(component._id)}.${makePropSafe(
|
||||
runtimeBoundKey
|
||||
|
@ -157,7 +155,14 @@ export const getContextBindings = (rootComponent, componentId) => {
|
|||
})
|
||||
})
|
||||
|
||||
// Add logged in user bindings
|
||||
return bindings
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all bindable properties from the logged in user.
|
||||
*/
|
||||
const getUserBindings = () => {
|
||||
let bindings = []
|
||||
const tables = get(backendUiStore).tables
|
||||
const userTable = tables.find(table => table._id === TableNames.USERS)
|
||||
const schema = {
|
||||
|
@ -176,7 +181,7 @@ export const getContextBindings = (rootComponent, componentId) => {
|
|||
runtimeBoundKey = `${key}_first`
|
||||
}
|
||||
|
||||
contextBindings.push({
|
||||
bindings.push({
|
||||
type: "context",
|
||||
runtimeBinding: `user.${runtimeBoundKey}`,
|
||||
readableBinding: `Current User.${key}`,
|
||||
|
@ -187,7 +192,26 @@ export const getContextBindings = (rootComponent, componentId) => {
|
|||
})
|
||||
})
|
||||
|
||||
return contextBindings
|
||||
return bindings
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all bindable properties from URL parameters.
|
||||
*/
|
||||
const getUrlBindings = asset => {
|
||||
const url = asset?.routing?.route ?? ""
|
||||
const split = url.split("/")
|
||||
let params = []
|
||||
split.forEach(part => {
|
||||
if (part.startsWith(":") && part.length > 1) {
|
||||
params.push(part.replace(/:/g, "").replace(/\?/g, ""))
|
||||
}
|
||||
})
|
||||
return params.map(param => ({
|
||||
type: "context",
|
||||
runtimeBinding: `url.${param}`,
|
||||
readableBinding: `URL.${param}`,
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<script>
|
||||
import { Icon, Input, Drawer, Body, Button } from "@budibase/bbui"
|
||||
import {
|
||||
readableToRuntimeBinding,
|
||||
runtimeToReadableBinding,
|
||||
} from "builderStore/dataBinding"
|
||||
import BindingPanel from "components/design/PropertiesPanel/BindingPanel.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let value = ""
|
||||
export let bindings = []
|
||||
|
||||
let bindingDrawer
|
||||
let tempValue = value
|
||||
|
||||
$: readableValue = runtimeToReadableBinding(bindings, value)
|
||||
|
||||
const handleClose = () => {
|
||||
onChange(tempValue)
|
||||
bindingDrawer.hide()
|
||||
}
|
||||
|
||||
const onChange = value => {
|
||||
dispatch("change", readableToRuntimeBinding(bindings, value))
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="control">
|
||||
<Input
|
||||
thin
|
||||
value={readableValue}
|
||||
on:change={event => onChange(event.detail)}
|
||||
placeholder="/screen" />
|
||||
<div class="icon" on:click={bindingDrawer.show}>
|
||||
<Icon name="lightning" />
|
||||
</div>
|
||||
</div>
|
||||
<Drawer bind:this={bindingDrawer} title="Bindings">
|
||||
<div slot="description">
|
||||
<Body extraSmall grey>
|
||||
Add the objects on the left to enrich your text.
|
||||
</Body>
|
||||
</div>
|
||||
<heading slot="buttons">
|
||||
<Button thin blue on:click={handleClose}>Save</Button>
|
||||
</heading>
|
||||
<div slot="body">
|
||||
<BindingPanel
|
||||
value={readableValue}
|
||||
close={handleClose}
|
||||
on:update={event => (tempValue = event.detail)}
|
||||
bindableProperties={bindings} />
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
<style>
|
||||
.control {
|
||||
flex: 1;
|
||||
margin-left: var(--spacing-l);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon {
|
||||
right: 2px;
|
||||
top: 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;
|
||||
}
|
||||
.icon:hover {
|
||||
color: var(--ink);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
$: value && checkValid()
|
||||
$: bindableProperties = getBindableProperties(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: dispatch("update", value)
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
type: "query",
|
||||
}))
|
||||
$: bindableProperties = getBindableProperties(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: queryBindableProperties = bindableProperties.map(property => ({
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
export let parameters
|
||||
|
||||
$: dataProviderComponents = getDataProviderComponents(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
ds => ds._id === parameters.datasourceId
|
||||
)
|
||||
$: bindableProperties = getBindableProperties(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
).map(property => ({
|
||||
...property,
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
<script>
|
||||
import { DataList, Label } from "@budibase/bbui"
|
||||
import { allScreens } from "builderStore"
|
||||
import { Label } from "@budibase/bbui"
|
||||
import { getBindableProperties } from "builderStore/dataBinding"
|
||||
import { currentAsset, store } from "builderStore"
|
||||
import DrawerBindableInput from "components/common/DrawerBindableInput.svelte"
|
||||
|
||||
export let parameters
|
||||
|
||||
let bindingDrawer
|
||||
let tempValue = parameters.url
|
||||
|
||||
$: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<Label size="m" color="dark">Screen</Label>
|
||||
<DataList secondary bind:value={parameters.url}>
|
||||
<option value="" />
|
||||
{#each $allScreens as screen}
|
||||
<option value={screen.routing.route}>{screen.props._instanceName}</option>
|
||||
{/each}
|
||||
</DataList>
|
||||
<DrawerBindableInput
|
||||
value={parameters.url}
|
||||
on:change={value => (parameters.url = value.detail)}
|
||||
{bindings} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
export let parameters
|
||||
|
||||
$: dataProviders = getDataProviderComponents(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
</script>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
const emptyField = () => ({ name: "", value: "" })
|
||||
|
||||
$: bindableProperties = getBindableProperties(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
export let parameters
|
||||
|
||||
$: dataProviderComponents = getDataProviderComponents(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: providerComponent = dataProviderComponents.find(
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
export let parameters
|
||||
|
||||
$: actionProviders = getActionProviderComponents(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId,
|
||||
"ValidateForm"
|
||||
)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
let valid
|
||||
|
||||
$: bindableProperties = getBindableProperties(
|
||||
$currentAsset.props,
|
||||
$currentAsset,
|
||||
$store.selectedComponentId
|
||||
)
|
||||
$: safeValue = getSafeValue(value, props.defaultValue, bindableProperties)
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
<script>
|
||||
import { DataList } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { store, allScreens, currentAsset } from "builderStore"
|
||||
import { getBindableProperties } from "builderStore/dataBinding"
|
||||
|
||||
export let value = ""
|
||||
|
||||
$: urls = getUrls($allScreens, $currentAsset, $store.selectedComponentId)
|
||||
|
||||
// Update value on blur
|
||||
const dispatch = createEventDispatcher()
|
||||
const handleBlur = () => dispatch("change", value)
|
||||
|
||||
// Get all valid screen URL, as well as detail screens which can be used in
|
||||
// the current data context
|
||||
const getUrls = (screens, asset, componentId) => {
|
||||
// Get all screens which aren't detail screens
|
||||
let urls = screens
|
||||
.filter(screen => !screen.props._component.endsWith("/rowdetail"))
|
||||
.map(screen => ({
|
||||
name: screen.props._instanceName,
|
||||
url: screen.routing.route,
|
||||
sort: screen.props._component,
|
||||
}))
|
||||
|
||||
// Add detail screens enriched with the current data context
|
||||
const bindableProperties = getBindableProperties(asset.props, componentId)
|
||||
screens
|
||||
.filter(screen => screen.props._component.endsWith("/rowdetail"))
|
||||
.forEach(detailScreen => {
|
||||
// Find any _id bindings that match the detail screen's table
|
||||
const binding = bindableProperties.find(p => {
|
||||
return (
|
||||
p.type === "context" &&
|
||||
p.runtimeBinding.endsWith("._id") &&
|
||||
p.tableId === detailScreen.props.table
|
||||
)
|
||||
})
|
||||
if (binding) {
|
||||
urls.push({
|
||||
name: detailScreen.props._instanceName,
|
||||
url: detailScreen.routing.route.replace(
|
||||
":id",
|
||||
`{{ ${binding.runtimeBinding} }}`
|
||||
),
|
||||
sort: detailScreen.props._component,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return urls
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<DataList
|
||||
editable
|
||||
secondary
|
||||
extraThin
|
||||
on:blur={handleBlur}
|
||||
on:change
|
||||
bind:value>
|
||||
<option value="" />
|
||||
{#each urls as url}
|
||||
<option value={url.url}>{url.name}</option>
|
||||
{/each}
|
||||
</DataList>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
div :global(> div) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
</style>
|
|
@ -18,7 +18,6 @@
|
|||
import MultiFieldSelect from "./PropertyControls/MultiFieldSelect.svelte"
|
||||
import SchemaSelect from "./PropertyControls/SchemaSelect.svelte"
|
||||
import EventsEditor from "./PropertyControls/EventsEditor"
|
||||
import ScreenSelect from "./PropertyControls/ScreenSelect.svelte"
|
||||
import DetailScreenSelect from "./PropertyControls/DetailScreenSelect.svelte"
|
||||
import { IconSelect } from "./PropertyControls/IconSelect"
|
||||
import ColorPicker from "./PropertyControls/ColorPicker.svelte"
|
||||
|
@ -62,7 +61,6 @@
|
|||
text: Input,
|
||||
select: OptionSelect,
|
||||
datasource: DatasourceSelect,
|
||||
screen: ScreenSelect,
|
||||
detailScreen: DetailScreenSelect,
|
||||
boolean: Checkbox,
|
||||
number: Input,
|
||||
|
|
|
@ -44,7 +44,7 @@ export const enrichProps = async (props, context) => {
|
|||
let enrichedProps = await enrichDataBindings(validProps, totalContext)
|
||||
|
||||
// Enrich button actions if they exist
|
||||
if (props._component.endsWith("/button") && enrichedProps.onClick) {
|
||||
if (props._component?.endsWith("/button") && enrichedProps.onClick) {
|
||||
enrichedProps.onClick = enrichButtonActions(
|
||||
enrichedProps.onClick,
|
||||
totalContext
|
||||
|
|
|
@ -137,9 +137,10 @@
|
|||
"key": "subheading"
|
||||
},
|
||||
{
|
||||
"type": "screen",
|
||||
"type": "text",
|
||||
"label": "Link URL",
|
||||
"key": "destinationUrl"
|
||||
"key": "destinationUrl",
|
||||
"placeholder": "/screen"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -170,9 +171,10 @@
|
|||
"key": "linkText"
|
||||
},
|
||||
{
|
||||
"type": "screen",
|
||||
"label": "Link Url",
|
||||
"key": "linkUrl"
|
||||
"type": "text",
|
||||
"label": "Link URL",
|
||||
"key": "linkUrl",
|
||||
"placeholder": "/screen"
|
||||
},
|
||||
{
|
||||
"type": "color",
|
||||
|
@ -339,9 +341,10 @@
|
|||
"key": "text"
|
||||
},
|
||||
{
|
||||
"type": "screen",
|
||||
"type": "text",
|
||||
"label": "URL",
|
||||
"key": "url"
|
||||
"key": "url",
|
||||
"placeholder": "/screen"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
|
@ -412,9 +415,10 @@
|
|||
"key": "linkText"
|
||||
},
|
||||
{
|
||||
"type": "screen",
|
||||
"type": "text",
|
||||
"label": "Link URL",
|
||||
"key": "linkUrl"
|
||||
"key": "linkUrl",
|
||||
"placeholder": "/screen"
|
||||
},
|
||||
{
|
||||
"type": "color",
|
||||
|
|
Loading…
Reference in New Issue