Add loading indicator and debounce evaluations to fix performance issues with large JSON payloads

This commit is contained in:
Andrew Kingston 2024-02-24 18:17:08 +00:00
parent a27529eca5
commit d666d03328
2 changed files with 37 additions and 9 deletions

View File

@ -1,5 +1,5 @@
<script> <script>
import { DrawerContent, ActionButton, Icon } from "@budibase/bbui" import { DrawerContent, ActionButton, Icon, Helpers } from "@budibase/bbui"
import { createEventDispatcher, getContext, onMount } from "svelte" import { createEventDispatcher, getContext, onMount } from "svelte"
import { import {
isValid, isValid,
@ -26,6 +26,7 @@
import formatHighlight from "json-format-highlight" import formatHighlight from "json-format-highlight"
import { capitalise } from "helpers" import { capitalise } from "helpers"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte" import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
import { Utils } from "@budibase/frontend-core"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -57,6 +58,7 @@
let targetMode = null let targetMode = null
let expressionResult let expressionResult
let drawerIsModal let drawerIsModal
let evaluating = false
$: drawerContext?.modal.subscribe(val => (drawerIsModal = val)) $: drawerContext?.modal.subscribe(val => (drawerIsModal = val))
$: editorTabs = allowJS ? [Modes.Text, Modes.JavaScript] : [Modes.Text] $: editorTabs = allowJS ? [Modes.Text, Modes.JavaScript] : [Modes.Text]
@ -67,9 +69,21 @@
mode === Modes.JavaScript ? EditorModes.JS : EditorModes.Handlebars mode === Modes.JavaScript ? EditorModes.JS : EditorModes.Handlebars
$: bindingCompletions = bindingsToCompletions(enrichedBindings, editorMode) $: bindingCompletions = bindingsToCompletions(enrichedBindings, editorMode)
$: runtimeExpression = readableToRuntimeBinding(enrichedBindings, value) $: runtimeExpression = readableToRuntimeBinding(enrichedBindings, value)
$: expressionResult = processStringSync(runtimeExpression || "", context) $: requestUpdateEvaluation(runtimeExpression, context)
$: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos) $: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos)
const updateEvaluation = (expression, context) => {
expressionResult = processStringSync(expression || "", context)
evaluating = false
}
const debouncedUpdateEvaluation = Utils.debounce(updateEvaluation, 260)
const requestUpdateEvaluation = (expression, context) => {
evaluating = true
debouncedUpdateEvaluation(expression, context)
}
const getBindingValue = (binding, context) => { const getBindingValue = (binding, context) => {
const hbs = `{{ literal ${binding.runtimeBinding} }}` const hbs = `{{ literal ${binding.runtimeBinding} }}`
const res = processStringSync(hbs, context) const res = processStringSync(hbs, context)
@ -103,7 +117,7 @@
valid = isValid(runtimeExpression) valid = isValid(runtimeExpression)
if (valid) { if (valid) {
dispatch("change", val) dispatch("change", val)
expressionResult = processStringSync(runtimeExpression || "", context) requestUpdateEvaluation(runtimeExpression, context)
} }
} }
@ -249,7 +263,7 @@
mode={editorMode} mode={editorMode}
/> />
{:else if sidePanel === SidePanels.Evaluation} {:else if sidePanel === SidePanels.Evaluation}
<EvaluationSidePanel {expressionResult} /> <EvaluationSidePanel {expressionResult} {evaluating} />
{/if} {/if}
</div> </div>
</div> </div>

View File

@ -1,13 +1,16 @@
<script> <script>
import formatHighlight from "json-format-highlight" import formatHighlight from "json-format-highlight"
import { Icon, notifications } from "@budibase/bbui" import { Icon, ProgressCircle, notifications } from "@budibase/bbui"
import { copyToClipboard } from "@budibase/bbui/helpers" import { copyToClipboard } from "@budibase/bbui/helpers"
import { fade } from "svelte/transition"
export let expressionResult export let expressionResult
export let evaluating = false
$: error = expressionResult === "Error while executing JS" $: error = expressionResult === "Error while executing JS"
$: empty = expressionResult == null || expressionResult === "" $: empty = expressionResult == null || expressionResult === ""
$: success = !error && !empty $: success = !error && !empty
$: highlightedResult = highlight(expressionResult)
const highlight = json => { const highlight = json => {
// Attempt to parse and then stringify, in case this is valid JSON // Attempt to parse and then stringify, in case this is valid JSON
@ -16,7 +19,6 @@
} catch (err) { } catch (err) {
// Ignore // Ignore
} }
return formatHighlight(json, { return formatHighlight(json, {
keyColor: "#e06c75", keyColor: "#e06c75",
numberColor: "#e5c07b", numberColor: "#e5c07b",
@ -42,10 +44,22 @@
<div class="header-content"> <div class="header-content">
{#if error} {#if error}
<Icon name="Alert" color="var(--spectrum-global-color-red-600)" /> <Icon name="Alert" color="var(--spectrum-global-color-red-600)" />
<span> Error </span> <div>Error</div>
{#if evaluating}
<div transition:fade|local={{ duration: 130 }}>
<ProgressCircle size="S" />
</div>
{/if}
<span />
<Icon name="Copy" hoverable on:click={copy} /> <Icon name="Copy" hoverable on:click={copy} />
{:else} {:else}
<span>Preview</span> <div>Preview</div>
{#if evaluating}
<div transition:fade|local={{ duration: 130 }}>
<ProgressCircle size="S" />
</div>
{/if}
<span />
{#if !empty} {#if !empty}
<Icon name="Copy" hoverable on:click={copy} /> <Icon name="Copy" hoverable on:click={copy} />
{/if} {/if}
@ -54,7 +68,7 @@
</div> </div>
<div class="body"> <div class="body">
{#if expressionResult} {#if expressionResult}
{@html highlight(expressionResult)} {@html highlightedResult}
{:else} {:else}
Your expression will be evaluated here Your expression will be evaluated here
{/if} {/if}