Merge pull request #14370 from Budibase/dean-fixes

Binding Drawer and CodeEditor fixes
This commit is contained in:
deanhannigan 2024-08-14 09:21:50 +01:00 committed by GitHub
commit d7f00c981b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 120 additions and 79 deletions

View File

@ -70,6 +70,7 @@
// Stop unnecessary rendering
const memoBlock = memo(block)
const memoEnvVariables = memo($environment.variables)
const rowTriggers = [
TriggerStepID.ROW_UPDATED,
@ -91,11 +92,20 @@
let insertAtPos, getCaretPosition
let stepLayouts = {}
$: memoEnvVariables.set($environment.variables)
$: memoBlock.set(block)
$: filters = lookForFilters(schemaProperties) || []
$: tempFilters = filters
$: stepId = block.stepId
$: bindings = getAvailableBindings(block, $selectedAutomation?.definition)
$: stepId = $memoBlock.stepId
$: automationBindings = getAvailableBindings(
$memoBlock,
$selectedAutomation?.definition
)
$: environmentBindings = buildEnvironmentBindings($memoEnvVariables)
$: bindings = [...automationBindings, ...environmentBindings]
$: getInputData(testData, $memoBlock.inputs)
$: tableId = inputData ? inputData.tableId : null
$: table = tableId
@ -110,7 +120,7 @@
{ allowLinks: true }
)
$: queryLimit = tableId?.includes("datasource") ? "∞" : "1000"
$: isTrigger = block?.type === AutomationStepType.TRIGGER
$: isTrigger = $memoBlock?.type === AutomationStepType.TRIGGER
$: codeMode =
stepId === AutomationActionStepId.EXECUTE_BASH
? EditorModes.Handlebars
@ -119,13 +129,30 @@
disableWrapping: true,
})
$: editingJs = codeMode === EditorModes.JS
$: requiredProperties = isTestModal ? [] : block.schema["inputs"].required
$: requiredProperties = isTestModal
? []
: $memoBlock.schema["inputs"].required
$: stepCompletions =
codeMode === EditorModes.Handlebars
? [hbAutocomplete([...bindingsToCompletions(bindings, codeMode)])]
: []
const buildEnvironmentBindings = () => {
if ($licensing.environmentVariablesEnabled) {
return getEnvironmentBindings().map(binding => {
return {
...binding,
display: {
...binding.display,
rank: 98,
},
}
})
}
return []
}
const getInputData = (testData, blockInputs) => {
// Test data is not cloned for reactivity
let newInputData = testData || cloneDeep(blockInputs)
@ -151,9 +178,9 @@
// Store for any UX related data
const stepStore = writable({})
$: currentStep = $stepStore?.[block.id]
$: stepState = $stepStore?.[block.id]
$: customStepLayouts($memoBlock, schemaProperties, currentStep)
$: customStepLayouts($memoBlock, schemaProperties, stepState)
const customStepLayouts = block => {
if (
@ -185,7 +212,6 @@
onChange: e => {
onChange({ ["revision"]: e.detail })
},
bindings,
updateOnChange: false,
forceModal: true,
},
@ -214,7 +240,6 @@
onChange: e => {
onChange({ [rowIdentifier]: e.detail })
},
bindings,
updateOnChange: false,
forceModal: true,
},
@ -275,7 +300,7 @@
isUpdateRow: block.stepId === ActionStepID.UPDATE_ROW,
}
if (isTestModal && currentStep?.rowType === "oldRow") {
if (isTestModal && stepState?.rowType === "oldRow") {
return [
{
type: RowSelector,
@ -722,22 +747,9 @@
)
}
// Environment bindings
if ($licensing.environmentVariablesEnabled) {
bindings = bindings.concat(
getEnvironmentBindings().map(binding => {
return {
...binding,
display: {
...binding.display,
rank: 98,
},
}
})
)
}
return bindings
}
function lookForFilters(properties) {
if (!properties) {
return []
@ -770,7 +782,7 @@
drawer.hide()
}
function canShowField(key, value) {
function canShowField(value) {
const dependsOn = value?.dependsOn
return !dependsOn || !!inputData[dependsOn]
}
@ -829,6 +841,7 @@
<svelte:component
this={config.type}
{...config.props}
{bindings}
on:change={config.props.onChange}
/>
</PropField>
@ -836,6 +849,7 @@
<svelte:component
this={config.type}
{...config.props}
{bindings}
on:change={config.props.onChange}
/>
{/if}

View File

@ -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,11 @@
/>
{:else if schema.type === "longform"}
<TextArea
value={fieldData}
value={readableValue}
on:change={e =>
onChange({
row: {
[field]: e.detail,
[field]: readableToRuntimeBinding(parsedBindings, e.detail),
},
})}
/>
@ -144,11 +150,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),
},
})
}}

View File

@ -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,37 +334,13 @@
})
}
$: {
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 () => {
if (editor) {
editor.destroy()
}
})
onDestroy(() => {
if (editor) {
editor.destroy()
}
})
</script>

View File

@ -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