From ec1e145eb54a919ea8c9052a0a2778d711840e6f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Jan 2025 18:06:49 +0000 Subject: [PATCH 01/17] Formatting for log lines. --- .../bindings/EvaluationSidePanel.svelte | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte index c8bf5529ad..54f7dc7d01 100644 --- a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte @@ -11,11 +11,16 @@ export let expressionError: string | undefined = undefined export let evaluating = false export let expression: string | null = null + export let logging: { log: string; line?: number }[] = [] $: error = expressionError != null $: empty = expression == null || expression?.trim() === "" $: success = !error && !empty $: highlightedResult = highlight(expressionResult) + $: highlightedLogs = logging.map(l => ({ + log: highlight(l.log), + line: l.line, + })) const formatError = (err: any) => { if (err.code === UserScriptError.code) { @@ -25,14 +30,14 @@ } // json can be any primitive type - const highlight = (json?: any | null) => { + const highlight = (json?: JSONValue | null) => { if (json == null) { return "" } // Attempt to parse and then stringify, in case this is valid result try { - json = JSON.stringify(JSON.parse(json), null, 2) + json = JSON.stringify(JSON.parse(json as any), null, 2) } catch (err) { // couldn't parse/stringify, just treat it as the raw input } @@ -90,8 +95,21 @@ {:else if error} {formatError(expressionError)} {:else} - - {@html highlightedResult} +
+ {#each highlightedLogs as logLine} +
+ + {@html logLine.log} + {#if logLine.line} + line {logLine.line} + {/if} +
+ {/each} +
+ + {@html highlightedResult} +
+
{/if} @@ -142,8 +160,21 @@ font-size: 12px; overflow-y: scroll; overflow-x: hidden; - white-space: pre-wrap; + white-space: pre-line; word-wrap: break-word; height: 0; } + .output-lines { + display: flex; + gap: var(--spacing-s); + flex-direction: column; + } + .line { + border-bottom: var(--border-light); + padding-bottom: var(--spacing-s); + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: end; + } From 6f9f36f9eb8d1c13a0c060762698c2a9f167c028 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Jan 2025 18:38:23 +0000 Subject: [PATCH 02/17] Getting string templates ready. --- .../src/helpers/javascript.ts | 22 +++++++++++++-- .../string-templates/src/processors/index.ts | 28 +++++++++++++++---- .../src/processors/postprocessor.ts | 28 +++++++++++-------- .../src/processors/preprocessor.ts | 7 +++-- packages/string-templates/src/types.ts | 5 ++++ 5 files changed, 69 insertions(+), 21 deletions(-) diff --git a/packages/string-templates/src/helpers/javascript.ts b/packages/string-templates/src/helpers/javascript.ts index 4fb1329196..a0fdd3cbe5 100644 --- a/packages/string-templates/src/helpers/javascript.ts +++ b/packages/string-templates/src/helpers/javascript.ts @@ -4,6 +4,7 @@ import { getJsHelperList } from "./list" import { iifeWrapper } from "../iife" import { JsTimeoutError, UserScriptError } from "../errors" import { cloneDeep } from "lodash/fp" +import { Log } from "../types" // The method of executing JS scripts depends on the bundle being built. // This setter is used in the entrypoint (either index.js or index.mjs). @@ -96,10 +97,9 @@ export function processJS(handlebars: string, context: any) { clonedContext = cloneDeep(context) } - const sandboxContext = { + const sandboxContext: Record = { $: (path: string) => getContextValue(path, clonedContext), helpers: getJsHelperList(), - // Proxy to evaluate snippets when running in the browser snippets: new Proxy( {}, @@ -114,8 +114,24 @@ export function processJS(handlebars: string, context: any) { ), } + const logs: Log[] = [] + // logging only supported on frontend + if (!isBackendService()) { + const log = (log: string) => logs.push({ log }) + sandboxContext.console = { + log: log, + info: log, + debug: log, + warn: log, + error: log, + // two below may need special cases + trace: log, + table: log, + } + } + // Create a sandbox with our context and run the JS - const res = { data: runJS(js, sandboxContext) } + const res = { data: runJS(js, sandboxContext), logs } return `{{${LITERAL_MARKER} js_result-${JSON.stringify(res)}}}` } catch (error: any) { onErrorLog && onErrorLog(error) diff --git a/packages/string-templates/src/processors/index.ts b/packages/string-templates/src/processors/index.ts index 79085b0dfe..4454d02738 100644 --- a/packages/string-templates/src/processors/index.ts +++ b/packages/string-templates/src/processors/index.ts @@ -1,9 +1,16 @@ import { FIND_HBS_REGEX } from "../utilities" import * as preprocessor from "./preprocessor" +import type { Preprocessor } from "./preprocessor" import * as postprocessor from "./postprocessor" -import { ProcessOptions } from "../types" +import type { Postprocessor } from "./postprocessor" +import { Log, ProcessOptions } from "../types" -function process(output: string, processors: any[], opts?: ProcessOptions) { +function process( + output: string, + processors: (Preprocessor | Postprocessor)[], + opts?: ProcessOptions +) { + let logs: Log[] = [] for (let processor of processors) { // if a literal statement has occurred stop if (typeof output !== "string") { @@ -16,10 +23,16 @@ function process(output: string, processors: any[], opts?: ProcessOptions) { continue } for (let match of matches) { - output = processor.process(output, match, opts) + const res = processor.process(output, match, opts || {}) + if (typeof res === "object" && "logs" in res && res.logs) { + logs = logs.concat(res.logs) + output = res.result + } else { + output = res as string + } } } - return output + return { result: output, logs } } export function preprocess(string: string, opts: ProcessOptions) { @@ -30,8 +43,13 @@ export function preprocess(string: string, opts: ProcessOptions) { ) } - return process(string, processors, opts) + return process(string, processors, opts).result } + export function postprocess(string: string) { + return process(string, postprocessor.processors).result +} + +export function postprocessWithLogs(string: string) { return process(string, postprocessor.processors) } diff --git a/packages/string-templates/src/processors/postprocessor.ts b/packages/string-templates/src/processors/postprocessor.ts index 6ddc0e67cd..49d5f7d1cf 100644 --- a/packages/string-templates/src/processors/postprocessor.ts +++ b/packages/string-templates/src/processors/postprocessor.ts @@ -1,12 +1,16 @@ import { LITERAL_MARKER } from "../helpers/constants" +import { Log } from "../types" export enum PostProcessorNames { CONVERT_LITERALS = "convert-literals", } -type PostprocessorFn = (statement: string) => string +export type PostprocessorFn = (statement: string) => { + result: any + logs?: Log[] +} -class Postprocessor { +export class Postprocessor { name: PostProcessorNames private readonly fn: PostprocessorFn @@ -23,12 +27,12 @@ class Postprocessor { export const processors = [ new Postprocessor( PostProcessorNames.CONVERT_LITERALS, - (statement: string) => { + (statement: string): { result: any; logs?: Log[] } => { if ( typeof statement !== "string" || !statement.includes(LITERAL_MARKER) ) { - return statement + return { result: statement } } const splitMarkerIndex = statement.indexOf("-") const type = statement.substring(12, splitMarkerIndex) @@ -38,20 +42,22 @@ export const processors = [ ) switch (type) { case "string": - return value + return { result: value } case "number": - return parseFloat(value) + return { result: parseFloat(value) } case "boolean": - return value === "true" + return { result: value === "true" } case "object": - return JSON.parse(value) - case "js_result": + return { result: JSON.parse(value) } + case "js_result": { // We use the literal helper to process the result of JS expressions // as we want to be able to return any types. // We wrap the value in an abject to be able to use undefined properly. - return JSON.parse(value).data + const parsed = JSON.parse(value) + return { result: parsed.data, logs: parsed.logs } + } } - return value + return { result: value } } ), ] diff --git a/packages/string-templates/src/processors/preprocessor.ts b/packages/string-templates/src/processors/preprocessor.ts index 97e5c56fcc..37981f31a8 100644 --- a/packages/string-templates/src/processors/preprocessor.ts +++ b/packages/string-templates/src/processors/preprocessor.ts @@ -11,9 +11,12 @@ export enum PreprocessorNames { NORMALIZE_SPACES = "normalize-spaces", } -type PreprocessorFn = (statement: string, opts?: ProcessOptions) => string +export type PreprocessorFn = ( + statement: string, + opts?: ProcessOptions +) => string -class Preprocessor { +export class Preprocessor { name: string private readonly fn: PreprocessorFn diff --git a/packages/string-templates/src/types.ts b/packages/string-templates/src/types.ts index 2a7a430bee..c973142c93 100644 --- a/packages/string-templates/src/types.ts +++ b/packages/string-templates/src/types.ts @@ -8,3 +8,8 @@ export interface ProcessOptions { onlyFound?: boolean disabledHelpers?: string[] } + +export interface Log { + log: string + line?: number +} From 28958f5a1ce32b46bd6415de0c6d10d55f27a3eb Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 16 Jan 2025 15:29:50 +0000 Subject: [PATCH 03/17] Expose the ability to get logs. --- packages/string-templates/src/index.ts | 82 ++++++++++++++++++++------ 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/packages/string-templates/src/index.ts b/packages/string-templates/src/index.ts index 7246bc4942..fafff5d9fb 100644 --- a/packages/string-templates/src/index.ts +++ b/packages/string-templates/src/index.ts @@ -1,7 +1,7 @@ import { createContext, runInNewContext } from "vm" import { create, TemplateDelegate } from "handlebars" import { registerAll, registerMinimum } from "./helpers/index" -import { postprocess, preprocess } from "./processors" +import { postprocess, postprocessWithLogs, preprocess } from "./processors" import { atob, btoa, @@ -15,7 +15,7 @@ import { convertHBSBlock } from "./conversion" import { removeJSRunner, setJSRunner } from "./helpers/javascript" import manifest from "./manifest.json" -import { ProcessOptions } from "./types" +import { Log, ProcessOptions } from "./types" import { UserScriptError } from "./errors" export { helpersToRemoveForJs, getJsHelperList } from "./helpers/list" @@ -187,23 +187,27 @@ export function processObjectSync( return object } -/** - * This will process a single handlebars containing string. If the string passed in has no valid handlebars statements - * then nothing will occur. This is a pure sync call and therefore does not have the full functionality of the async call. - * @param {string} string The template string which is the filled from the context object. - * @param {object} context An object of information which will be used to enrich the string. - * @param {object|undefined} [opts] optional - specify some options for processing. - * @returns {string} The enriched string, all templates should have been replaced if they can be. - */ -export function processStringSync( +// keep the logging function internal, don't want to add this to the process options directly +// as it can't be used for object processing etc. +function processStringSyncInternal( + str: string, + context?: object, + opts?: ProcessOptions & { logging: false } +): string +function processStringSyncInternal( + str: string, + context?: object, + opts?: ProcessOptions & { logging: true } +): { result: string; logs: Log[] } +function processStringSyncInternal( string: string, context?: object, - opts?: ProcessOptions -): string { + opts?: ProcessOptions & { logging: boolean } +): string | { result: string; logs: Log[] } { // Take a copy of input in case of error const input = string if (typeof string !== "string") { - throw "Cannot process non-string types." + throw new Error("Cannot process non-string types.") } function process(stringPart: string) { // context is needed to check for overlap between helpers and context @@ -217,16 +221,24 @@ export function processStringSync( }, ...context, }) - return postprocess(processedString) + return opts?.logging + ? postprocessWithLogs(processedString) + : postprocess(processedString) } try { if (opts && opts.onlyFound) { + let logs: Log[] = [] const blocks = findHBSBlocks(string) for (let block of blocks) { const outcome = process(block) - string = string.replace(block, outcome) + if (typeof outcome === "object" && "result" in outcome) { + logs = logs.concat(outcome.logs || []) + string = string.replace(block, outcome.result) + } else { + string = string.replace(block, outcome) + } } - return string + return opts?.logging ? string : { result: string, logs } } else { return process(string) } @@ -239,6 +251,42 @@ export function processStringSync( } } +/** + * This will process a single handlebars containing string. If the string passed in has no valid handlebars statements + * then nothing will occur. This is a pure sync call and therefore does not have the full functionality of the async call. + * @param {string} string The template string which is the filled from the context object. + * @param {object} context An object of information which will be used to enrich the string. + * @param {object|undefined} [opts] optional - specify some options for processing. + * @returns {string} The enriched string, all templates should have been replaced if they can be. + */ +export function processStringSync( + string: string, + context?: object, + opts?: ProcessOptions +): string { + return processStringSyncInternal(string, context, { + ...opts, + logging: false, + }) +} + +/** + * Same as function above, but allows logging to be returned - this is only for JS bindings. + */ +export function processStringWithLogsSync( + string: string, + context?: object, + opts?: ProcessOptions +): { result: string; logs: Log[] } { + if (isBackendService()) { + throw new Error("Logging disabled for backend bindings") + } + return processStringSyncInternal(string, context, { + ...opts, + logging: true, + }) +} + /** * By default with expressions like {{ name }} handlebars will escape various * characters, which can be problematic. To fix this we use the syntax {{{ name }}}, From d3a2306787d15b9051571572c3b12fcdb6295c76 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 16 Jan 2025 15:48:49 +0000 Subject: [PATCH 04/17] Finishing link up of logs. --- .../src/components/common/bindings/BindingPanel.svelte | 9 +++++++-- .../common/bindings/EvaluationSidePanel.svelte | 5 +++-- packages/string-templates/src/index.ts | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 98df69bc06..ffb477012c 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -12,7 +12,7 @@ decodeJSBinding, encodeJSBinding, processObjectSync, - processStringSync, + processStringWithLogsSync, } from "@budibase/string-templates" import { readableToRuntimeBinding } from "@/dataBinding" import CodeEditor from "../CodeEditor/CodeEditor.svelte" @@ -41,6 +41,7 @@ InsertAtPositionFn, JSONValue, } from "@budibase/types" + import type { Log } from "@budibase/string-templates" import type { CompletionContext } from "@codemirror/autocomplete" const dispatch = createEventDispatcher() @@ -66,6 +67,7 @@ let insertAtPos: InsertAtPositionFn | undefined let targetMode: BindingMode | null = null let expressionResult: string | undefined + let expressionLogs: Log[] | undefined let expressionError: string | undefined let evaluating = false @@ -157,7 +159,7 @@ (expression: string | null, context: any, snippets: Snippet[]) => { try { expressionError = undefined - expressionResult = processStringSync( + const output = processStringWithLogsSync( expression || "", { ...context, @@ -167,6 +169,8 @@ noThrow: false, } ) + expressionResult = output.result + expressionLogs = output.logs } catch (err: any) { expressionResult = undefined expressionError = err @@ -421,6 +425,7 @@ diff --git a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte index 54f7dc7d01..41245af4f9 100644 --- a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte @@ -4,20 +4,21 @@ import { Helpers } from "@budibase/bbui" import { fade } from "svelte/transition" import { UserScriptError } from "@budibase/string-templates" + import type { Log } from "@budibase/string-templates" import type { JSONValue } from "@budibase/types" // this can be essentially any primitive response from the JS function export let expressionResult: JSONValue | undefined = undefined export let expressionError: string | undefined = undefined + export let expressionLogs: Log[] = [] export let evaluating = false export let expression: string | null = null - export let logging: { log: string; line?: number }[] = [] $: error = expressionError != null $: empty = expression == null || expression?.trim() === "" $: success = !error && !empty $: highlightedResult = highlight(expressionResult) - $: highlightedLogs = logging.map(l => ({ + $: highlightedLogs = expressionLogs.map(l => ({ log: highlight(l.log), line: l.line, })) diff --git a/packages/string-templates/src/index.ts b/packages/string-templates/src/index.ts index fafff5d9fb..553c0e8861 100644 --- a/packages/string-templates/src/index.ts +++ b/packages/string-templates/src/index.ts @@ -18,6 +18,7 @@ import manifest from "./manifest.json" import { Log, ProcessOptions } from "./types" import { UserScriptError } from "./errors" +export type { Log } from "./types" export { helpersToRemoveForJs, getJsHelperList } from "./helpers/list" export { FIND_ANY_HBS_REGEX } from "./utilities" export { setJSRunner, setOnErrorLog } from "./helpers/javascript" From e6d536bcc83e172926fb753ea30ecf95ba2860a1 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 16 Jan 2025 18:15:54 +0000 Subject: [PATCH 05/17] Getting the line number calculated correctly, as well as adding some basic test cases. --- .../bindings/EvaluationSidePanel.svelte | 2 +- .../src/helpers/javascript.ts | 23 +++++++++++-- packages/string-templates/src/index.ts | 16 ++------- packages/string-templates/src/utilities.ts | 17 ++++++++++ .../string-templates/test/jsLogging.spec.ts | 33 +++++++++++++++++++ 5 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 packages/string-templates/test/jsLogging.spec.ts diff --git a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte index 41245af4f9..984fba9b7a 100644 --- a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte @@ -102,7 +102,7 @@ {@html logLine.log} {#if logLine.line} - line {logLine.line} + :{logLine.line} {/if} {/each} diff --git a/packages/string-templates/src/helpers/javascript.ts b/packages/string-templates/src/helpers/javascript.ts index a0fdd3cbe5..a1bfb7a824 100644 --- a/packages/string-templates/src/helpers/javascript.ts +++ b/packages/string-templates/src/helpers/javascript.ts @@ -1,4 +1,9 @@ -import { atob, isBackendService, isJSAllowed } from "../utilities" +import { + atob, + frontendWrapJS, + isBackendService, + isJSAllowed, +} from "../utilities" import { LITERAL_MARKER } from "../helpers/constants" import { getJsHelperList } from "./list" import { iifeWrapper } from "../iife" @@ -117,7 +122,21 @@ export function processJS(handlebars: string, context: any) { const logs: Log[] = [] // logging only supported on frontend if (!isBackendService()) { - const log = (log: string) => logs.push({ log }) + // this counts the lines in the wrapped JS *before* the user's code, so that we can minus it + const jsLineCount = frontendWrapJS(js).split(js)[0].split("\n").length + const log = (log: string) => { + // quick way to find out what line this is being called from + // its an anonymous function and we look for the overall length to find the + // line number we care about (from the users function) + // JS stack traces are in the format function:line:column + const lineNumber = new Error().stack?.match( + /:(\d+):\d+/ + )?.[1] + logs.push({ + log, + line: lineNumber ? parseInt(lineNumber) - jsLineCount : undefined, + }) + } sandboxContext.console = { log: log, info: log, diff --git a/packages/string-templates/src/index.ts b/packages/string-templates/src/index.ts index 553c0e8861..a21bfdb755 100644 --- a/packages/string-templates/src/index.ts +++ b/packages/string-templates/src/index.ts @@ -8,6 +8,7 @@ import { FIND_ANY_HBS_REGEX, FIND_HBS_REGEX, findDoubleHbsInstances, + frontendWrapJS, isBackendService, prefixStrings, } from "./utilities" @@ -511,20 +512,7 @@ export function browserJSSetup() { setJSRunner((js: string, context: Record) => { createContext(context) - const wrappedJs = ` - result = { - result: null, - error: null, - }; - - try { - result.result = ${js}; - } catch (e) { - result.error = e; - } - - result; - ` + const wrappedJs = frontendWrapJS(js) const result = runInNewContext(wrappedJs, context, { timeout: 1000 }) if (result.error) { diff --git a/packages/string-templates/src/utilities.ts b/packages/string-templates/src/utilities.ts index 779bef3735..dba1faab17 100644 --- a/packages/string-templates/src/utilities.ts +++ b/packages/string-templates/src/utilities.ts @@ -86,3 +86,20 @@ export const prefixStrings = ( const regexPattern = new RegExp(`\\b(${escapedStrings.join("|")})\\b`, "g") return baseString.replace(regexPattern, `${prefix}$1`) } + +export function frontendWrapJS(js: string) { + return ` + result = { + result: null, + error: null, + }; + + try { + result.result = ${js}; + } catch (e) { + result.error = e; + } + + result; + ` +} diff --git a/packages/string-templates/test/jsLogging.spec.ts b/packages/string-templates/test/jsLogging.spec.ts new file mode 100644 index 0000000000..9b2bb945d2 --- /dev/null +++ b/packages/string-templates/test/jsLogging.spec.ts @@ -0,0 +1,33 @@ +import { + processStringWithLogsSync, + encodeJSBinding, + defaultJSSetup, +} from "../src/index" + +const processJS = (js: string, context?: object) => { + return processStringWithLogsSync(encodeJSBinding(js), context) +} + +describe("Javascript", () => { + beforeAll(() => { + defaultJSSetup() + }) + + describe("Test logging in JS bindings", () => { + it("should execute a simple expression", () => { + const output = processJS( + `console.log("hello"); + console.log("world"); + console.log("foo"); + return "hello"` + ) + expect(output.result).toBe("hello") + expect(output.logs[0].log).toBe("hello") + expect(output.logs[0].line).toBe(1) + expect(output.logs[1].log).toBe("world") + expect(output.logs[1].line).toBe(2) + expect(output.logs[2].log).toBe("foo") + expect(output.logs[2].line).toBe(3) + }) + }) +}) From e146d995ebcd89c661e769b21743875ceddd81c0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 17 Jan 2025 11:06:55 +0000 Subject: [PATCH 06/17] Adding in support for multi-parameter logs and actual logging to console. --- .../bindings/EvaluationSidePanel.svelte | 2 +- .../src/helpers/javascript.ts | 48 +++++++++++-------- packages/string-templates/src/types.ts | 2 +- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte index 984fba9b7a..dc3f585033 100644 --- a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte @@ -19,7 +19,7 @@ $: success = !error && !empty $: highlightedResult = highlight(expressionResult) $: highlightedLogs = expressionLogs.map(l => ({ - log: highlight(l.log), + log: highlight(l.log.join(", ")), line: l.line, })) diff --git a/packages/string-templates/src/helpers/javascript.ts b/packages/string-templates/src/helpers/javascript.ts index a1bfb7a824..5a4f69de5b 100644 --- a/packages/string-templates/src/helpers/javascript.ts +++ b/packages/string-templates/src/helpers/javascript.ts @@ -124,28 +124,38 @@ export function processJS(handlebars: string, context: any) { if (!isBackendService()) { // this counts the lines in the wrapped JS *before* the user's code, so that we can minus it const jsLineCount = frontendWrapJS(js).split(js)[0].split("\n").length - const log = (log: string) => { - // quick way to find out what line this is being called from - // its an anonymous function and we look for the overall length to find the - // line number we care about (from the users function) - // JS stack traces are in the format function:line:column - const lineNumber = new Error().stack?.match( - /:(\d+):\d+/ - )?.[1] - logs.push({ - log, - line: lineNumber ? parseInt(lineNumber) - jsLineCount : undefined, - }) + const buildLogResponse = ( + type: "log" | "info" | "debug" | "warn" | "error" | "trace" | "table" + ) => { + return (...props: any[]) => { + console[type](...props) + props.forEach((prop, index) => { + if (typeof prop === "object") { + props[index] = JSON.stringify(prop) + } + }) + // quick way to find out what line this is being called from + // its an anonymous function and we look for the overall length to find the + // line number we care about (from the users function) + // JS stack traces are in the format function:line:column + const lineNumber = new Error().stack?.match( + /:(\d+):\d+/ + )?.[1] + logs.push({ + log: props, + line: lineNumber ? parseInt(lineNumber) - jsLineCount : undefined, + }) + } } sandboxContext.console = { - log: log, - info: log, - debug: log, - warn: log, - error: log, + log: buildLogResponse("log"), + info: buildLogResponse("info"), + debug: buildLogResponse("debug"), + warn: buildLogResponse("warn"), + error: buildLogResponse("error"), // two below may need special cases - trace: log, - table: log, + trace: buildLogResponse("trace"), + table: buildLogResponse("table"), } } diff --git a/packages/string-templates/src/types.ts b/packages/string-templates/src/types.ts index c973142c93..a32149c8bb 100644 --- a/packages/string-templates/src/types.ts +++ b/packages/string-templates/src/types.ts @@ -10,6 +10,6 @@ export interface ProcessOptions { } export interface Log { - log: string + log: any[] line?: number } From 272bbf5f8bbf4f59307baf525f02f338633b3391 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 17 Jan 2025 17:18:42 +0000 Subject: [PATCH 07/17] Logging with types - allows for coloured outputs. --- packages/bbui/src/bbui.css | 5 +++ .../bindings/EvaluationSidePanel.svelte | 36 ++++++++++++++----- .../src/helpers/javascript.ts | 11 +++--- packages/string-templates/src/index.ts | 2 +- packages/string-templates/src/types.ts | 3 ++ 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/bbui/src/bbui.css b/packages/bbui/src/bbui.css index dd0588818e..810c5ff2c0 100644 --- a/packages/bbui/src/bbui.css +++ b/packages/bbui/src/bbui.css @@ -45,6 +45,11 @@ --purple: #806fde; --purple-dark: #130080; + --error-bg: rgba(226, 109, 105, 0.3); + --warning-bg: rgba(255, 210, 106, 0.3); + --error-content: rgba(226, 109, 105, 0.6); + --warning-content: rgba(255, 210, 106, 0.6); + --rounded-small: 4px; --rounded-medium: 8px; --rounded-large: 16px; diff --git a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte index dc3f585033..fcd23bb816 100644 --- a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte @@ -21,6 +21,7 @@ $: highlightedLogs = expressionLogs.map(l => ({ log: highlight(l.log.join(", ")), line: l.line, + type: l.type, })) const formatError = (err: any) => { @@ -67,7 +68,7 @@
{#if error} - +
Error
{#if evaluating}
@@ -98,9 +99,24 @@ {:else}
{#each highlightedLogs as logLine} -
- - {@html logLine.log} +
+
+ {#if logLine.type === "error"} + + {:else if logLine.type === "warn"} + + {/if} + + {@html logLine.log} +
{#if logLine.line} :{logLine.line} {/if} @@ -149,10 +165,9 @@ height: 100%; z-index: 1; position: absolute; - opacity: 10%; } .header.error::before { - background: var(--spectrum-global-color-red-400); + background: var(--error-bg); } .body { flex: 1 1 auto; @@ -167,15 +182,20 @@ } .output-lines { display: flex; - gap: var(--spacing-s); flex-direction: column; + gap: var(--spacing-xs); } .line { border-bottom: var(--border-light); - padding-bottom: var(--spacing-s); display: flex; flex-direction: row; justify-content: space-between; align-items: end; + padding: var(--spacing-s); + } + .icon-log { + display: flex; + gap: var(--spacing-s); + align-items: start; } diff --git a/packages/string-templates/src/helpers/javascript.ts b/packages/string-templates/src/helpers/javascript.ts index 5a4f69de5b..997ca7b6ec 100644 --- a/packages/string-templates/src/helpers/javascript.ts +++ b/packages/string-templates/src/helpers/javascript.ts @@ -9,7 +9,7 @@ import { getJsHelperList } from "./list" import { iifeWrapper } from "../iife" import { JsTimeoutError, UserScriptError } from "../errors" import { cloneDeep } from "lodash/fp" -import { Log } from "../types" +import { Log, LogType } from "../types" // The method of executing JS scripts depends on the bundle being built. // This setter is used in the entrypoint (either index.js or index.mjs). @@ -124,9 +124,7 @@ export function processJS(handlebars: string, context: any) { if (!isBackendService()) { // this counts the lines in the wrapped JS *before* the user's code, so that we can minus it const jsLineCount = frontendWrapJS(js).split(js)[0].split("\n").length - const buildLogResponse = ( - type: "log" | "info" | "debug" | "warn" | "error" | "trace" | "table" - ) => { + const buildLogResponse = (type: LogType) => { return (...props: any[]) => { console[type](...props) props.forEach((prop, index) => { @@ -144,6 +142,7 @@ export function processJS(handlebars: string, context: any) { logs.push({ log: props, line: lineNumber ? parseInt(lineNumber) - jsLineCount : undefined, + type, }) } } @@ -153,8 +152,8 @@ export function processJS(handlebars: string, context: any) { debug: buildLogResponse("debug"), warn: buildLogResponse("warn"), error: buildLogResponse("error"), - // two below may need special cases - trace: buildLogResponse("trace"), + // table should be treated differently, but works the same + // as the rest of the logs for now table: buildLogResponse("table"), } } diff --git a/packages/string-templates/src/index.ts b/packages/string-templates/src/index.ts index a21bfdb755..67ccde727e 100644 --- a/packages/string-templates/src/index.ts +++ b/packages/string-templates/src/index.ts @@ -19,7 +19,7 @@ import manifest from "./manifest.json" import { Log, ProcessOptions } from "./types" import { UserScriptError } from "./errors" -export type { Log } from "./types" +export type { Log, LogType } from "./types" export { helpersToRemoveForJs, getJsHelperList } from "./helpers/list" export { FIND_ANY_HBS_REGEX } from "./utilities" export { setJSRunner, setOnErrorLog } from "./helpers/javascript" diff --git a/packages/string-templates/src/types.ts b/packages/string-templates/src/types.ts index a32149c8bb..f6ec7098f9 100644 --- a/packages/string-templates/src/types.ts +++ b/packages/string-templates/src/types.ts @@ -9,7 +9,10 @@ export interface ProcessOptions { disabledHelpers?: string[] } +export type LogType = "log" | "info" | "debug" | "warn" | "error" | "table" + export interface Log { log: any[] line?: number + type?: LogType } From bd5e55480e045886597a0c5d24938756954ec4be Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 11:16:19 +0000 Subject: [PATCH 08/17] Adding more test cases. --- .../string-templates/test/jsLogging.spec.ts | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/packages/string-templates/test/jsLogging.spec.ts b/packages/string-templates/test/jsLogging.spec.ts index 9b2bb945d2..44b3b392ba 100644 --- a/packages/string-templates/test/jsLogging.spec.ts +++ b/packages/string-templates/test/jsLogging.spec.ts @@ -21,13 +21,33 @@ describe("Javascript", () => { console.log("foo"); return "hello"` ) - expect(output.result).toBe("hello") - expect(output.logs[0].log).toBe("hello") - expect(output.logs[0].line).toBe(1) - expect(output.logs[1].log).toBe("world") - expect(output.logs[1].line).toBe(2) - expect(output.logs[2].log).toBe("foo") - expect(output.logs[2].line).toBe(3) + expect(output.result).toEqual("hello") + expect(output.logs[0].log).toEqual(["hello"]) + expect(output.logs[0].line).toEqual(1) + expect(output.logs[1].log).toEqual(["world"]) + expect(output.logs[1].line).toEqual(2) + expect(output.logs[2].log).toEqual(["foo"]) + expect(output.logs[2].line).toEqual(3) }) }) + + it("should log comma separated values", () => { + const output = processJS(`console.log(1, { a: 1 }); return 1`) + expect(output.logs[0].log).toEqual([1, JSON.stringify({ a: 1 })]) + expect(output.logs[0].line).toEqual(1) + }) + + it("should return the type working with warn", () => { + const output = processJS(`console.warn("warning"); return 1`) + expect(output.logs[0].log).toEqual(["warning"]) + expect(output.logs[0].line).toEqual(1) + expect(output.logs[0].type).toEqual("warn") + }) + + it("should return the type working with error", () => { + const output = processJS(`console.error("error"); return 1`) + expect(output.logs[0].log).toEqual(["error"]) + expect(output.logs[0].line).toEqual(1) + expect(output.logs[0].type).toEqual("error") + }) }) From 3b03515253bd6f5203b65b67be2d9eb6ebd91111 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 15:23:00 +0000 Subject: [PATCH 09/17] Fixing test failure. --- packages/string-templates/src/processors/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/string-templates/src/processors/index.ts b/packages/string-templates/src/processors/index.ts index 4454d02738..0916c791cd 100644 --- a/packages/string-templates/src/processors/index.ts +++ b/packages/string-templates/src/processors/index.ts @@ -24,8 +24,10 @@ function process( } for (let match of matches) { const res = processor.process(output, match, opts || {}) - if (typeof res === "object" && "logs" in res && res.logs) { - logs = logs.concat(res.logs) + if (typeof res === "object") { + if ("logs" in res && res.logs) { + logs = logs.concat(res.logs) + } output = res.result } else { output = res as string From a920be3207f850c71a52758b7d675e86a2dc7643 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 15:33:06 +0000 Subject: [PATCH 10/17] Remove error. --- packages/string-templates/test/jsLogging.spec.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/string-templates/test/jsLogging.spec.ts b/packages/string-templates/test/jsLogging.spec.ts index 44b3b392ba..f328b76c7c 100644 --- a/packages/string-templates/test/jsLogging.spec.ts +++ b/packages/string-templates/test/jsLogging.spec.ts @@ -43,11 +43,4 @@ describe("Javascript", () => { expect(output.logs[0].line).toEqual(1) expect(output.logs[0].type).toEqual("warn") }) - - it("should return the type working with error", () => { - const output = processJS(`console.error("error"); return 1`) - expect(output.logs[0].log).toEqual(["error"]) - expect(output.logs[0].line).toEqual(1) - expect(output.logs[0].type).toEqual("error") - }) }) From ae73c0147ffc481206a4e7bc29e0d942cbba511e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 15:41:08 +0000 Subject: [PATCH 11/17] Adding test checks. --- packages/string-templates/src/environment.ts | 11 +++++++++++ packages/string-templates/src/helpers/javascript.ts | 5 ++++- packages/string-templates/test/jsLogging.spec.ts | 7 +++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 packages/string-templates/src/environment.ts diff --git a/packages/string-templates/src/environment.ts b/packages/string-templates/src/environment.ts new file mode 100644 index 0000000000..ede52591b1 --- /dev/null +++ b/packages/string-templates/src/environment.ts @@ -0,0 +1,11 @@ +function isJest() { + return ( + process.env.NODE_ENV === "jest" || + (process.env.JEST_WORKER_ID != null && + process.env.JEST_WORKER_ID !== "null") + ) +} + +export function isTest() { + return isJest() +} diff --git a/packages/string-templates/src/helpers/javascript.ts b/packages/string-templates/src/helpers/javascript.ts index 997ca7b6ec..91f2f9a0ce 100644 --- a/packages/string-templates/src/helpers/javascript.ts +++ b/packages/string-templates/src/helpers/javascript.ts @@ -10,6 +10,7 @@ import { iifeWrapper } from "../iife" import { JsTimeoutError, UserScriptError } from "../errors" import { cloneDeep } from "lodash/fp" import { Log, LogType } from "../types" +import { isTest } from "../environment" // The method of executing JS scripts depends on the bundle being built. // This setter is used in the entrypoint (either index.js or index.mjs). @@ -126,7 +127,9 @@ export function processJS(handlebars: string, context: any) { const jsLineCount = frontendWrapJS(js).split(js)[0].split("\n").length const buildLogResponse = (type: LogType) => { return (...props: any[]) => { - console[type](...props) + if (!isTest()) { + console[type](...props) + } props.forEach((prop, index) => { if (typeof prop === "object") { props[index] = JSON.stringify(prop) diff --git a/packages/string-templates/test/jsLogging.spec.ts b/packages/string-templates/test/jsLogging.spec.ts index f328b76c7c..44b3b392ba 100644 --- a/packages/string-templates/test/jsLogging.spec.ts +++ b/packages/string-templates/test/jsLogging.spec.ts @@ -43,4 +43,11 @@ describe("Javascript", () => { expect(output.logs[0].line).toEqual(1) expect(output.logs[0].type).toEqual("warn") }) + + it("should return the type working with error", () => { + const output = processJS(`console.error("error"); return 1`) + expect(output.logs[0].log).toEqual(["error"]) + expect(output.logs[0].line).toEqual(1) + expect(output.logs[0].type).toEqual("error") + }) }) From 9c65f1ab41cfdb2e98282ed52d1af7e224152865 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 15:58:11 +0000 Subject: [PATCH 12/17] Another quick fix. --- packages/string-templates/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/string-templates/src/index.ts b/packages/string-templates/src/index.ts index 67ccde727e..b2097b0d4c 100644 --- a/packages/string-templates/src/index.ts +++ b/packages/string-templates/src/index.ts @@ -240,7 +240,7 @@ function processStringSyncInternal( string = string.replace(block, outcome) } } - return opts?.logging ? string : { result: string, logs } + return !opts?.logging ? string : { result: string, logs } } else { return process(string) } From 98bd824d7ae01e59df1141ed2f68c8b7b3e233b0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 16:33:21 +0000 Subject: [PATCH 13/17] Adding the ability to configure whether or not string templates is testing backend JS or frontend. --- packages/server/src/api/routes/tests/row.spec.ts | 2 ++ packages/string-templates/src/environment.ts | 12 ++++++++++++ packages/string-templates/src/index.ts | 1 + packages/string-templates/src/utilities.ts | 11 ++++++++--- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 576f0bb663..2a145e1ed9 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -50,9 +50,11 @@ import { JsTimeoutError } from "@budibase/string-templates" import { isDate } from "../../../utilities" import nock from "nock" import { mockChatGPTResponse } from "../../../tests/utilities/mocks/openai" +import { setTestingBackendJS } from "@budibase/string-templates" const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) +setTestingBackendJS() interface WaitOptions { name: string matchFn?: (event: any) => boolean diff --git a/packages/string-templates/src/environment.ts b/packages/string-templates/src/environment.ts index ede52591b1..6bee6fd3a9 100644 --- a/packages/string-templates/src/environment.ts +++ b/packages/string-templates/src/environment.ts @@ -9,3 +9,15 @@ function isJest() { export function isTest() { return isJest() } + +export const isJSAllowed = () => { + return process && !process.env.NO_JS +} + +export const isTestingBackendJS = () => { + return process && process.env.BACKEND_JS +} + +export const setTestingBackendJS = () => { + process.env.BACKEND_JS = "1" +} diff --git a/packages/string-templates/src/index.ts b/packages/string-templates/src/index.ts index b2097b0d4c..8dda8b71ab 100644 --- a/packages/string-templates/src/index.ts +++ b/packages/string-templates/src/index.ts @@ -20,6 +20,7 @@ import { Log, ProcessOptions } from "./types" import { UserScriptError } from "./errors" export type { Log, LogType } from "./types" +export { setTestingBackendJS } from "./environment" export { helpersToRemoveForJs, getJsHelperList } from "./helpers/list" export { FIND_ANY_HBS_REGEX } from "./utilities" export { setJSRunner, setOnErrorLog } from "./helpers/javascript" diff --git a/packages/string-templates/src/utilities.ts b/packages/string-templates/src/utilities.ts index dba1faab17..b05945f075 100644 --- a/packages/string-templates/src/utilities.ts +++ b/packages/string-templates/src/utilities.ts @@ -1,15 +1,20 @@ +import { isTest, isTestingBackendJS } from "./environment" + const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g export const FIND_HBS_REGEX = /{{([^{].*?)}}/g export const FIND_ANY_HBS_REGEX = /{?{{([^{].*?)}}}?/g export const FIND_TRIPLE_HBS_REGEX = /{{{([^{].*?)}}}/g -const isJest = () => typeof jest !== "undefined" - export const isBackendService = () => { + // allow configuring backend JS mode when testing - we default to assuming + // frontend, but need a method to control this + if (isTest() && isTestingBackendJS()) { + return true + } // We consider the tests for string-templates to be frontend, so that they // test the frontend JS functionality. - if (isJest()) { + if (isTest()) { return false } return typeof window === "undefined" From 68374bce29126c0f38da9f030acfdc82c2ed8e60 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 16:40:08 +0000 Subject: [PATCH 14/17] Testing backend JS further. --- packages/server/src/jsRunner/tests/jsRunner.spec.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index 006df19fa6..e10e9c4d43 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -1,5 +1,9 @@ import { validate as isValidUUID } from "uuid" -import { processStringSync, encodeJSBinding } from "@budibase/string-templates" +import { + processStringSync, + encodeJSBinding, + setTestingBackendJS, +} from "@budibase/string-templates" import { runJsHelpersTests } from "@budibase/string-templates/test/utils" @@ -7,6 +11,7 @@ import tk from "timekeeper" import { init } from ".." import TestConfiguration from "../../tests/utilities/TestConfiguration" +setTestingBackendJS() const DATE = "2021-01-21T12:00:00" tk.freeze(DATE) From 04a7878ce9ad4d6ea5656ae6409eb6cbbb68bb53 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 17:02:57 +0000 Subject: [PATCH 15/17] Changing how we enforce backend JS. --- packages/server/src/api/routes/tests/row.spec.ts | 2 -- .../automations/tests/utilities/AutomationTestBuilder.ts | 1 + packages/server/src/jsRunner/index.ts | 5 +++++ packages/server/src/jsRunner/tests/jsRunner.spec.ts | 7 +------ packages/string-templates/src/helpers/javascript.ts | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 2a145e1ed9..576f0bb663 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -50,11 +50,9 @@ import { JsTimeoutError } from "@budibase/string-templates" import { isDate } from "../../../utilities" import nock from "nock" import { mockChatGPTResponse } from "../../../tests/utilities/mocks/openai" -import { setTestingBackendJS } from "@budibase/string-templates" const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) -setTestingBackendJS() interface WaitOptions { name: string matchFn?: (event: any) => boolean diff --git a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts index 830d2ee5ca..f89c815752 100644 --- a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts +++ b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts @@ -43,6 +43,7 @@ import { import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as setup from "../utilities" import { automations } from "@budibase/shared-core" +import { setTestingBackendJS } from "@budibase/string-templates" type TriggerOutputs = | RowCreatedTriggerOutputs diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts index e17529a687..a29e952b6d 100644 --- a/packages/server/src/jsRunner/index.ts +++ b/packages/server/src/jsRunner/index.ts @@ -4,12 +4,17 @@ import { JsTimeoutError, setJSRunner, setOnErrorLog, + setTestingBackendJS, } from "@budibase/string-templates" import { context, logging } from "@budibase/backend-core" import tracer from "dd-trace" import { IsolatedVM } from "./vm" export function init() { + // enforce that if we're using isolated-VM runner then we are running backend JS + if (env.isTest()) { + setTestingBackendJS() + } setJSRunner((js: string, ctx: Record) => { return tracer.trace("runJS", {}, () => { try { diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index e10e9c4d43..006df19fa6 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -1,9 +1,5 @@ import { validate as isValidUUID } from "uuid" -import { - processStringSync, - encodeJSBinding, - setTestingBackendJS, -} from "@budibase/string-templates" +import { processStringSync, encodeJSBinding } from "@budibase/string-templates" import { runJsHelpersTests } from "@budibase/string-templates/test/utils" @@ -11,7 +7,6 @@ import tk from "timekeeper" import { init } from ".." import TestConfiguration from "../../tests/utilities/TestConfiguration" -setTestingBackendJS() const DATE = "2021-01-21T12:00:00" tk.freeze(DATE) diff --git a/packages/string-templates/src/helpers/javascript.ts b/packages/string-templates/src/helpers/javascript.ts index 91f2f9a0ce..6132adf892 100644 --- a/packages/string-templates/src/helpers/javascript.ts +++ b/packages/string-templates/src/helpers/javascript.ts @@ -88,7 +88,7 @@ export function processJS(handlebars: string, context: any) { let clonedContext: Record if (isBackendService()) { - // On the backned, values are copied across the isolated-vm boundary and + // On the backend, values are copied across the isolated-vm boundary and // so we don't need to do any cloning here. This does create a fundamental // difference in how JS executes on the frontend vs the backend, e.g. // consider this snippet: From d51491a19adc19b70fe80532d5bee7bad07c4f23 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Jan 2025 17:06:31 +0000 Subject: [PATCH 16/17] Linting. --- .../src/automations/tests/utilities/AutomationTestBuilder.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts index f89c815752..830d2ee5ca 100644 --- a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts +++ b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts @@ -43,7 +43,6 @@ import { import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as setup from "../utilities" import { automations } from "@budibase/shared-core" -import { setTestingBackendJS } from "@budibase/string-templates" type TriggerOutputs = | RowCreatedTriggerOutputs From c5e4edcc9713f6286644fe10f65c19ac02a5c66c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Jan 2025 11:54:27 +0000 Subject: [PATCH 17/17] Setting overflow-y in evaluation panel to auto. --- .../src/components/common/bindings/EvaluationSidePanel.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte index fcd23bb816..c47840ea83 100644 --- a/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte +++ b/packages/builder/src/components/common/bindings/EvaluationSidePanel.svelte @@ -174,7 +174,7 @@ padding: var(--spacing-m) var(--spacing-l); font-family: var(--font-mono); font-size: 12px; - overflow-y: scroll; + overflow-y: auto; overflow-x: hidden; white-space: pre-line; word-wrap: break-word;