Bug fixes for bindings panel and code editor
This commit is contained in:
parent
8e301902a3
commit
8a31cc2ff7
|
@ -13,6 +13,10 @@
|
|||
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
||||
import CodeEditor from "components/common/CodeEditor/CodeEditor.svelte"
|
||||
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
|
||||
import {
|
||||
readableToRuntimeBinding,
|
||||
runtimeToReadableBinding,
|
||||
} from "dataBinding"
|
||||
|
||||
export let onChange
|
||||
export let field
|
||||
|
@ -30,6 +34,8 @@
|
|||
return clone
|
||||
})
|
||||
|
||||
$: readableValue = runtimeToReadableBinding(parsedBindings, fieldData)
|
||||
|
||||
let attachmentTypes = [
|
||||
FieldType.ATTACHMENTS,
|
||||
FieldType.ATTACHMENT_SINGLE,
|
||||
|
@ -132,11 +138,12 @@
|
|||
/>
|
||||
{:else if schema.type === "longform"}
|
||||
<TextArea
|
||||
value={fieldData}
|
||||
value={readableValue}
|
||||
bindings={parsedBindings}
|
||||
on:change={e =>
|
||||
onChange({
|
||||
row: {
|
||||
[field]: e.detail,
|
||||
[field]: readableToRuntimeBinding(parsedBindings, e.detail),
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
@ -144,11 +151,11 @@
|
|||
<span>
|
||||
<div class="field-wrap json-field">
|
||||
<CodeEditor
|
||||
value={fieldData}
|
||||
on:change={e => {
|
||||
value={readableValue}
|
||||
on:blur={e => {
|
||||
onChange({
|
||||
row: {
|
||||
[field]: e.detail,
|
||||
[field]: readableToRuntimeBinding(parsedBindings, e.detail),
|
||||
},
|
||||
})
|
||||
}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { Label } from "@budibase/bbui"
|
||||
import { onMount, createEventDispatcher } from "svelte"
|
||||
import { onMount, createEventDispatcher, onDestroy } from "svelte"
|
||||
import { FIND_ANY_HBS_REGEX } from "@budibase/string-templates"
|
||||
|
||||
import {
|
||||
|
@ -58,6 +58,64 @@
|
|||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let textarea
|
||||
let editor
|
||||
let mounted = false
|
||||
let isEditorInitialised = false
|
||||
let queuedRefresh = false
|
||||
|
||||
// Theming!
|
||||
let currentTheme = $themeStore?.theme
|
||||
let isDark = !currentTheme.includes("light")
|
||||
let themeConfig = new Compartment()
|
||||
|
||||
$: {
|
||||
if (autofocus && isEditorInitialised) {
|
||||
editor.focus()
|
||||
}
|
||||
}
|
||||
|
||||
// Init when all elements are ready
|
||||
$: if (mounted && !isEditorInitialised) {
|
||||
isEditorInitialised = true
|
||||
initEditor()
|
||||
}
|
||||
|
||||
// Theme change
|
||||
$: if (mounted && isEditorInitialised && $themeStore?.theme) {
|
||||
if (currentTheme != $themeStore?.theme) {
|
||||
currentTheme = $themeStore?.theme
|
||||
isDark = !currentTheme.includes("light")
|
||||
|
||||
// Issue theme compartment update
|
||||
editor.dispatch({
|
||||
effects: themeConfig.reconfigure([...(isDark ? [oneDark] : [])]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Wait to try and gracefully replace
|
||||
$: refresh(value, isEditorInitialised, mounted)
|
||||
|
||||
/**
|
||||
* Will refresh the editor contents only after
|
||||
* it has been fully initialised
|
||||
* @param value {string} the editor value
|
||||
*/
|
||||
const refresh = (value, initialised, mounted) => {
|
||||
if (!initialised || !mounted) {
|
||||
queuedRefresh = true
|
||||
return
|
||||
}
|
||||
|
||||
if (editor.state.doc.toString() !== value || queuedRefresh) {
|
||||
editor.dispatch({
|
||||
changes: { from: 0, to: editor.state.doc.length, insert: value },
|
||||
})
|
||||
queuedRefresh = false
|
||||
}
|
||||
}
|
||||
|
||||
// Export a function to expose caret position
|
||||
export const getCaretPosition = () => {
|
||||
const selection_range = editor.state.selection.ranges[0]
|
||||
|
@ -132,11 +190,6 @@
|
|||
}
|
||||
)
|
||||
|
||||
// Theming!
|
||||
let currentTheme = $themeStore?.theme
|
||||
let isDark = !currentTheme.includes("light")
|
||||
let themeConfig = new Compartment()
|
||||
|
||||
const indentWithTabCustom = {
|
||||
key: "Tab",
|
||||
run: view => {
|
||||
|
@ -253,6 +306,11 @@
|
|||
lineNumbers(),
|
||||
foldGutter(),
|
||||
keymap.of(buildKeymap()),
|
||||
EditorView.domEventHandlers({
|
||||
blur: () => {
|
||||
dispatch("blur", editor.state.doc.toString())
|
||||
},
|
||||
}),
|
||||
EditorView.updateListener.of(v => {
|
||||
const docStr = v.state.doc?.toString()
|
||||
if (docStr === value) {
|
||||
|
@ -266,11 +324,6 @@
|
|||
return complete
|
||||
}
|
||||
|
||||
let textarea
|
||||
let editor
|
||||
let mounted = false
|
||||
let isEditorInitialised = false
|
||||
|
||||
const initEditor = () => {
|
||||
const baseExtensions = buildBaseExtensions()
|
||||
|
||||
|
@ -281,38 +334,14 @@
|
|||
})
|
||||
}
|
||||
|
||||
$: {
|
||||
if (autofocus && isEditorInitialised) {
|
||||
editor.focus()
|
||||
}
|
||||
}
|
||||
|
||||
// Init when all elements are ready
|
||||
$: if (mounted && !isEditorInitialised) {
|
||||
isEditorInitialised = true
|
||||
initEditor()
|
||||
}
|
||||
|
||||
// Theme change
|
||||
$: if (mounted && isEditorInitialised && $themeStore?.theme) {
|
||||
if (currentTheme != $themeStore?.theme) {
|
||||
currentTheme = $themeStore?.theme
|
||||
isDark = !currentTheme.includes("light")
|
||||
|
||||
// Issue theme compartment update
|
||||
editor.dispatch({
|
||||
effects: themeConfig.reconfigure([...(isDark ? [oneDark] : [])]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
mounted = true
|
||||
return () => {
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
if (editor) {
|
||||
editor.destroy()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -67,6 +67,10 @@
|
|||
let targetMode = null
|
||||
let expressionResult
|
||||
let evaluating = false
|
||||
let mounted = false
|
||||
|
||||
// Value updates must be reprocessed to avoid timing issues
|
||||
$: processUpdate(value, mounted)
|
||||
|
||||
$: useSnippets = allowSnippets && !$licensing.isFreePlan
|
||||
$: editorModeOptions = getModeOptions(allowHBS, allowJS)
|
||||
|
@ -94,6 +98,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
const processUpdate = value => {
|
||||
if (!mounted) return
|
||||
let isJS = value?.startsWith?.("{{ js ")
|
||||
jsValue = isJS ? value : null
|
||||
hbsValue = isJS ? null : value
|
||||
}
|
||||
|
||||
const getHBSCompletions = bindingCompletions => {
|
||||
return [
|
||||
hbAutocomplete([
|
||||
|
@ -266,6 +277,8 @@
|
|||
|
||||
// Set the initial side panel
|
||||
sidePanel = sidePanelOptions[0]
|
||||
|
||||
mounted = true
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
export let allowJS = true
|
||||
export let allowHelpers = true
|
||||
export let updateOnChange = true
|
||||
export let drawerLeft
|
||||
export let type
|
||||
export let schema
|
||||
|
||||
|
@ -170,14 +169,7 @@
|
|||
<Icon disabled={isJS} size="S" name="Close" />
|
||||
</div>
|
||||
{:else}
|
||||
<slot
|
||||
{label}
|
||||
{disabled}
|
||||
readonly={isJS}
|
||||
value={isJS ? "(JavaScript function)" : readableValue}
|
||||
{placeholder}
|
||||
{updateOnChange}
|
||||
/>
|
||||
<slot />
|
||||
{/if}
|
||||
{#if !disabled && type !== "formula" && !disabled && !attachmentTypes.includes(type)}
|
||||
<div
|
||||
|
@ -195,7 +187,7 @@
|
|||
on:drawerShow
|
||||
bind:this={bindingDrawer}
|
||||
title={title ?? placeholder ?? "Bindings"}
|
||||
left={drawerLeft}
|
||||
forceModal={true}
|
||||
>
|
||||
<Button cta slot="buttons" on:click={saveBinding}>Save</Button>
|
||||
<svelte:component
|
||||
|
|
Loading…
Reference in New Issue