Add live eval of bindings
This commit is contained in:
parent
a880c5e62a
commit
daec133f79
|
@ -15,6 +15,7 @@
|
||||||
decodeJSBinding,
|
decodeJSBinding,
|
||||||
encodeJSBinding,
|
encodeJSBinding,
|
||||||
convertToJS,
|
convertToJS,
|
||||||
|
processStringSync,
|
||||||
} from "@budibase/string-templates"
|
} from "@budibase/string-templates"
|
||||||
import {
|
import {
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
|
@ -59,15 +60,21 @@
|
||||||
let hbsValue = initialValueJS ? null : value
|
let hbsValue = initialValueJS ? null : value
|
||||||
let sidebar = true
|
let sidebar = true
|
||||||
let targetMode = null
|
let targetMode = null
|
||||||
|
let expressionResult
|
||||||
|
|
||||||
$: usingJS = mode === "JavaScript"
|
$: usingJS = mode === "JavaScript"
|
||||||
$: editorMode = mode == "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
|
$: editorMode =
|
||||||
|
mode === "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
|
||||||
$: bindingCompletions = bindingsToCompletions(bindings, editorMode)
|
$: bindingCompletions = bindingsToCompletions(bindings, editorMode)
|
||||||
|
$: runtimeExpression = readableToRuntimeBinding(bindings, value)
|
||||||
|
$: expressionResult = processStringSync(runtimeExpression || "", context)
|
||||||
|
|
||||||
const updateValue = val => {
|
const updateValue = val => {
|
||||||
valid = isValid(readableToRuntimeBinding(bindings, val))
|
const runtimeExpression = readableToRuntimeBinding(bindings, val)
|
||||||
|
valid = isValid(runtimeExpression)
|
||||||
if (valid) {
|
if (valid) {
|
||||||
dispatch("change", val)
|
dispatch("change", val)
|
||||||
|
expressionResult = processStringSync(runtimeExpression || "", context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +121,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const switchMode = () => {
|
const switchMode = () => {
|
||||||
if (targetMode == "Text") {
|
if (targetMode === "Text") {
|
||||||
jsValue = null
|
jsValue = null
|
||||||
updateValue(jsValue)
|
updateValue(jsValue)
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,6 +211,11 @@
|
||||||
autofocus={autofocusEditor}
|
autofocus={autofocusEditor}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{#if expressionResult}
|
||||||
|
<div class="result">
|
||||||
|
{expressionResult}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="binding-footer">
|
<div class="binding-footer">
|
||||||
<div class="messaging">
|
<div class="messaging">
|
||||||
{#if !valid}
|
{#if !valid}
|
||||||
|
@ -308,6 +320,11 @@
|
||||||
autofocus={autofocusEditor}
|
autofocus={autofocusEditor}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{#if expressionResult}
|
||||||
|
<div class="result">
|
||||||
|
{expressionResult}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="binding-footer">
|
<div class="binding-footer">
|
||||||
<div class="messaging">
|
<div class="messaging">
|
||||||
<Icon name="FlashOn" />
|
<Icon name="FlashOn" />
|
||||||
|
@ -515,4 +532,18 @@
|
||||||
.binding-drawer :global(.code-editor > div) {
|
.binding-drawer :global(.code-editor > div) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--spectrum-global-color-gray-200);
|
||||||
|
font-size: 14px;
|
||||||
|
padding: var(--spacing-l);
|
||||||
|
border-radius: var(--border-radius-s);
|
||||||
|
font-family: monospace;
|
||||||
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
white-space: pre;
|
||||||
|
word-wrap: anywhere;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -16,12 +16,8 @@
|
||||||
let popoverAnchor
|
let popoverAnchor
|
||||||
let hoverTarget
|
let hoverTarget
|
||||||
let helpers = handlebarsCompletions()
|
let helpers = handlebarsCompletions()
|
||||||
|
|
||||||
let selectedCategory
|
let selectedCategory
|
||||||
|
|
||||||
$: searchRgx = new RegExp(search, "ig")
|
|
||||||
|
|
||||||
// Icons
|
|
||||||
$: bindingIcons = bindings?.reduce((acc, ele) => {
|
$: bindingIcons = bindings?.reduce((acc, ele) => {
|
||||||
if (ele.icon) {
|
if (ele.icon) {
|
||||||
acc[ele.category] = acc[ele.category] || ele.icon
|
acc[ele.category] = acc[ele.category] || ele.icon
|
||||||
|
@ -29,10 +25,9 @@
|
||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {})
|
||||||
$: categoryIcons = { ...bindingIcons, Helpers: "MagicWand" }
|
$: categoryIcons = { ...bindingIcons, Helpers: "MagicWand" }
|
||||||
|
|
||||||
$: categories = Object.entries(groupBy("category", bindings))
|
$: categories = Object.entries(groupBy("category", bindings))
|
||||||
$: categoryNames = getCategoryNames(categories)
|
$: categoryNames = getCategoryNames(categories)
|
||||||
|
$: searchRgx = new RegExp(search, "ig")
|
||||||
$: filteredCategories = categories
|
$: filteredCategories = categories
|
||||||
.map(([name, categoryBindings]) => ({
|
.map(([name, categoryBindings]) => ({
|
||||||
name,
|
name,
|
||||||
|
@ -73,38 +68,35 @@
|
||||||
}
|
}
|
||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getBindingValue = binding => {
|
||||||
|
const hbs = `{{ ${binding.runtimeBinding} }}`
|
||||||
|
return processStringSync(hbs, context)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span class="detailPopover">
|
<Popover
|
||||||
<Popover
|
align="left-outside"
|
||||||
align="left-outside"
|
bind:this={popover}
|
||||||
bind:this={popover}
|
anchor={popoverAnchor}
|
||||||
anchor={popoverAnchor}
|
maxWidth={400}
|
||||||
maxWidth={300}
|
maxHeight={300}
|
||||||
maxHeight={300}
|
dismissible={false}
|
||||||
dismissible={false}
|
>
|
||||||
>
|
<div class="helper">
|
||||||
<Layout gap="S">
|
<Layout gap="S">
|
||||||
<div class="helper">
|
{#if hoverTarget.description}
|
||||||
{#if hoverTarget.title}
|
<div>
|
||||||
<div class="helper__name">{hoverTarget.title}</div>
|
<!-- eslint-disable-next-line svelte/no-at-html-tags-->
|
||||||
{/if}
|
{@html hoverTarget.description}
|
||||||
{#if hoverTarget.description}
|
</div>
|
||||||
<div class="helper__description">
|
{/if}
|
||||||
<!-- eslint-disable-next-line svelte/no-at-html-tags-->
|
{#if hoverTarget.code}
|
||||||
{@html hoverTarget.description}
|
<pre>{hoverTarget.code}</pre>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
|
||||||
{#if hoverTarget.example}
|
|
||||||
<pre class="helper__example">{hoverTarget.example}</pre>
|
|
||||||
{/if}
|
|
||||||
{#if hoverTarget.val}
|
|
||||||
<pre>{hoverTarget.val}</pre>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
</Popover>
|
</div>
|
||||||
</span>
|
</Popover>
|
||||||
|
|
||||||
<Layout noPadding gap="S">
|
<Layout noPadding gap="S">
|
||||||
{#if selectedCategory}
|
{#if selectedCategory}
|
||||||
|
@ -171,14 +163,13 @@
|
||||||
<li
|
<li
|
||||||
class="binding"
|
class="binding"
|
||||||
on:mouseenter={e => {
|
on:mouseenter={e => {
|
||||||
const hbs = `{{ ${binding.runtimeBinding} }}`
|
let val = getBindingValue(binding)
|
||||||
const val = processStringSync(hbs, context)
|
if (val === "") {
|
||||||
console.log(binding.runtimeBinding, val)
|
val = " "
|
||||||
|
}
|
||||||
popoverAnchor = e.target
|
popoverAnchor = e.target
|
||||||
hoverTarget = {
|
hoverTarget = {
|
||||||
title: binding.display?.name || binding.fieldSchema?.name,
|
code: val,
|
||||||
description: binding.description,
|
|
||||||
val,
|
|
||||||
}
|
}
|
||||||
popover.show()
|
popover.show()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
@ -224,19 +215,15 @@
|
||||||
{#each filteredHelpers as helper}
|
{#each filteredHelpers as helper}
|
||||||
<li
|
<li
|
||||||
class="binding"
|
class="binding"
|
||||||
on:click={() => addHelper(helper, mode.name == "javascript")}
|
on:click={() => addHelper(helper, mode.name === "javascript")}
|
||||||
on:mouseenter={e => {
|
on:mouseenter={e => {
|
||||||
popoverAnchor = e.target
|
popoverAnchor = e.target
|
||||||
if (!helper.displayText && helper.description) {
|
if (!helper.displayText && helper.description) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hoverTarget = {
|
hoverTarget = {
|
||||||
title: helper.displayText,
|
|
||||||
description: helper.description,
|
description: helper.description,
|
||||||
example: getHelperExample(
|
code: getHelperExample(helper, mode.name === "javascript"),
|
||||||
helper,
|
|
||||||
mode.name == "javascript"
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
popover.show()
|
popover.show()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
@ -397,4 +384,16 @@
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.helper pre {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.helper :global(p) {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -150,8 +150,6 @@
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
store.actions.preview.sendEvent("request-context")
|
store.actions.preview.sendEvent("request-context")
|
||||||
})
|
})
|
||||||
|
|
||||||
$: console.log(context)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each sections as section, idx (section.name)}
|
{#each sections as section, idx (section.name)}
|
||||||
|
|
Loading…
Reference in New Issue