diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 246590a22e..85ac822006 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -1090,17 +1090,18 @@ export const removeBindings = (obj, replacement = "Invalid binding") => { * When converting from readable to runtime it can sometimes add too many square brackets, * this makes sure that doesn't happen. */ -const shouldReplaceBinding = (currentValue, convertFrom, convertTo) => { - if (!currentValue?.includes(convertFrom)) { +const shouldReplaceBinding = (currentValue, from, convertTo, binding) => { + if (!currentValue?.includes(from)) { return false } if (convertTo === "readableBinding") { - return true + // Dont replace if the value already matches the readable binding + return currentValue.indexOf(binding.readableBinding) === -1 } // remove all the spaces, if the input is surrounded by spaces e.g. [ Auto ID ] then // this makes sure it is detected const noSpaces = currentValue.replace(/\s+/g, "") - const fromNoSpaces = convertFrom.replace(/\s+/g, "") + const fromNoSpaces = from.replace(/\s+/g, "") const invalids = [ `[${fromNoSpaces}]`, `"${fromNoSpaces}"`, @@ -1152,8 +1153,11 @@ const bindingReplacement = ( // in the search, working from longest to shortest so always use best match first let searchString = newBoundValue for (let from of convertFromProps) { - if (isJS || shouldReplaceBinding(newBoundValue, from, convertTo)) { - const binding = bindableProperties.find(el => el[convertFrom] === from) + const binding = bindableProperties.find(el => el[convertFrom] === from) + if ( + isJS || + shouldReplaceBinding(newBoundValue, from, convertTo, binding) + ) { let idx do { // see if any instances of this binding exist in the search string diff --git a/packages/builder/src/builderStore/tests/dataBinding.test.js b/packages/builder/src/builderStore/tests/dataBinding.test.js new file mode 100644 index 0000000000..47f6564749 --- /dev/null +++ b/packages/builder/src/builderStore/tests/dataBinding.test.js @@ -0,0 +1,86 @@ +import { expect, describe, it, vi } from "vitest" +import { + runtimeToReadableBinding, + readableToRuntimeBinding, +} from "../dataBinding" + +vi.mock("@budibase/frontend-core") +vi.mock("builderStore/componentUtils") +vi.mock("builderStore/store") +vi.mock("builderStore/store/theme") +vi.mock("builderStore/store/temporal") + +describe("runtimeToReadableBinding", () => { + const bindableProperties = [ + { + category: "Current User", + icon: "User", + providerId: "user", + readableBinding: "Current User.firstName", + runtimeBinding: "[user].[firstName]", + type: "context", + }, + { + category: "Bindings", + icon: "Brackets", + readableBinding: "Binding.count", + runtimeBinding: "count", + type: "context", + }, + ] + it("should convert a runtime binding to a readable one", () => { + const textWithBindings = `Hello {{ [user].[firstName] }}! The count is {{ count }}.` + expect( + runtimeToReadableBinding( + bindableProperties, + textWithBindings, + "readableBinding" + ) + ).toEqual( + `Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.` + ) + }) + + it("should not convert to readable binding if it is already readable", () => { + const textWithBindings = `Hello {{ [user].[firstName] }}! The count is {{ Binding.count }}.` + expect( + runtimeToReadableBinding( + bindableProperties, + textWithBindings, + "readableBinding" + ) + ).toEqual( + `Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.` + ) + }) +}) + +describe("readableToRuntimeBinding", () => { + const bindableProperties = [ + { + category: "Current User", + icon: "User", + providerId: "user", + readableBinding: "Current User.firstName", + runtimeBinding: "[user].[firstName]", + type: "context", + }, + { + category: "Bindings", + icon: "Brackets", + readableBinding: "Binding.count", + runtimeBinding: "count", + type: "context", + }, + ] + it("should convert a readable binding to a runtime one", () => { + const textWithBindings = `Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.` + expect( + readableToRuntimeBinding( + bindableProperties, + textWithBindings, + "runtimeBinding" + ) + ).toEqual(`Hello {{ [user].[firstName] }}! The count is {{ count }}.`) + }) +})