Update how available actions on the screen are found so that they understand global bindings properly and respect local scope

This commit is contained in:
Andrew Kingston 2024-08-08 15:17:55 +01:00
parent 691d6b04bb
commit 013f13315c
No known key found for this signature in database
3 changed files with 55 additions and 46 deletions

View File

@ -1,4 +1,4 @@
import { getComponentContexts } from "dataBinding" import { getAllComponentContexts } from "dataBinding"
import { capitalise } from "helpers" import { capitalise } from "helpers"
// Generates bindings for all components that provider "datasource like" // Generates bindings for all components that provider "datasource like"
@ -7,7 +7,7 @@ import { capitalise } from "helpers"
// Some examples are saving rows or duplicating rows. // Some examples are saving rows or duplicating rows.
export const getDatasourceLikeProviders = ({ asset, componentId, nested }) => { export const getDatasourceLikeProviders = ({ asset, componentId, nested }) => {
// Get all form context providers // Get all form context providers
const formComponentContexts = getComponentContexts( const formComponentContexts = getAllComponentContexts(
asset, asset,
componentId, componentId,
"form", "form",
@ -16,7 +16,7 @@ export const getDatasourceLikeProviders = ({ asset, componentId, nested }) => {
} }
) )
// Get all schema context providers // Get all schema context providers
const schemaComponentContexts = getComponentContexts( const schemaComponentContexts = getAllComponentContexts(
asset, asset,
componentId, componentId,
"schema", "schema",

View File

@ -6,6 +6,7 @@ import {
findAllMatchingComponents, findAllMatchingComponents,
findComponent, findComponent,
findComponentPath, findComponentPath,
getComponentContexts,
} from "helpers/components" } from "helpers/components"
import { import {
componentStore, componentStore,
@ -213,7 +214,7 @@ export const getComponentBindableProperties = (asset, componentId) => {
* both global and local bindings, taking into account a component's position * both global and local bindings, taking into account a component's position
* in the component tree. * in the component tree.
*/ */
export const getComponentContexts = ( export const getAllComponentContexts = (
asset, asset,
componentId, componentId,
type, type,
@ -229,11 +230,6 @@ export const getComponentContexts = (
// Processes all contexts exposed by a component // Processes all contexts exposed by a component
const processContexts = scope => component => { const processContexts = scope => component => {
const def = componentStore.getDefinition(component._component)
if (!def?.context) {
return
}
// Filter out global contexts not in the same branch. // Filter out global contexts not in the same branch.
// Global contexts are only valid if their branch root is an ancestor of // Global contexts are only valid if their branch root is an ancestor of
// this component. // this component.
@ -242,8 +238,8 @@ export const getComponentContexts = (
return return
} }
// Process all contexts provided by this component const componentType = component._component
const contexts = Array.isArray(def.context) ? def.context : [def.context] const contexts = getComponentContexts(componentType)
contexts.forEach(context => { contexts.forEach(context => {
// Ensure type matches // Ensure type matches
if (type && context.type !== type) { if (type && context.type !== type) {
@ -261,7 +257,7 @@ export const getComponentContexts = (
if (!map[component._id]) { if (!map[component._id]) {
map[component._id] = { map[component._id] = {
component, component,
definition: def, definition: componentStore.getDefinition(componentType),
contexts: [], contexts: [],
} }
} }
@ -286,7 +282,7 @@ export const getComponentContexts = (
} }
/** /**
* Gets all data provider components above a component. * Gets all components available to this component that expose a certain action
*/ */
export const getActionProviders = ( export const getActionProviders = (
asset, asset,
@ -294,36 +290,31 @@ export const getActionProviders = (
actionType, actionType,
options = { includeSelf: false } options = { includeSelf: false }
) => { ) => {
if (!asset) { const contexts = getAllComponentContexts(asset, componentId, "action", {
return [] includeSelf: options?.includeSelf,
}
// Get all components
const components = findAllComponents(asset.props)
// Find matching contexts and generate bindings
let providers = []
components.forEach(component => {
if (!options?.includeSelf && component._id === componentId) {
return
}
const def = componentStore.getDefinition(component._component)
const actions = (def?.actions || []).map(action => {
return typeof action === "string" ? { type: action } : action
}) })
const action = actions.find(x => x.type === actionType) return (
if (action) { contexts
// Find the definition of the action in question, if one is provided
.map(context => ({
...context,
action: context.contexts[0].actions.find(x => x.type === actionType),
}))
// Filter out contexts which don't have this action
.filter(({ action }) => action != null)
// Generate bindings for this component and action
.map(({ component, action }) => {
let runtimeBinding = component._id let runtimeBinding = component._id
if (action.suffix) { if (action.suffix) {
runtimeBinding += `-${action.suffix}` runtimeBinding += `-${action.suffix}`
} }
providers.push({ return {
readableBinding: component._instanceName, readableBinding: component._instanceName,
runtimeBinding, runtimeBinding,
})
} }
}) })
return providers )
} }
/** /**
@ -371,7 +362,7 @@ export const getDatasourceForProvider = (asset, component) => {
*/ */
const getContextBindings = (asset, componentId) => { const getContextBindings = (asset, componentId) => {
// Get all available contexts for this component // Get all available contexts for this component
const componentContexts = getComponentContexts(asset, componentId) const componentContexts = getAllComponentContexts(asset, componentId)
// Generate bindings for each context // Generate bindings for each context
return componentContexts return componentContexts

View File

@ -228,6 +228,25 @@ export const getComponentName = component => {
return componentDefinition.friendlyName || componentDefinition.name || "" return componentDefinition.friendlyName || componentDefinition.name || ""
} }
// Gets all contexts exposed by a certain component type, including actions
export const getComponentContexts = component => {
const def = componentStore.getDefinition(component)
let contexts = []
if (def?.context) {
contexts = Array.isArray(def.context) ? [...def.context] : [def.context]
}
if (def?.actions) {
contexts.push({
type: "action",
scope: ContextScopes.Global,
// Ensure all actions are their verbose object versions
actions: def.actions.map(x => (typeof x === "string" ? { type: x } : x)),
})
}
return contexts
}
/** /**
* Recurses through the component tree and builds a tree of contexts provided * Recurses through the component tree and builds a tree of contexts provided
* by components. * by components.
@ -243,10 +262,9 @@ export const buildContextTree = (
} }
// Process this component's contexts // Process this component's contexts
const def = componentStore.getDefinition(rootComponent._component) const contexts = getComponentContexts(rootComponent._component)
if (def?.context) { if (contexts.length) {
tree[currentBranch].push(rootComponent._id) tree[currentBranch].push(rootComponent._id)
const contexts = Array.isArray(def.context) ? def.context : [def.context]
// If we provide local context, start a new branch for our children // If we provide local context, start a new branch for our children
if (contexts.some(context => context.scope === ContextScopes.Local)) { if (contexts.some(context => context.scope === ContextScopes.Local)) {