Integrate actions into new global context and greatly improve performance by only enriching when required
This commit is contained in:
parent
3839e26758
commit
f78cc26a68
|
@ -35,6 +35,10 @@
|
||||||
findHBSBlocks,
|
findHBSBlocks,
|
||||||
isJSBinding,
|
isJSBinding,
|
||||||
} from "@budibase/string-templates"
|
} from "@budibase/string-templates"
|
||||||
|
import {
|
||||||
|
getActionContextKey,
|
||||||
|
getActionDependentContextKeys,
|
||||||
|
} from "../utils/buttonActions.js"
|
||||||
|
|
||||||
export let instance = {}
|
export let instance = {}
|
||||||
export let isLayout = false
|
export let isLayout = false
|
||||||
|
@ -165,9 +169,6 @@
|
||||||
hasMissingRequiredSettings)
|
hasMissingRequiredSettings)
|
||||||
$: emptyState = empty && showEmptyState
|
$: emptyState = empty && showEmptyState
|
||||||
|
|
||||||
// Enrich component settings
|
|
||||||
// $: enrichComponentSettings($context, settingsDefinitionMap)
|
|
||||||
|
|
||||||
// Evaluate conditional UI settings and store any component setting changes
|
// Evaluate conditional UI settings and store any component setting changes
|
||||||
// which need to be made
|
// which need to be made
|
||||||
$: evaluateConditions(conditions)
|
$: evaluateConditions(conditions)
|
||||||
|
@ -296,18 +297,42 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// The known context key map is built up at runtime, as changes to keys are
|
||||||
|
// encountered. We manually seed this to the required action keys as these
|
||||||
|
// are not encountered at runtime and so need computed in advance.
|
||||||
|
knownContextKeyMap = generateActionKeyMap(instance, settingsDefinition)
|
||||||
|
bindingString = bindings.join(" ")
|
||||||
|
|
||||||
// Run any migrations
|
// Run any migrations
|
||||||
runMigrations(instance, settingsDefinition)
|
runMigrations(instance, settingsDefinition)
|
||||||
|
|
||||||
// Force an initial enrichment of the new settings
|
// Force an initial enrichment of the new settings
|
||||||
enrichComponentSettings(get(context), settingsDefinitionMap, {
|
enrichComponentSettings(get(context), settingsDefinitionMap)
|
||||||
force: true,
|
}
|
||||||
})
|
|
||||||
bindingString = bindings.join(" ")
|
|
||||||
knownContextKeyMap = {}
|
|
||||||
|
|
||||||
// Force an initial enrichment of the new settings
|
// Extracts a map of all context keys which are required by action settings
|
||||||
enrichComponentSettings($context, settingsDefinitionMap)
|
// to provide the functions to evaluate at runtime. This needs done manually
|
||||||
|
// as the action definitions themselves do not specify bindings for action
|
||||||
|
// keys, meaning we cannot do this while doing the other normal bindings.
|
||||||
|
const generateActionKeyMap = (instance, settingsDefinition) => {
|
||||||
|
let map = {}
|
||||||
|
settingsDefinition.forEach(setting => {
|
||||||
|
if (setting.type === "event") {
|
||||||
|
instance[setting.key]?.forEach(action => {
|
||||||
|
// We depend on the actual action key
|
||||||
|
const actionKey = getActionContextKey(action)
|
||||||
|
if (actionKey) {
|
||||||
|
map[actionKey] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// We also depend on any manually declared context keys
|
||||||
|
getActionDependentContextKeys(action)?.forEach(key => {
|
||||||
|
map[key] = true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
const runMigrations = (instance, settingsDefinition) => {
|
const runMigrations = (instance, settingsDefinition) => {
|
||||||
|
|
|
@ -17,6 +17,54 @@ import { ActionTypes } from "constants"
|
||||||
import { enrichDataBindings } from "./enrichDataBinding"
|
import { enrichDataBindings } from "./enrichDataBinding"
|
||||||
import { Helpers } from "@budibase/bbui"
|
import { Helpers } from "@budibase/bbui"
|
||||||
|
|
||||||
|
// Default action handler, which extracts an action from context that was
|
||||||
|
// provided by another component and executes it with all action parameters
|
||||||
|
const contextActionHandler = async (action, context) => {
|
||||||
|
const key = getActionContextKey(action)
|
||||||
|
const fn = context[key]
|
||||||
|
if (fn) {
|
||||||
|
return await fn(action.parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates the context key, which is the key that this action depends on in
|
||||||
|
// context to provide the function it will run. This is broken out as a util
|
||||||
|
// because we reuse this inside the core Component.svelte file to determine
|
||||||
|
// what the required action context keys are for all action settings.
|
||||||
|
export const getActionContextKey = action => {
|
||||||
|
const type = action?.["##eventHandlerType"]
|
||||||
|
const key = (componentId, type) => `${componentId}_${type}`
|
||||||
|
switch (type) {
|
||||||
|
case "Scroll To Field":
|
||||||
|
return key(action.parameters.componentId, ActionTypes.ScrollTo)
|
||||||
|
case "Update Field Value":
|
||||||
|
return key(action.parameters.componentId, ActionTypes.UpdateFieldValue)
|
||||||
|
case "Validate Form":
|
||||||
|
return key(action.parameters.componentId, ActionTypes.ValidateForm)
|
||||||
|
case "Refresh Data Provider":
|
||||||
|
return key(action.parameters.componentId, ActionTypes.RefreshDatasource)
|
||||||
|
case "Clear Form":
|
||||||
|
return key(action.parameters.componentId, ActionTypes.ClearForm)
|
||||||
|
case "Change Form Step":
|
||||||
|
return key(action.parameters.componentId, ActionTypes.ChangeFormStep)
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If button actions depend on context, they must declare which keys they need
|
||||||
|
export const getActionDependentContextKeys = action => {
|
||||||
|
const type = action?.["##eventHandlerType"]
|
||||||
|
switch (type) {
|
||||||
|
case "Save Row":
|
||||||
|
case "Duplicate Row":
|
||||||
|
if (action.parameters?.providerId) {
|
||||||
|
return [action.parameters.providerId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
const saveRowHandler = async (action, context) => {
|
const saveRowHandler = async (action, context) => {
|
||||||
const { fields, providerId, tableId, notificationOverride } =
|
const { fields, providerId, tableId, notificationOverride } =
|
||||||
action.parameters
|
action.parameters
|
||||||
|
@ -189,17 +237,6 @@ const navigationHandler = action => {
|
||||||
routeStore.actions.navigate(url, peek, externalNewTab)
|
routeStore.actions.navigate(url, peek, externalNewTab)
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollHandler = async (action, context) => {
|
|
||||||
return await executeActionHandler(
|
|
||||||
context,
|
|
||||||
action.parameters.componentId,
|
|
||||||
ActionTypes.ScrollTo,
|
|
||||||
{
|
|
||||||
field: action.parameters.field,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryExecutionHandler = async action => {
|
const queryExecutionHandler = async action => {
|
||||||
const { datasourceId, queryId, queryParams, notificationOverride } =
|
const { datasourceId, queryId, queryParams, notificationOverride } =
|
||||||
action.parameters
|
action.parameters
|
||||||
|
@ -235,47 +272,6 @@ const queryExecutionHandler = async action => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const executeActionHandler = async (
|
|
||||||
context,
|
|
||||||
componentId,
|
|
||||||
actionType,
|
|
||||||
params
|
|
||||||
) => {
|
|
||||||
const fn = context[`${componentId}_${actionType}`]
|
|
||||||
if (fn) {
|
|
||||||
return await fn(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateFieldValueHandler = async (action, context) => {
|
|
||||||
return await executeActionHandler(
|
|
||||||
context,
|
|
||||||
action.parameters.componentId,
|
|
||||||
ActionTypes.UpdateFieldValue,
|
|
||||||
{
|
|
||||||
type: action.parameters.type,
|
|
||||||
field: action.parameters.field,
|
|
||||||
value: action.parameters.value,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const validateFormHandler = async (action, context) => {
|
|
||||||
return await executeActionHandler(
|
|
||||||
context,
|
|
||||||
action.parameters.componentId,
|
|
||||||
ActionTypes.ValidateForm
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshDataProviderHandler = async (action, context) => {
|
|
||||||
return await executeActionHandler(
|
|
||||||
context,
|
|
||||||
action.parameters.componentId,
|
|
||||||
ActionTypes.RefreshDatasource
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const logoutHandler = async action => {
|
const logoutHandler = async action => {
|
||||||
await authStore.actions.logOut()
|
await authStore.actions.logOut()
|
||||||
let redirectUrl = "/builder/auth/login"
|
let redirectUrl = "/builder/auth/login"
|
||||||
|
@ -292,23 +288,6 @@ const logoutHandler = async action => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearFormHandler = async (action, context) => {
|
|
||||||
return await executeActionHandler(
|
|
||||||
context,
|
|
||||||
action.parameters.componentId,
|
|
||||||
ActionTypes.ClearForm
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeFormStepHandler = async (action, context) => {
|
|
||||||
return await executeActionHandler(
|
|
||||||
context,
|
|
||||||
action.parameters.componentId,
|
|
||||||
ActionTypes.ChangeFormStep,
|
|
||||||
action.parameters
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeScreenModalHandler = action => {
|
const closeScreenModalHandler = action => {
|
||||||
let url
|
let url
|
||||||
if (action?.parameters) {
|
if (action?.parameters) {
|
||||||
|
@ -416,16 +395,10 @@ const handlerMap = {
|
||||||
["Duplicate Row"]: duplicateRowHandler,
|
["Duplicate Row"]: duplicateRowHandler,
|
||||||
["Delete Row"]: deleteRowHandler,
|
["Delete Row"]: deleteRowHandler,
|
||||||
["Navigate To"]: navigationHandler,
|
["Navigate To"]: navigationHandler,
|
||||||
["Scroll To Field"]: scrollHandler,
|
|
||||||
["Execute Query"]: queryExecutionHandler,
|
["Execute Query"]: queryExecutionHandler,
|
||||||
["Trigger Automation"]: triggerAutomationHandler,
|
["Trigger Automation"]: triggerAutomationHandler,
|
||||||
["Validate Form"]: validateFormHandler,
|
|
||||||
["Update Field Value"]: updateFieldValueHandler,
|
|
||||||
["Refresh Data Provider"]: refreshDataProviderHandler,
|
|
||||||
["Log Out"]: logoutHandler,
|
["Log Out"]: logoutHandler,
|
||||||
["Clear Form"]: clearFormHandler,
|
|
||||||
["Close Screen Modal"]: closeScreenModalHandler,
|
["Close Screen Modal"]: closeScreenModalHandler,
|
||||||
["Change Form Step"]: changeFormStepHandler,
|
|
||||||
["Update State"]: updateStateHandler,
|
["Update State"]: updateStateHandler,
|
||||||
["Upload File to S3"]: s3UploadHandler,
|
["Upload File to S3"]: s3UploadHandler,
|
||||||
["Export Data"]: exportDataHandler,
|
["Export Data"]: exportDataHandler,
|
||||||
|
@ -460,7 +433,12 @@ export const enrichButtonActions = (actions, context) => {
|
||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]])
|
// Get handlers for each action. If no bespoke handler is configured, fall
|
||||||
|
// back to simply executing this action from context.
|
||||||
|
const handlers = actions.map(def => {
|
||||||
|
return handlerMap[def["##eventHandlerType"]] || contextActionHandler
|
||||||
|
})
|
||||||
|
|
||||||
return async eventContext => {
|
return async eventContext => {
|
||||||
// Button context is built up as actions are executed.
|
// Button context is built up as actions are executed.
|
||||||
// Inherit any previous button context which may have come from actions
|
// Inherit any previous button context which may have come from actions
|
||||||
|
|
Loading…
Reference in New Issue