This commit is contained in:
Adria Navarro 2025-02-17 17:21:23 +01:00
parent a2d36410d6
commit b931a24d5e
4 changed files with 63 additions and 35 deletions

View File

@ -8,28 +8,32 @@ import {
} from "@budibase/string-templates"
import { capitalise } from "@/helpers"
import { Constants } from "@budibase/frontend-core"
import { ScreenProps } from "@budibase/types"
import { Component, ComponentContext } from "@budibase/types"
const { ContextScopes } = Constants
/**
* Recursively searches for a specific component ID
*/
export const findComponent = (rootComponent: ScreenProps, id: string) => {
export const findComponent = (rootComponent: Component, id: string) => {
return searchComponentTree(rootComponent, comp => comp._id === id)
}
/**
* Recursively searches for a specific component type
*/
export const findComponentType = (rootComponent, type) => {
export const findComponentType = (rootComponent: Component, type: string) => {
return searchComponentTree(rootComponent, comp => comp._component === type)
}
/**
* Recursively searches for the parent component of a specific component ID
*/
export const findComponentParent = (rootComponent, id, parentComponent) => {
export const findComponentParent = (
rootComponent: Component,
id: string,
parentComponent: Component
): Component | null => {
if (!rootComponent || !id) {
return null
}
@ -52,7 +56,11 @@ export const findComponentParent = (rootComponent, id, parentComponent) => {
* Recursively searches for a specific component ID and records the component
* path to this component
*/
export const findComponentPath = (rootComponent, id, path = []) => {
export const findComponentPath = (
rootComponent: Component,
id: string,
path: Component[] = []
): Component[] => {
if (!rootComponent || !id) {
return []
}
@ -76,11 +84,14 @@ export const findComponentPath = (rootComponent, id, path = []) => {
* Recurses through the component tree and finds all components which match
* a certain selector
*/
export const findAllMatchingComponents = (rootComponent, selector) => {
export const findAllMatchingComponents = (
rootComponent: Component,
selector: (component: Component) => boolean
) => {
if (!rootComponent || !selector) {
return []
}
let components = []
let components: Component[] = []
if (rootComponent._children) {
rootComponent._children.forEach(child => {
components = [
@ -98,7 +109,7 @@ export const findAllMatchingComponents = (rootComponent, selector) => {
/**
* Recurses through the component tree and finds all components.
*/
export const findAllComponents = rootComponent => {
export const findAllComponents = (rootComponent: Component) => {
return findAllMatchingComponents(rootComponent, () => true)
}
@ -106,9 +117,9 @@ export const findAllComponents = rootComponent => {
* Finds the closest parent component which matches certain criteria
*/
export const findClosestMatchingComponent = (
rootComponent,
componentId,
selector
rootComponent: Component,
componentId: string,
selector: (component: Component) => boolean
) => {
if (!selector) {
return null
@ -126,7 +137,10 @@ export const findClosestMatchingComponent = (
* Recurses through a component tree evaluating a matching function against
* components until a match is found
*/
const searchComponentTree = (rootComponent, matchComponent) => {
const searchComponentTree = (
rootComponent: Component,
matchComponent: (component: Component) => boolean
): Component | null => {
if (!rootComponent || !matchComponent) {
return null
}
@ -151,15 +165,18 @@ const searchComponentTree = (rootComponent, matchComponent) => {
* This mutates the object in place.
* @param component the component to randomise
*/
export const makeComponentUnique = component => {
export const makeComponentUnique = (component: Component) => {
if (!component) {
return
}
// Generate a full set of component ID replacements in this tree
const idReplacements = []
const generateIdReplacements = (component, replacements) => {
const oldId = component._id
const idReplacements: [string, string][] = []
const generateIdReplacements = (
component: Component,
replacements: [string, string][]
) => {
const oldId = component._id!
const newId = Helpers.uuid()
replacements.push([oldId, newId])
component._children?.forEach(x => generateIdReplacements(x, replacements))
@ -183,9 +200,9 @@ export const makeComponentUnique = component => {
let js = decodeJSBinding(sanitizedBinding)
if (js != null) {
// Replace ID inside JS binding
idReplacements.forEach(([oldId, newId]) => {
for (const [oldId, newId] of idReplacements) {
js = js.replace(new RegExp(oldId, "g"), newId)
})
}
// Create new valid JS binding
let newBinding = encodeJSBinding(js)
@ -205,7 +222,7 @@ export const makeComponentUnique = component => {
return JSON.parse(definition)
}
export const getComponentText = component => {
export const getComponentText = (component: Component) => {
if (component == null) {
return ""
}
@ -219,7 +236,7 @@ export const getComponentText = component => {
return capitalise(type)
}
export const getComponentName = component => {
export const getComponentName = (component: Component) => {
if (component == null) {
return ""
}
@ -230,9 +247,9 @@ export const getComponentName = component => {
}
// Gets all contexts exposed by a certain component type, including actions
export const getComponentContexts = component => {
export const getComponentContexts = (component: string) => {
const def = componentStore.getDefinition(component)
let contexts = []
let contexts: ComponentContext[] = []
if (def?.context) {
contexts = Array.isArray(def.context) ? [...def.context] : [def.context]
}
@ -252,9 +269,9 @@ export const getComponentContexts = component => {
* Recurses through the component tree and builds a tree of contexts provided
* by components.
*/
export const buildContextTree = (
rootComponent,
tree = { root: [] },
const buildContextTree = (
rootComponent: Component,
tree: Record<string, string[]> = { root: [] },
currentBranch = "root"
) => {
// Sanity check
@ -265,12 +282,12 @@ export const buildContextTree = (
// Process this component's contexts
const contexts = getComponentContexts(rootComponent._component)
if (contexts.length) {
tree[currentBranch].push(rootComponent._id)
tree[currentBranch].push(rootComponent._id!)
// If we provide local context, start a new branch for our children
if (contexts.some(context => context.scope === ContextScopes.Local)) {
currentBranch = rootComponent._id
tree[rootComponent._id] = []
currentBranch = rootComponent._id!
tree[rootComponent._id!] = []
}
}
@ -300,9 +317,9 @@ export const buildContextTreeLookupMap = rootComponent => {
}
// Get a flat list of ids for all descendants of a component
export const getChildIdsForComponent = component => {
export const getChildIdsForComponent = (component: Component): string[] => {
return [
component._id,
component._id!,
...(component?._children ?? []).map(getChildIdsForComponent).flat(1),
]
}

View File

@ -112,10 +112,7 @@ export const EventPublishType = {
ENV_VAR_UPGRADE_PANEL_OPENED: "environment_variable_upgrade_panel_opened",
}
export const ContextScopes = {
Local: "local",
Global: "global",
}
export { ComponentContextScopes } from "@budibase/types"
export const TypeIconMap = {
[FieldType.STRING]: "Text",

View File

@ -28,6 +28,8 @@ export interface ComponentDefinition {
width: number
height: number
}
context?: ComponentContext | ComponentContext[]
actions?: (string | any)[]
}
export type DependsOnComponentSetting =
@ -56,3 +58,16 @@ export interface ComponentSetting {
self: boolean
}
}
export interface ComponentContext {
type: ComponentContextType
scope: ComponentContextScopes
actions: any[]
}
export type ComponentContextType = "action"
export const enum ComponentContextScopes {
Local = "local",
Global = "global",
}

View File

@ -1,2 +1 @@
export type PreviewDevice = "desktop" | "tablet" | "mobile"
export type ComponentContext = Record<string, any>