From ed403fd79daebbb8649566c5d10dfd7bbe1192a1 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 8 Dec 2023 13:45:51 +0000 Subject: [PATCH 01/67] WIP --- packages/builder/src/builderStore/store/frontend.js | 8 +++++++- .../components/common/bindings/BindingPanel.svelte | 3 +++ .../components/common/bindings/BindingPicker.svelte | 13 +++++++++---- .../common/bindings/ClientBindingPanel.svelte | 3 ++- .../common/bindings/DrawerBindableInput.svelte | 4 +++- .../design/settings/controls/PropertyControl.svelte | 2 ++ .../Component/ComponentSettingsSection.svelte | 9 +++++++++ .../design/[screenId]/_components/AppPreview.svelte | 10 ++++++++++ packages/client/src/index.js | 6 ++++++ 9 files changed, 51 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 2e22276e50..83f72669ee 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -88,7 +88,7 @@ const INITIAL_FRONTEND_STATE = { selectedLayoutId: null, // Client state - selectedComponentInstance: null, + selectedComponentContext: null, // Onboarding onboarding: false, @@ -504,6 +504,12 @@ export const getFrontendStore = () => { return state }) }, + setSelectedComponentContext: context => { + store.update(state => { + state.selectedComponentContext = context + return state + }) + }, }, layouts: { select: layoutId => { diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 4df26c5d03..927b5cb82a 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -45,6 +45,7 @@ export let valid export let allowJS = false export let allowHelpers = true + export let context = null const drawerActions = getContext("drawer-actions") const bindingDrawerActions = getContext("binding-drawer-actions") @@ -250,6 +251,7 @@ import groupBy from "lodash/fp/groupBy" - import { convertToJS } from "@budibase/string-templates" + import { convertToJS, processStringSync } from "@budibase/string-templates" import { Input, Layout, ActionButton, Icon, Popover } from "@budibase/bbui" import { handlebarsCompletions } from "constants/completions" @@ -9,6 +9,7 @@ export let bindings export let mode export let allowHelpers + export let context = null let search = "" let popover @@ -95,6 +96,9 @@ {#if hoverTarget.example}
{hoverTarget.example}
{/if} + {#if hoverTarget.val} +
{hoverTarget.val}
+ {/if} @@ -165,13 +169,14 @@
  • { + const hbs = `{{ ${binding.runtimeBinding} }}` + const val = processStringSync(hbs, context) + console.log(binding.runtimeBinding, val) popoverAnchor = e.target - if (!binding.description) { - return - } hoverTarget = { title: binding.display?.name || binding.fieldSchema?.name, description: binding.description, + val, } popover.show() e.stopPropagation() diff --git a/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte b/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte index 74e14574ab..a46c18af27 100644 --- a/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte @@ -6,7 +6,7 @@ export let value = "" export let allowJS = false export let allowHelpers = true - + export let context = null $: enrichedBindings = enrichBindings(bindings) // Ensure bindings have the correct categories @@ -24,6 +24,7 @@ (tempValue = event.detail)} + {context} {bindings} {allowJS} {allowHelpers} diff --git a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte index a6f3d1b218..2195e8a1b9 100644 --- a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte +++ b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte @@ -24,6 +24,7 @@ export let propertyFocus = false export let info = null export let disableBindings = false + export let context = null $: nullishValue = value == null || value === "" $: allBindings = getAllBindings(bindings, componentBindings, nested) @@ -97,6 +98,7 @@ onChange={handleChange} bindings={allBindings} name={key} + {context} {nested} {key} {type} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte index 6093d2a45e..eb69756626 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte @@ -8,6 +8,7 @@ import { getComponentForSetting } from "components/design/settings/componentSettings" import InfoDisplay from "./InfoDisplay.svelte" import analytics, { Events } from "analytics" + import { onMount } from "svelte" export let componentDefinition export let componentInstance @@ -26,6 +27,7 @@ tag, includeHidden ) + $: context = $store.selectedComponentContext const getSections = (instance, definition, isScreen, tag, includeHidden) => { const settings = definition?.settings ?? [] @@ -145,6 +147,12 @@ } return shouldDisplay(instance, setting) } + + onMount(() => { + store.actions.preview.sendEvent("request-context") + }) + + $: console.log(context) {#each sections as section, idx (section.name)} @@ -191,6 +199,7 @@ min: setting.min ?? null, max: setting.max ?? null, }} + {context} {bindings} {componentBindings} {componentInstance} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index 45fe005ceb..a6820cb551 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -181,6 +181,16 @@ } else if (type === "add-parent-component") { const { componentId, parentType } = data await store.actions.components.addParent(componentId, parentType) + } else if (type === "provide-context") { + let context = data?.context + if (context) { + try { + context = JSON.parse(context) + } catch (error) { + context = null + } + } + store.actions.preview.setSelectedComponentContext(context) } else { console.warn(`Client sent unknown event type: ${type}`) } diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 415d9fa5f2..2d2419eeca 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -75,6 +75,12 @@ const loadBudibase = async () => { } else { dndStore.actions.reset() } + } else if (type === "request-context") { + const { selectedComponentInstance } = get(componentStore) + const context = selectedComponentInstance?.getDataContext() + eventStore.actions.dispatchEvent("provide-context", { + context: JSON.stringify(context), + }) } } From 06556325a1595389faf5db9d829b0e3d14782c4a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 1 Feb 2024 14:45:16 +0000 Subject: [PATCH 02/67] Remove proxying of context changes up the chain --- .../src/components/context/Provider.svelte | 4 +- packages/client/src/stores/context.js | 53 +++++-------------- 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/packages/client/src/components/context/Provider.svelte b/packages/client/src/components/context/Provider.svelte index 1b6a073512..ad5b580c4f 100644 --- a/packages/client/src/components/context/Provider.svelte +++ b/packages/client/src/components/context/Provider.svelte @@ -33,7 +33,7 @@ const provideData = newData => { const dataKey = JSON.stringify(newData) if (dataKey !== lastDataKey) { - context.actions.provideData(providerKey, newData, scope) + context.actions.provideData(providerKey, newData) lastDataKey = dataKey } } @@ -43,7 +43,7 @@ if (actionsKey !== lastActionsKey) { lastActionsKey = actionsKey newActions?.forEach(({ type, callback, metadata }) => { - context.actions.provideAction(providerKey, type, callback, scope) + context.actions.provideAction(providerKey, type, callback) // Register any "refresh datasource" actions with a singleton store // so we can easily refresh data at all levels for any datasource diff --git a/packages/client/src/stores/context.js b/packages/client/src/stores/context.js index e54c773591..c1ec18ef13 100644 --- a/packages/client/src/stores/context.js +++ b/packages/client/src/stores/context.js @@ -1,5 +1,4 @@ import { writable, derived } from "svelte/store" -import { ContextScopes } from "constants" export const createContextStore = parentContext => { const context = writable({}) @@ -20,60 +19,34 @@ export const createContextStore = parentContext => { } // Provide some data in context - const provideData = (providerId, data, scope = ContextScopes.Global) => { + const provideData = (providerId, data) => { if (!providerId || data === undefined) { return } - // Proxy message up the chain if we have a parent and are providing global - // context - if (scope === ContextScopes.Global && parentContext) { - parentContext.actions.provideData(providerId, data, scope) - } - // Otherwise this is either the context root, or we're providing a local // context override, so we need to update the local context instead - else { - context.update(state => { - state[providerId] = data - return state - }) - broadcastChange(providerId) - } + context.update(state => { + state[providerId] = data + return state + }) + broadcastChange(providerId) } // Provides some action in context - const provideAction = ( - providerId, - actionType, - callback, - scope = ContextScopes.Global - ) => { + const provideAction = (providerId, actionType, callback) => { if (!providerId || !actionType) { return } - // Proxy message up the chain if we have a parent and are providing global - // context - if (scope === ContextScopes.Global && parentContext) { - parentContext.actions.provideAction( - providerId, - actionType, - callback, - scope - ) - } - // Otherwise this is either the context root, or we're providing a local // context override, so we need to update the local context instead - else { - const key = `${providerId}_${actionType}` - context.update(state => { - state[key] = callback - return state - }) - broadcastChange(key) - } + const key = `${providerId}_${actionType}` + context.update(state => { + state[key] = callback + return state + }) + broadcastChange(key) } const observeChanges = callback => { From a880c5e62a5aceb3c4a207ad55cedaee9d6834d8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Feb 2024 10:27:23 +0000 Subject: [PATCH 03/67] Update outside popover styles --- packages/bbui/src/Actions/position_dropdown.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index cc169eac09..14bb209b97 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -38,8 +38,9 @@ export default function positionDropdown(element, opts) { styles = customUpdate(anchorBounds, elementBounds, styles) } else { // Determine vertical styles - if (align === "right-outside") { - styles.top = anchorBounds.top + if (align === "right-outside" || align === "left-outside") { + styles.top = anchorBounds.bottom - elementBounds.height + styles.maxHeight = maxHeight } else if ( window.innerHeight - anchorBounds.bottom < (maxHeight || 100) From daec133f792e89499700510949a0d3b15aac6262 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Feb 2024 10:27:29 +0000 Subject: [PATCH 04/67] Add live eval of bindings --- .../common/bindings/BindingPanel.svelte | 37 +++++++- .../common/bindings/BindingPicker.svelte | 91 +++++++++---------- .../Component/ComponentSettingsSection.svelte | 2 - 3 files changed, 79 insertions(+), 51 deletions(-) diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 1dba55c733..3b64c918d0 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -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} /> + {#if expressionResult} +
    + {expressionResult} +
    + {/if}
  • { - 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}
  • 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; + } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte index a18f21ae1d..c096ef58ec 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte @@ -150,8 +150,6 @@ onMount(() => { store.actions.preview.sendEvent("request-context") }) - - $: console.log(context) {#each sections as section, idx (section.name)} From f3f5532ad630e9560063f968d35cbe635cd63f37 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Feb 2024 16:32:28 +0000 Subject: [PATCH 05/67] Fix merge issues --- .../_components/Component/ComponentSettingsSection.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte index 36ef6a7526..c7fe7b6b33 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte @@ -1,7 +1,7 @@ From 461418390d6a72bbb012d88d85543c6b7d18979b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Feb 2024 12:36:03 +0000 Subject: [PATCH 06/67] Change how context is passed through to binding drawers to ensure it's always available --- .../common/bindings/BindingPanel.svelte | 20 +++++++++---------- .../common/bindings/BindingPicker.svelte | 17 ++++++++-------- .../common/bindings/ClientBindingPanel.svelte | 4 ++-- .../bindings/DrawerBindableInput.svelte | 2 -- .../ButtonConfiguration.svelte | 1 + .../settings/controls/PropertyControl.svelte | 2 -- .../Component/ComponentSettingsSection.svelte | 2 -- 7 files changed, 20 insertions(+), 28 deletions(-) diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index cb564593a0..d7b0e6e65c 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -135,13 +135,10 @@ selected={mode} on:select={onChangeMode} beforeSwitch={selectedMode => { - if (selectedMode == mode) { + if (selectedMode === mode) { return true } - - //Get the current mode value const editorValue = usingJS ? decodeJSBinding(jsValue) : hbsValue - if (editorValue) { targetMode = selectedMode return false @@ -204,9 +201,9 @@
    Current Handlebars syntax is invalid, please check the guide - here + + here + for more details.
    {:else} @@ -523,9 +520,10 @@ 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; + overflow-y: scroll; + overflow-x: hidden; + white-space: pre-wrap; + word-wrap: break-word; + max-height: 92px; } diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte index 8ae236a7ab..cb990b277a 100644 --- a/packages/builder/src/components/common/bindings/BindingPicker.svelte +++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte @@ -10,7 +10,6 @@ export let mode export let allowHelpers export let context = null - export let noPaddingTop = false let search = "" let popover @@ -70,6 +69,8 @@ return names } + $: console.log(context) + const getBindingValue = binding => { const hbs = `{{ ${binding.runtimeBinding} }}` return processStringSync(hbs, context) @@ -165,15 +166,13 @@ class="binding" on:mouseenter={e => { let val = getBindingValue(binding) - if (val === "") { - val = " " + if (val !== "") { + popoverAnchor = e.target + hoverTarget = { + code: val, + } + popover.show() } - popoverAnchor = e.target - hoverTarget = { - code: val, - } - popover.show() - e.stopPropagation() }} on:mouseleave={() => { popover.hide() diff --git a/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte b/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte index 4bf05190db..39d8aaf2f5 100644 --- a/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte @@ -1,12 +1,12 @@ import { helpers } from "@budibase/shared-core" import { DetailSummary, notifications } from "@budibase/bbui" - import { componentStore, previewStore } from "stores/builder" + import { componentStore } from "stores/builder" import PropertyControl from "components/design/settings/controls/PropertyControl.svelte" import ResetFieldsButton from "components/design/settings/controls/ResetFieldsButton.svelte" import EjectBlockButton from "components/design/settings/controls/EjectBlockButton.svelte" import { getComponentForSetting } from "components/design/settings/componentSettings" import InfoDisplay from "./InfoDisplay.svelte" import analytics, { Events } from "analytics" - import { onMount } from "svelte" export let componentDefinition export let componentInstance @@ -145,10 +144,6 @@ } return shouldDisplay(instance, setting) } - - onMount(() => { - previewStore.sendEvent("request-context") - }) {#each sections as section, idx (section.name)} diff --git a/packages/builder/src/stores/builder/preview.js b/packages/builder/src/stores/builder/preview.js index eca69d56d7..4923185ee7 100644 --- a/packages/builder/src/stores/builder/preview.js +++ b/packages/builder/src/stores/builder/preview.js @@ -60,6 +60,10 @@ export const createPreviewStore = () => { }) } + const requestComponentContext = () => { + sendEvent("request-context") + } + return { subscribe: store.subscribe, setDevice, @@ -69,6 +73,7 @@ export const createPreviewStore = () => { stopDrag, showPreview, setSelectedComponentContext, + requestComponentContext, } } diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index c2bc9f3989..46a507387d 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -53,7 +53,7 @@ export const getAdditionalDataContext = () => { const rows = get(grid?.getContext()?.rows) const goldenRow = generateGoldenSample(rows) - const id = [get(component).id] + const id = get(component).id return { [id]: goldenRow, eventContext: { diff --git a/packages/client/src/components/app/blocks/CardsBlock.svelte b/packages/client/src/components/app/blocks/CardsBlock.svelte index 008fa7e730..bd2b69d352 100644 --- a/packages/client/src/components/app/blocks/CardsBlock.svelte +++ b/packages/client/src/components/app/blocks/CardsBlock.svelte @@ -4,6 +4,7 @@ import BlockComponent from "components/BlockComponent.svelte" import { makePropSafe as safe } from "@budibase/string-templates" import { enrichSearchColumns, enrichFilter } from "utils/blocks.js" + import { get } from "svelte/store" export let title export let dataSource @@ -31,7 +32,9 @@ export let linkColumn export let noRowsMessage - const { fetchDatasourceSchema } = getContext("sdk") + const context = getContext("context") + const { fetchDatasourceSchema, generateGoldenSample } = getContext("sdk") + const component = getContext("component") let formId let dataProviderId @@ -62,6 +65,16 @@ }, ] + // Provide additional data context for live binding eval + export const getAdditionalDataContext = () => { + const rows = get(context)[dataProviderId]?.rows || [] + const goldenRow = generateGoldenSample(rows) + const id = get(component).id + return { + [`${id}-repeater`]: goldenRow, + } + } + // Builds a full details page URL for the card title const buildFullCardUrl = (link, url, repeaterId, linkColumn) => { if (!link || !url || !repeaterId) { From 5c4e797251a0ceca04ed1735688536d012652ea5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Feb 2024 14:23:17 +0000 Subject: [PATCH 09/67] Provide additional context from repeater blocks --- .../src/components/app/blocks/RepeaterBlock.svelte | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/client/src/components/app/blocks/RepeaterBlock.svelte b/packages/client/src/components/app/blocks/RepeaterBlock.svelte index 30fbdddcdc..878b827c78 100644 --- a/packages/client/src/components/app/blocks/RepeaterBlock.svelte +++ b/packages/client/src/components/app/blocks/RepeaterBlock.svelte @@ -4,6 +4,7 @@ import Placeholder from "components/app/Placeholder.svelte" import { getContext } from "svelte" import { makePropSafe as safe } from "@budibase/string-templates" + import { get } from "svelte/store" export let dataSource export let filter @@ -18,8 +19,20 @@ export let gap const component = getContext("component") + const context = getContext("context") + const { generateGoldenSample } = getContext("sdk") let providerId + + // Provide additional data context for live binding eval + export const getAdditionalDataContext = () => { + const rows = get(context)[providerId]?.rows || [] + const goldenRow = generateGoldenSample(rows) + const id = get(component).id + return { + [`${id}-repeater`]: goldenRow, + } + } From 840f499b47d110ebc77726d95b14835ef9df5370 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Feb 2024 14:33:40 +0000 Subject: [PATCH 10/67] Provide additional data context from form blocks --- .../app/blocks/MultiStepFormblock.svelte | 14 ++- .../app/blocks/form/FormBlock.svelte | 88 +++++++++++-------- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/packages/client/src/components/app/blocks/MultiStepFormblock.svelte b/packages/client/src/components/app/blocks/MultiStepFormblock.svelte index b24c2f418a..1a0fbbd50d 100644 --- a/packages/client/src/components/app/blocks/MultiStepFormblock.svelte +++ b/packages/client/src/components/app/blocks/MultiStepFormblock.svelte @@ -5,7 +5,7 @@ import { builderStore } from "stores" import { Utils } from "@budibase/frontend-core" import FormBlockWrapper from "./form/FormBlockWrapper.svelte" - import { writable } from "svelte/store" + import { get, writable } from "svelte/store" export let actionType export let rowId @@ -15,7 +15,7 @@ export let buttonPosition = "bottom" export let size - const { fetchDatasourceSchema } = getContext("sdk") + const { fetchDatasourceSchema, generateGoldenSample } = getContext("sdk") const component = getContext("component") const context = getContext("context") @@ -45,6 +45,16 @@ $: enrichedSteps = enrichSteps(steps, schema, $component.id, $currentStep) $: updateCurrentStep(enrichedSteps, $builderStore, $component) + // Provide additional data context for live binding eval + export const getAdditionalDataContext = () => { + const id = get(component).id + const rows = get(context)[`${id}-provider`]?.rows || [] + const goldenRow = generateGoldenSample(rows) + return { + [`${id}-repeater`]: goldenRow, + } + } + const updateCurrentStep = (steps, builderStore, component) => { const { componentId, step } = builderStore.metadata || {} diff --git a/packages/client/src/components/app/blocks/form/FormBlock.svelte b/packages/client/src/components/app/blocks/form/FormBlock.svelte index cdf1a05628..8c084a71ab 100644 --- a/packages/client/src/components/app/blocks/form/FormBlock.svelte +++ b/packages/client/src/components/app/blocks/form/FormBlock.svelte @@ -3,6 +3,7 @@ import InnerFormBlock from "./InnerFormBlock.svelte" import { Utils } from "@budibase/frontend-core" import FormBlockWrapper from "./FormBlockWrapper.svelte" + import { get } from "svelte/store" export let actionType export let dataSource @@ -11,7 +12,6 @@ export let fields export let buttons export let buttonPosition - export let title export let description export let rowId @@ -25,8 +25,56 @@ export let saveButtonLabel export let deleteButtonLabel - const { fetchDatasourceSchema } = getContext("sdk") + const { fetchDatasourceSchema, generateGoldenSample } = getContext("sdk") const component = getContext("component") + const context = getContext("context") + + let schema + + $: formattedFields = convertOldFieldFormat(fields) + $: fieldsOrDefault = getDefaultFields(formattedFields, schema) + $: fetchSchema(dataSource) + // We could simply spread $$props into the inner form and append our + // additions, but that would create svelte warnings about unused props and + // make maintenance in future more confusing as we typically always have a + // proper mapping of schema settings to component exports, without having to + // search multiple files + $: innerProps = { + dataSource, + actionUrl, + actionType, + size, + disabled, + fields: fieldsOrDefault, + title, + description, + schema, + notificationOverride, + buttons: + buttons || + Utils.buildFormBlockButtonConfig({ + _id: $component.id, + showDeleteButton, + showSaveButton, + saveButtonLabel, + deleteButtonLabel, + notificationOverride, + actionType, + actionUrl, + dataSource, + }), + buttonPosition: buttons ? buttonPosition : "top", + } + + // Provide additional data context for live binding eval + export const getAdditionalDataContext = () => { + const id = get(component).id + const rows = get(context)[`${id}-provider`]?.rows || [] + const goldenRow = generateGoldenSample(rows) + return { + [`${id}-repeater`]: goldenRow, + } + } const convertOldFieldFormat = fields => { if (!fields) { @@ -68,42 +116,6 @@ return [...fields, ...defaultFields].filter(field => field.active) } - let schema - - $: formattedFields = convertOldFieldFormat(fields) - $: fieldsOrDefault = getDefaultFields(formattedFields, schema) - $: fetchSchema(dataSource) - // We could simply spread $$props into the inner form and append our - // additions, but that would create svelte warnings about unused props and - // make maintenance in future more confusing as we typically always have a - // proper mapping of schema settings to component exports, without having to - // search multiple files - $: innerProps = { - dataSource, - actionUrl, - actionType, - size, - disabled, - fields: fieldsOrDefault, - title, - description, - schema, - notificationOverride, - buttons: - buttons || - Utils.buildFormBlockButtonConfig({ - _id: $component.id, - showDeleteButton, - showSaveButton, - saveButtonLabel, - deleteButtonLabel, - notificationOverride, - actionType, - actionUrl, - dataSource, - }), - buttonPosition: buttons ? buttonPosition : "top", - } const fetchSchema = async () => { schema = (await fetchDatasourceSchema(dataSource)) || {} } From 53bb890d3d9f8ec922b3f9c07261e02e08c989a3 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Feb 2024 14:36:28 +0000 Subject: [PATCH 11/67] Provide additional context from row explorer block --- .../src/components/app/blocks/RowExplorer.svelte | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/client/src/components/app/blocks/RowExplorer.svelte b/packages/client/src/components/app/blocks/RowExplorer.svelte index 8fadcb5006..1e2357713a 100644 --- a/packages/client/src/components/app/blocks/RowExplorer.svelte +++ b/packages/client/src/components/app/blocks/RowExplorer.svelte @@ -3,25 +3,35 @@ import BlockComponent from "components/BlockComponent.svelte" import { makePropSafe as safe } from "@budibase/string-templates" import { generate } from "shortid" + import { get } from "svelte/store" + import { getContext } from "svelte" export let dataSource export let height - export let cardTitle export let cardSubtitle export let cardDescription export let cardImageURL export let cardSearchField - export let detailFields export let detailTitle - export let noRowsMessage const stateKey = generate() + const context = getContext("context") + const { generateGoldenSample } = getContext("sdk") let listDataProviderId let listRepeaterId + + // Provide additional data context for live binding eval + export const getAdditionalDataContext = () => { + const rows = get(context)[listDataProviderId]?.rows || [] + const goldenRow = generateGoldenSample(rows) + return { + [listRepeaterId]: goldenRow, + } + } From 86695c0ee49fb41cf6117c48e9a1388d757f0ad0 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Feb 2024 16:24:31 +0000 Subject: [PATCH 12/67] Add syntax highlighting to live binding eval --- packages/builder/package.json | 1 + .../common/bindings/BindingPanel.svelte | 25 +++++++++++++-- .../common/bindings/BindingPicker.svelte | 31 +++++++++++++++---- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/packages/builder/package.json b/packages/builder/package.json index 52db8e11bc..3bf9ab4442 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -70,6 +70,7 @@ "dayjs": "^1.10.8", "downloadjs": "1.4.7", "fast-json-patch": "^3.1.1", + "json-format-highlight": "^1.0.4", "lodash": "4.17.21", "posthog-js": "^1.36.0", "remixicon": "2.5.0", diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index d7b0e6e65c..f0ded4a67b 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -33,6 +33,7 @@ } from "../CodeEditor" import BindingPicker from "./BindingPicker.svelte" import { BindingHelpers } from "./utils" + import formatHighlight from "json-format-highlight" const dispatch = createEventDispatcher() @@ -123,6 +124,24 @@ onSelectBinding("", { forceJS: true }) } + const highlight = json => { + // Attempt to parse and then stringify, in case this is valid JSON + try { + json = JSON.stringify(JSON.parse(json), null, 2) + } catch (err) { + // Ignore + } + + return formatHighlight(json, { + keyColor: "#e06c75", + numberColor: "#e5c07b", + stringColor: "#98c379", + trueColor: "#d19a66", + falseColor: "#d19a66", + nullColor: "#c678dd", + }) + } + onMount(() => { valid = isValid(readableToRuntimeBinding(bindings, value)) }) @@ -192,7 +211,7 @@ {#if expressionResult}
    - {expressionResult} + {@html highlight(expressionResult)}
    {/if} {#if expressionResult}
    - {expressionResult} + {@html highlight(expressionResult)}
    {/if} {/if} {#if hoverTarget.code} -
    {hoverTarget.code}
    +
    {@html highlight(hoverTarget.code)}
    {/if} @@ -387,8 +400,14 @@ padding: 0; margin: 0; font-size: 12px; - white-space: pre-wrap; - word-break: break-all; + white-space: pre; + text-overflow: ellipsis; + overflow: hidden; + } + .helper pre :global(span) { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; } .helper :global(p) { padding: 0; From 14b2bfa8d690802877058b3b5b1faf7b6ad2582d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Feb 2024 16:24:46 +0000 Subject: [PATCH 13/67] Update lock --- yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yarn.lock b/yarn.lock index 1937482837..3e147eed34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13765,6 +13765,11 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== +json-format-highlight@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/json-format-highlight/-/json-format-highlight-1.0.4.tgz#2e44277edabcec79a3d2c84e984c62e2258037b9" + integrity sha512-RqenIjKr1I99XfXPAml9G7YlEZg/GnsH7emWyWJh2yuGXqHW8spN7qx6/ME+MoIBb35/fxrMC9Jauj6nvGe4Mg== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" From 433c3a6306fdd161da70d145b4ac73885f215757 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 19 Feb 2024 16:22:23 +0000 Subject: [PATCH 14/67] Debounce hiding binding values to enable interacting with them --- packages/bbui/src/Popover/Popover.svelte | 2 + .../common/bindings/BindingPicker.svelte | 51 +++++++++++++------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte index 5066e3aa05..7ff5ae5f03 100644 --- a/packages/bbui/src/Popover/Popover.svelte +++ b/packages/bbui/src/Popover/Popover.svelte @@ -101,6 +101,8 @@ role="presentation" style="height: {customHeight}; --customZindex: {customZindex};" transition:fly|local={{ y: -20, duration: animate ? 200 : 0 }} + on:mouseenter + on:mouseleave > diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte index 4f08cd5306..342855f427 100644 --- a/packages/builder/src/components/common/bindings/BindingPicker.svelte +++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte @@ -18,6 +18,7 @@ let hoverTarget let helpers = handlebarsCompletions() let selectedCategory + let hideTimeout $: bindingIcons = bindings?.reduce((acc, ele) => { if (ele.icon) { @@ -86,6 +87,37 @@ nullColor: "#c678dd", }) } + + const showPopover = (target, binding) => { + if (hideTimeout) { + clearTimeout(hideTimeout) + hideTimeout = null + } + let val = getBindingValue(binding) + if (val !== "") { + popoverAnchor = target + hoverTarget = { + code: val, + } + popover.show() + } + } + + const hidePopover = () => { + hideTimeout = setTimeout(() => { + popover.hide() + popoverAnchor = null + hoverTarget = null + hideTimeout = null + }, 100) + } + + const stopHiding = () => { + if (hideTimeout) { + clearTimeout(hideTimeout) + hideTimeout = null + } + }
    @@ -175,21 +209,8 @@ {#each category.bindings as binding}
  • { - let val = getBindingValue(binding) - if (val !== "") { - popoverAnchor = e.target - hoverTarget = { - code: val, - } - popover.show() - } - }} - on:mouseleave={() => { - popover.hide() - popoverAnchor = null - hoverTarget = null - }} + on:mouseenter={e => showPopover(e.target, binding)} + on:mouseleave={hidePopover} on:focus={() => {}} on:blur={() => {}} on:click={() => addBinding(binding)} From 602f35537d9f0438014c0600ae3afcb89f6a94d8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 19 Feb 2024 16:28:23 +0000 Subject: [PATCH 15/67] Support custom min widths for popovers --- packages/bbui/src/Actions/position_dropdown.js | 3 ++- packages/bbui/src/Popover/Popover.svelte | 3 ++- .../src/components/common/bindings/BindingPicker.svelte | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 14bb209b97..31a1044ba4 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -15,6 +15,7 @@ export default function positionDropdown(element, opts) { align, maxHeight, maxWidth, + minWidth, useAnchorWidth, offset = 5, customUpdate, @@ -28,7 +29,7 @@ export default function positionDropdown(element, opts) { const elementBounds = element.getBoundingClientRect() let styles = { maxHeight: null, - minWidth: null, + minWidth, maxWidth, left: null, top: null, diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte index 7ff5ae5f03..407fb0b153 100644 --- a/packages/bbui/src/Popover/Popover.svelte +++ b/packages/bbui/src/Popover/Popover.svelte @@ -12,6 +12,7 @@ export let anchor export let align = "right" export let portalTarget + export let minWidth export let maxWidth export let maxHeight export let open = false @@ -21,7 +22,6 @@ export let customHeight export let animate = true export let customZindex - export let handlePostionUpdate export let showPopover = true export let clickOutsideOverride = false @@ -86,6 +86,7 @@ align, maxHeight, maxWidth, + minWidth, useAnchorWidth, offset, customUpdate: handlePostionUpdate, diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte index 342855f427..9c0522ce5a 100644 --- a/packages/builder/src/components/common/bindings/BindingPicker.svelte +++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte @@ -124,11 +124,11 @@ align="left-outside" bind:this={popover} anchor={popoverAnchor} - maxWidth={600} + minWidth={0} + maxWidth={480} maxHeight={300} dismissible={false} on:mouseenter={stopHiding} - on:mouseleave={hidePopover} >
    From 7a278234b55d82b4407e51edc4d46b0b7c342eb5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 19 Feb 2024 16:30:29 +0000 Subject: [PATCH 16/67] Suppress warning --- .../src/components/common/bindings/BindingPicker.svelte | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte index 9c0522ce5a..60ca6abf7c 100644 --- a/packages/builder/src/components/common/bindings/BindingPicker.svelte +++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte @@ -139,7 +139,10 @@
    {/if} {#if hoverTarget.code} -
    {@html highlight(hoverTarget.code)}
    +
    +          
    +          {@html highlight(hoverTarget.code)}
    +        
    {/if} From ca3f464523f4f57351db2f979c6392da4297756e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 20 Feb 2024 10:11:27 +0000 Subject: [PATCH 17/67] Tidy up logic for showing and hiding popovers for bindings and helpers --- .../common/CodeEditor/CodeEditor.svelte | 22 ++++- .../src/components/common/CodeEditor/index.js | 5 + .../common/bindings/BindingPanel.svelte | 45 +++++++-- .../common/bindings/BindingPicker.svelte | 93 +++++++------------ 4 files changed, 91 insertions(+), 74 deletions(-) diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte index f4fa762bce..b169cd2f7c 100644 --- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte +++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte @@ -117,7 +117,7 @@ const indentWithTabCustom = { key: "Tab", run: view => { - if (completionStatus(view.state) == "active") { + if (completionStatus(view.state) === "active") { acceptCompletion(view) return true } @@ -131,7 +131,7 @@ } const buildKeymap = () => { - const baseMap = [ + return [ ...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, @@ -139,7 +139,6 @@ ...completionKeymap, indentWithTabCustom, ] - return baseMap } const buildBaseExtensions = () => { @@ -215,7 +214,7 @@ ) } - if (mode.name == "javascript") { + if (mode.name === "javascript") { complete.push(javascript()) complete.push(highlightWhitespace()) complete.push(lineNumbers()) @@ -321,4 +320,19 @@ border-radius: var(--border-radius-s); padding: 4px 6px; } + + .code-editor :global(.binding__example) { + padding: 0; + margin: 0; + font-size: 12px; + white-space: pre; + text-overflow: ellipsis; + overflow: hidden; + max-height: 480px; + } + .code-editor :global(.binding__example span) { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } diff --git a/packages/builder/src/components/common/CodeEditor/index.js b/packages/builder/src/components/common/CodeEditor/index.js index 0d71a475f0..6f55f42169 100644 --- a/packages/builder/src/components/common/CodeEditor/index.js +++ b/packages/builder/src/components/common/CodeEditor/index.js @@ -255,6 +255,11 @@ export const buildBindingInfoNode = (completion, binding) => { const ele = document.createElement("div") ele.classList.add("info-bubble") + if (binding.valueHTML) { + ele.innerHTML = `
    ${binding.valueHTML}
    ` + return ele + } + const exampleNodeHtml = binding.readableBinding ? `
    {{ ${binding.readableBinding} }}
    ` : "" diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index f0ded4a67b..3708f83c61 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -62,16 +62,45 @@ let targetMode = null let expressionResult + $: enrichedBindings = enrichBindings(bindings, context) $: usingJS = mode === "JavaScript" $: editorMode = mode === "JavaScript" ? EditorModes.JS : EditorModes.Handlebars - $: bindingCompletions = bindingsToCompletions(bindings, editorMode) - $: runtimeExpression = readableToRuntimeBinding(bindings, value) + $: bindingCompletions = bindingsToCompletions(enrichedBindings, editorMode) + $: runtimeExpression = readableToRuntimeBinding(enrichedBindings, value) $: expressionResult = processStringSync(runtimeExpression || "", context) $: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos) + const getBindingValue = (binding, context) => { + const hbs = `{{ literal ${binding.runtimeBinding} }}` + const res = processStringSync(hbs, context) + return JSON.stringify(res, null, 2) + } + + const highlightJSON = json => { + return formatHighlight(json, { + keyColor: "#e06c75", + numberColor: "#e5c07b", + stringColor: "#98c379", + trueColor: "#d19a66", + falseColor: "#d19a66", + nullColor: "#c678dd", + }) + } + + const enrichBindings = (bindings, context) => { + return bindings.map(binding => { + const value = getBindingValue(binding, context) + return { + ...binding, + value, + valueHTML: highlightJSON(value), + } + }) + } + const updateValue = val => { - const runtimeExpression = readableToRuntimeBinding(bindings, val) + const runtimeExpression = readableToRuntimeBinding(enrichedBindings, val) valid = isValid(runtimeExpression) if (valid) { dispatch("change", val) @@ -116,9 +145,9 @@ } const convert = () => { - const runtime = readableToRuntimeBinding(bindings, hbsValue) + const runtime = readableToRuntimeBinding(enrichedBindings, hbsValue) const runtimeJs = encodeJSBinding(convertToJS(runtime)) - jsValue = runtimeToReadableBinding(bindings, runtimeJs) + jsValue = runtimeToReadableBinding(enrichedBindings, runtimeJs) hbsValue = null mode = "JavaScript" onSelectBinding("", { forceJS: true }) @@ -143,7 +172,7 @@ } onMount(() => { - valid = isValid(readableToRuntimeBinding(bindings, value)) + valid = isValid(readableToRuntimeBinding(enrichedBindings, value)) }) @@ -261,7 +290,7 @@ {#if sidebar}
    { - const hbs = `{{ literal ${binding.runtimeBinding} }}` - const res = processStringSync(hbs, context) - return JSON.stringify(res, null, 2) + const showBindingPopover = (binding, target) => { + stopHidingPopover() + popoverAnchor = target + hoverTarget = { + code: binding.valueHTML, + } + popover.show() } - const highlight = json => { - return formatHighlight(json, { - keyColor: "#e06c75", - numberColor: "#e5c07b", - stringColor: "#98c379", - trueColor: "#d19a66", - falseColor: "#d19a66", - nullColor: "#c678dd", - }) - } - - const showPopover = (target, binding) => { - if (hideTimeout) { - clearTimeout(hideTimeout) - hideTimeout = null + const showHelperPopover = (helper, target) => { + stopHidingPopover() + if (!helper.displayText && helper.description) { + return } - let val = getBindingValue(binding) - if (val !== "") { - popoverAnchor = target - hoverTarget = { - code: val, - } - popover.show() + popoverAnchor = target + hoverTarget = { + description: helper.description, + code: getHelperExample(helper, mode.name === "javascript"), } + popover.show() } const hidePopover = () => { @@ -112,7 +102,7 @@ }, 100) } - const stopHiding = () => { + const stopHidingPopover = () => { if (hideTimeout) { clearTimeout(hideTimeout) hideTimeout = null @@ -126,9 +116,10 @@ anchor={popoverAnchor} minWidth={0} maxWidth={480} - maxHeight={300} + maxHeight={480} dismissible={false} - on:mouseenter={stopHiding} + on:mouseenter={stopHidingPopover} + on:mouseleave={hidePopover} >
    @@ -139,10 +130,8 @@
    {/if} {#if hoverTarget.code} -
    -          
    -          {@html highlight(hoverTarget.code)}
    -        
    + +
    {@html hoverTarget.code}
    {/if}
    @@ -212,10 +201,8 @@ {#each category.bindings as binding}
  • showPopover(e.target, binding)} + on:mouseenter={e => showBindingPopover(binding, e.target)} on:mouseleave={hidePopover} - on:focus={() => {}} - on:blur={() => {}} on:click={() => addBinding(binding)} > @@ -227,7 +214,6 @@ {binding.readableBinding} {/if} - {#if binding.display?.type || binding.fieldSchema?.type} @@ -250,26 +236,9 @@ {#each filteredHelpers as helper}
  • showHelperPopover(helper, e.target)} + on:mouseleave={hidePopover} on:click={() => addHelper(helper, mode.name === "javascript")} - on:mouseenter={e => { - popoverAnchor = e.target - if (!helper.displayText && helper.description) { - return - } - hoverTarget = { - description: helper.description, - code: getHelperExample(helper, mode.name === "javascript"), - } - popover.show() - e.stopPropagation() - }} - on:mouseleave={() => { - popover.hide() - popoverAnchor = null - hoverTarget = null - }} - on:focus={() => {}} - on:blur={() => {}} > {helper.displayText} @@ -287,16 +256,16 @@ diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte similarity index 66% rename from packages/builder/src/components/common/bindings/BindingPicker.svelte rename to packages/builder/src/components/common/bindings/BindingSidePanel.svelte index d1baa03999..b74f3c6fcd 100644 --- a/packages/builder/src/components/common/bindings/BindingPicker.svelte +++ b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte @@ -137,123 +137,129 @@ - - {#if selectedCategory} -
    - { - selectedCategory = null - }} - > - Back - -
    - {/if} - - {#if !selectedCategory} - - {/if} - - {#if !selectedCategory && !search} -
      - {#each categoryNames as categoryName} -
    • + + {#if selectedCategory} +
      + { - selectedCategory = categoryName + selectedCategory = null }} > - - {categoryName} - -
    • - {/each} -
    - {/if} + Back + + + {/if} - {#if selectedCategory || search} - {#each filteredCategories as category} - {#if category.bindings?.length} -
    -
    - {category.name} -
    -
      - {#each category.bindings as binding} -
    • showBindingPopover(binding, e.target)} - on:mouseleave={hidePopover} - on:click={() => addBinding(binding)} - > - - {#if binding.display?.name} - {binding.display.name} - {:else if binding.fieldSchema?.name} - {binding.fieldSchema?.name} - {:else} - {binding.readableBinding} - {/if} - - {#if binding.display?.type || binding.fieldSchema?.type} - - - {binding.display?.type || binding.fieldSchema?.type} - + {#if !selectedCategory} + + {/if} + + {#if !selectedCategory && !search} +
        + {#each categoryNames as categoryName} +
      • { + selectedCategory = categoryName + }} + > + + {categoryName} + +
      • + {/each} +
      + {/if} + + {#if selectedCategory || search} + {#each filteredCategories as category} + {#if category.bindings?.length} +
      +
      + {category.name} +
      +
        + {#each category.bindings as binding} +
      • showBindingPopover(binding, e.target)} + on:mouseleave={hidePopover} + on:click={() => addBinding(binding)} + > + + {#if binding.display?.name} + {binding.display.name} + {:else if binding.fieldSchema?.name} + {binding.fieldSchema?.name} + {:else} + {binding.readableBinding} + {/if} - {/if} -
      • - {/each} -
      -
      - {/if} - {/each} + {#if binding.display?.type || binding.fieldSchema?.type} + + + {binding.display?.type || binding.fieldSchema?.type} + + + {/if} +
    • + {/each} +
    +
    + {/if} + {/each} - {#if selectedCategory === "Helpers" || search} - {#if filteredHelpers?.length} -
    -
    Helpers
    -
      - {#each filteredHelpers as helper} -
    • showHelperPopover(helper, e.target)} - on:mouseleave={hidePopover} - on:click={() => addHelper(helper, mode.name === "javascript")} - > - {helper.displayText} - - function - -
    • - {/each} -
    -
    + {#if selectedCategory === "Helpers" || search} + {#if filteredHelpers?.length} +
    +
    Helpers
    +
      + {#each filteredHelpers as helper} +
    • showHelperPopover(helper, e.target)} + on:mouseleave={hidePopover} + on:click={() => addHelper(helper, mode.name === "javascript")} + > + {helper.displayText} + + function + +
    • + {/each} +
    +
    + {/if} {/if} {/if} - {/if} -
    + + From 8320c50c9686602084240fcc8adb2b449d840dd8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 22 Feb 2024 16:44:18 +0000 Subject: [PATCH 19/67] Fix multiple style issues with codemirror --- packages/builder/package.json | 2 +- .../common/CodeEditor/CodeEditor.svelte | 44 ++++++++++++++++++- .../src/components/common/CodeEditor/index.js | 13 ------ 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/packages/builder/package.json b/packages/builder/package.json index 3bf9ab4442..4871833d48 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -66,7 +66,7 @@ "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", "@zerodevx/svelte-json-view": "^1.0.7", - "codemirror": "^5.59.0", + "codemirror": "^6.0.1", "dayjs": "^1.10.8", "downloadjs": "1.4.7", "fast-json-patch": "^3.1.1", diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte index 0d8798d0f2..9341711022 100644 --- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte +++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte @@ -299,12 +299,53 @@ diff --git a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte index d68857b420..2c8c6144fb 100644 --- a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte @@ -140,21 +140,19 @@
    {#if selectedCategory} -
    - { - selectedCategory = null - }} - > - Back - +
    + (selectedCategory = null)} + /> + {selectedCategory}
    {/if} {#if !selectedCategory} -
    - {#if expressionResult} - {@html highlightedResult} - {:else} + {#if empty} Your expression will be evaluated here + {:else} + {@html highlightedResult} {/if}
    From e53676791a8d8b9dfd47759bb02242287ca3be7f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 29 Feb 2024 17:04:01 +0000 Subject: [PATCH 49/67] Fix font size of code block in helper popovers --- .../src/components/common/bindings/BindingSidePanel.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte index 87fcb7cb5b..4815353cff 100644 --- a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte @@ -123,7 +123,6 @@ maxHeight={480} dismissible={false} on:mouseenter={stopHidingPopover} - on:mouseleave={hidePopover} >
    {#if hoverTarget.description} @@ -414,4 +413,7 @@ padding: 0; margin: 0; } + .binding-popover.helper :global(code) { + font-size: 12px; + } From b159258fb5c814bb9c512973a73e9832c6682068 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 29 Feb 2024 17:04:39 +0000 Subject: [PATCH 50/67] Restore mouse functionality --- .../src/components/common/bindings/BindingSidePanel.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte index 4815353cff..3a3c3c4034 100644 --- a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte @@ -123,6 +123,7 @@ maxHeight={480} dismissible={false} on:mouseenter={stopHidingPopover} + on:mouseleave={hidePopover} >
    {#if hoverTarget.description} From 3aed79ad03a5f36d1e9d0c7646dea82289e29365 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 29 Feb 2024 19:08:29 +0000 Subject: [PATCH 51/67] Remove helpers subheading --- .../src/components/common/bindings/BindingSidePanel.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte index 3a3c3c4034..1595aed3b5 100644 --- a/packages/builder/src/components/common/bindings/BindingSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingSidePanel.svelte @@ -237,7 +237,6 @@ {#if selectedCategory === "Helpers" || search} {#if filteredHelpers?.length}
    -
    Helpers
      {#each filteredHelpers as helper}
    • Date: Thu, 29 Feb 2024 19:40:21 +0000 Subject: [PATCH 52/67] Lint, remove drawer modal border, bump account portal --- packages/account-portal | 2 +- packages/bbui/src/Drawer/Drawer.svelte | 1 + packages/builder/src/components/common/CodeEditor/index.js | 1 - .../builder/src/components/common/bindings/BindingPanel.svelte | 2 -- .../[application]/design/[screenId]/_components/AppPanel.svelte | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/account-portal b/packages/account-portal index 8c446c4ba3..19f7a5829f 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit 8c446c4ba385592127fa31755d3b64467b291882 +Subproject commit 19f7a5829f4d23cbc694136e45d94482a59a475a diff --git a/packages/bbui/src/Drawer/Drawer.svelte b/packages/bbui/src/Drawer/Drawer.svelte index 118a7dcd8e..606b4e28cd 100644 --- a/packages/bbui/src/Drawer/Drawer.svelte +++ b/packages/bbui/src/Drawer/Drawer.svelte @@ -211,6 +211,7 @@ width: 70vw; bottom: 15vh; height: 70vh; + border: none; } .drawer.stacked { transform: translateY(calc(-1 * 1024px * (1 - var(--scale-factor)))) diff --git a/packages/builder/src/components/common/CodeEditor/index.js b/packages/builder/src/components/common/CodeEditor/index.js index 962e0bd393..82c8ddf647 100644 --- a/packages/builder/src/components/common/CodeEditor/index.js +++ b/packages/builder/src/components/common/CodeEditor/index.js @@ -1,4 +1,3 @@ -import { EditorView } from "@codemirror/view" import { getManifest } from "@budibase/string-templates" import sanitizeHtml from "sanitize-html" import { groupBy } from "lodash" diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 2e4a7a63a8..a3d57e1d5c 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -225,7 +225,6 @@ ...getHelperCompletions(editorMode), ]), ]} - height="100%" autofocus={autofocusEditor} placeholder="Add bindings by typing {{ or use the menu on the right" /> @@ -242,7 +241,6 @@ mode={EditorModes.JS} bind:getCaretPosition bind:insertAtPos - height="100%" autofocus={autofocusEditor} placeholder="Add bindings by typing $ or use the menu on the right" /> diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte index c90c4ea599..4617814485 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte @@ -33,7 +33,7 @@ flex-direction: column; justify-content: flex-start; align-items: stretch; - padding: 9px var(--spacing-m); + padding: 9px 10px 12px 10px; position: relative; transition: width 360ms ease-out; } From 10b5ab34cfa10cb1ad6c278879fc66b6815c6628 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 29 Feb 2024 19:51:25 +0000 Subject: [PATCH 53/67] Re-add border for drawer modals --- packages/bbui/src/Drawer/Drawer.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/bbui/src/Drawer/Drawer.svelte b/packages/bbui/src/Drawer/Drawer.svelte index 606b4e28cd..118a7dcd8e 100644 --- a/packages/bbui/src/Drawer/Drawer.svelte +++ b/packages/bbui/src/Drawer/Drawer.svelte @@ -211,7 +211,6 @@ width: 70vw; bottom: 15vh; height: 70vh; - border: none; } .drawer.stacked { transform: translateY(calc(-1 * 1024px * (1 - var(--scale-factor)))) From d2cdee13aec50d912fea881cf90ad8562a38c088 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 29 Feb 2024 20:18:20 +0000 Subject: [PATCH 54/67] Update automation code editors to work with new components --- .../SetupPanel/AutomationBlockSetup.svelte | 24 ++++--------------- .../common/CodeEditor/CodeEditor.svelte | 15 ++++++++---- .../common/bindings/BindingPanel.svelte | 9 ------- .../common/bindings/BindingSidePanel.svelte | 6 ++--- 4 files changed, 17 insertions(+), 37 deletions(-) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 2434002d52..aff9e43aa7 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -547,7 +547,7 @@ {:else if value.customType === "code"}
      -
      +
      { @@ -560,20 +560,10 @@ autocompleteEnabled={codeMode !== EditorModes.JS} bind:getCaretPosition bind:insertAtPos - height={500} + placeholder={codeMode === EditorModes.Handlebars + ? "Add bindings by typing {{" + : null} /> -
      - {#if codeMode === EditorModes.Handlebars} - -
      -
      - Add available bindings by typing - }} - -
      -
      - {/if} -
      {#if editingJs}
      @@ -650,11 +640,6 @@ width: 320px; } - .messaging { - display: flex; - align-items: center; - margin-top: var(--spacing-xl); - } .fields { display: flex; flex-direction: column; @@ -666,7 +651,6 @@ .block-field { display: flex; /* Use Flexbox */ justify-content: space-between; - align-items: center; flex-direction: row; /* Arrange label and field side by side */ align-items: center; /* Align vertically in the center */ gap: 10px; /* Add some space between label and field */ diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte index 58942e5091..080476a9b7 100644 --- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte +++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte @@ -47,7 +47,6 @@ export let label export let completions = [] - export let height = 200 export let resize = "none" export let mode = EditorModes.Handlebars export let value = "" @@ -241,8 +240,6 @@ } } - $: editorHeight = typeof height === "number" ? `${height}px` : height - // Init when all elements are ready $: if (mounted && !isEditorInitialised) { isEditorInitialised = true @@ -284,14 +281,22 @@