From d9278dbc24a9fe37ec1334f97a1c05a69b3ab0ba Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 9 Dec 2021 11:25:32 +0000 Subject: [PATCH] Dynamically enrich button actions at runtime and provide additional ephemeral button action output context --- .../EventsEditor/EventEditor.svelte | 1 - packages/client/src/utils/buttonActions.js | 35 +++++++++- packages/client/src/utils/componentProps.js | 65 ++++++++++++------- 3 files changed, 75 insertions(+), 26 deletions(-) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte index 7b2d04b73c..2361d8eb71 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte @@ -27,7 +27,6 @@ actions, selectedAction?.id ) - $: console.log(buttonContextBindings) $: allBindings = buttonContextBindings.concat(bindings) // Assign a unique ID to each action diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 0380f6d1e8..f5f88b9151 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -8,6 +8,7 @@ import { } from "stores" import { saveRow, deleteRow, executeQuery, triggerAutomation } from "api" import { ActionTypes } from "constants" +import { enrichDataBindings } from "./enrichDataBinding" const saveRowHandler = async (action, context) => { const { fields, providerId, tableId } = action.parameters @@ -25,7 +26,10 @@ const saveRowHandler = async (action, context) => { if (tableId) { payload.tableId = tableId } - await saveRow(payload) + const row = await saveRow(payload) + return { + row, + } } const duplicateRowHandler = async (action, context) => { @@ -178,11 +182,26 @@ export const enrichButtonActions = (actions, context) => { return actions } + // Button context is built up as actions are executed. + // Inherit any previous button context which may have come from actions + // before a confirmable action since this breaks the chain. + let buttonContext = context.actions || [] + const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]]) return async () => { for (let i = 0; i < handlers.length; i++) { try { - const action = actions[i] + // Skip any non-existent action definitions + if (!handlers[i]) { + continue + } + + // Built total context for this action + const totalContext = { ...context, actions: buttonContext } + + // Get and enrich this button action with the total context + let action = actions[i] + action = enrichDataBindings(action, totalContext) const callback = async () => handlers[i](action, context) // If this action is confirmable, show confirmation and await a @@ -198,7 +217,15 @@ export const enrichButtonActions = (actions, context) => { // then execute the rest of the actions in the chain const result = await callback() if (result !== false) { - const next = enrichButtonActions(actions.slice(i + 1), context) + // Generate a new total context to pass into the next enrichment + buttonContext.push(result) + const newContext = { ...context, actions: buttonContext } + + // Enrich and call the next button action + const next = enrichButtonActions( + actions.slice(i + 1), + newContext + ) await next() } } @@ -214,6 +241,8 @@ export const enrichButtonActions = (actions, context) => { const result = await callback() if (result === false) { return + } else { + buttonContext.push(result) } } } catch (error) { diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js index d600fdef04..b6b2cf7a99 100644 --- a/packages/client/src/utils/componentProps.js +++ b/packages/client/src/utils/componentProps.js @@ -32,35 +32,56 @@ export const enrichProps = (props, context) => { data: context[context.closestComponentId], } - // Enrich all data bindings in top level props - let enrichedProps = enrichDataBindings(props, totalContext) - - // Enrich click actions if they exist - Object.keys(enrichedProps).forEach(prop => { + // We want to exclude any button actions from enrichment at this stage. + // Extract top level button action settings. + let normalProps = { ...props } + let actionProps = {} + Object.keys(normalProps).forEach(prop => { if (prop?.toLowerCase().includes("onclick")) { - enrichedProps[prop] = enrichButtonActions( - enrichedProps[prop], - totalContext - ) + actionProps[prop] = normalProps[prop] + delete normalProps[prop] } }) - // Enrich any click actions in conditions - if (enrichedProps._conditions) { - enrichedProps._conditions.forEach(condition => { - if (condition.setting?.toLowerCase().includes("onclick")) { - condition.settingValue = enrichButtonActions( - condition.settingValue, - totalContext - ) + // Handle conditional UI separately after normal settings + let conditions = normalProps._conditions + delete normalProps._conditions - // If there is an onclick function in here then it won't be serialised - // properly, and therefore will not be updated properly. - // The solution to this is add a rand which will ensure diffs happen - // every time. - condition.rand = Math.random() + // Enrich all props except button actions + let enrichedProps = enrichDataBindings(normalProps, totalContext) + + // Enrich button actions. + // Actions are enriched into a function at this stage, but actual data + // binding enrichment is done dynamically at runtime. + Object.keys(actionProps).forEach(prop => { + enrichedProps[prop] = enrichButtonActions(actionProps[prop], totalContext) + }) + + // Conditions + if (conditions?.length) { + let enrichedConditions = [] + conditions.forEach(condition => { + if (condition.setting?.toLowerCase().includes("onclick")) { + // Copy and remove the setting value from the condition as it needs + // enriched separately + let toEnrich = { ...condition } + delete toEnrich.settingValue + + // Join the condition back together + enrichedConditions.push({ + ...enrichDataBindings(toEnrich, totalContext), + settingValue: enrichButtonActions( + condition.settingValue, + totalContext + ), + rand: Math.random(), + }) + } else { + // Normal condition + enrichedConditions.push(enrichDataBindings(condition, totalContext)) } }) + enrichedProps._conditions = enrichedConditions } return enrichedProps