1
0
Fork 0
mirror of synced 2024-07-11 09:15:48 +12:00

Add live eval of bindings

This commit is contained in:
Andrew Kingston 2024-02-02 10:27:29 +00:00
parent a880c5e62a
commit daec133f79
3 changed files with 79 additions and 51 deletions

View file

@ -15,6 +15,7 @@
decodeJSBinding,
encodeJSBinding,
convertToJS,
processStringSync,
} from "@budibase/string-templates"
import {
readableToRuntimeBinding,
@ -59,15 +60,21 @@
let hbsValue = initialValueJS ? null : value
let sidebar = true
let targetMode = null
let expressionResult
$: usingJS = mode === "JavaScript"
$: editorMode = mode == "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
$: editorMode =
mode === "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
$: bindingCompletions = bindingsToCompletions(bindings, editorMode)
$: runtimeExpression = readableToRuntimeBinding(bindings, value)
$: expressionResult = processStringSync(runtimeExpression || "", context)
const updateValue = val => {
valid = isValid(readableToRuntimeBinding(bindings, val))
const runtimeExpression = readableToRuntimeBinding(bindings, val)
valid = isValid(runtimeExpression)
if (valid) {
dispatch("change", val)
expressionResult = processStringSync(runtimeExpression || "", context)
}
}
@ -114,7 +121,7 @@
}
const switchMode = () => {
if (targetMode == "Text") {
if (targetMode === "Text") {
jsValue = null
updateValue(jsValue)
} else {
@ -204,6 +211,11 @@
autofocus={autofocusEditor}
/>
</div>
{#if expressionResult}
<div class="result">
{expressionResult}
</div>
{/if}
<div class="binding-footer">
<div class="messaging">
{#if !valid}
@ -308,6 +320,11 @@
autofocus={autofocusEditor}
/>
</div>
{#if expressionResult}
<div class="result">
{expressionResult}
</div>
{/if}
<div class="binding-footer">
<div class="messaging">
<Icon name="FlashOn" />
@ -515,4 +532,18 @@
.binding-drawer :global(.code-editor > div) {
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>

View file

@ -16,12 +16,8 @@
let popoverAnchor
let hoverTarget
let helpers = handlebarsCompletions()
let selectedCategory
$: searchRgx = new RegExp(search, "ig")
// Icons
$: bindingIcons = bindings?.reduce((acc, ele) => {
if (ele.icon) {
acc[ele.category] = acc[ele.category] || ele.icon
@ -29,10 +25,9 @@
return acc
}, {})
$: categoryIcons = { ...bindingIcons, Helpers: "MagicWand" }
$: categories = Object.entries(groupBy("category", bindings))
$: categoryNames = getCategoryNames(categories)
$: searchRgx = new RegExp(search, "ig")
$: filteredCategories = categories
.map(([name, categoryBindings]) => ({
name,
@ -73,38 +68,35 @@
}
return names
}
const getBindingValue = binding => {
const hbs = `{{ ${binding.runtimeBinding} }}`
return processStringSync(hbs, context)
}
</script>
<span class="detailPopover">
<Popover
align="left-outside"
bind:this={popover}
anchor={popoverAnchor}
maxWidth={300}
maxHeight={300}
dismissible={false}
>
<Popover
align="left-outside"
bind:this={popover}
anchor={popoverAnchor}
maxWidth={400}
maxHeight={300}
dismissible={false}
>
<div class="helper">
<Layout gap="S">
<div class="helper">
{#if hoverTarget.title}
<div class="helper__name">{hoverTarget.title}</div>
{/if}
{#if hoverTarget.description}
<div class="helper__description">
<!-- eslint-disable-next-line svelte/no-at-html-tags-->
{@html hoverTarget.description}
</div>
{/if}
{#if hoverTarget.example}
<pre class="helper__example">{hoverTarget.example}</pre>
{/if}
{#if hoverTarget.val}
<pre>{hoverTarget.val}</pre>
{/if}
</div>
{#if hoverTarget.description}
<div>
<!-- eslint-disable-next-line svelte/no-at-html-tags-->
{@html hoverTarget.description}
</div>
{/if}
{#if hoverTarget.code}
<pre>{hoverTarget.code}</pre>
{/if}
</Layout>
</Popover>
</span>
</div>
</Popover>
<Layout noPadding gap="S">
{#if selectedCategory}
@ -171,14 +163,13 @@
<li
class="binding"
on:mouseenter={e => {
const hbs = `{{ ${binding.runtimeBinding} }}`
const val = processStringSync(hbs, context)
console.log(binding.runtimeBinding, val)
let val = getBindingValue(binding)
if (val === "") {
val = " "
}
popoverAnchor = e.target
hoverTarget = {
title: binding.display?.name || binding.fieldSchema?.name,
description: binding.description,
val,
code: val,
}
popover.show()
e.stopPropagation()
@ -224,19 +215,15 @@
{#each filteredHelpers as helper}
<li
class="binding"
on:click={() => addHelper(helper, mode.name == "javascript")}
on:click={() => addHelper(helper, mode.name === "javascript")}
on:mouseenter={e => {
popoverAnchor = e.target
if (!helper.displayText && helper.description) {
return
}
hoverTarget = {
title: helper.displayText,
description: helper.description,
example: getHelperExample(
helper,
mode.name == "javascript"
),
code: getHelperExample(helper, mode.name === "javascript"),
}
popover.show()
e.stopPropagation()
@ -397,4 +384,16 @@
margin-left: 2px;
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>

View file

@ -150,8 +150,6 @@
onMount(() => {
store.actions.preview.sendEvent("request-context")
})
$: console.log(context)
</script>
{#each sections as section, idx (section.name)}