Fix dependency loop in client stores

This commit is contained in:
Andrew Kingston 2021-08-20 09:27:38 +01:00
parent 8a8e13119e
commit 08171c1e68
5 changed files with 103 additions and 44 deletions

View File

@ -74,7 +74,6 @@
styles: { ...instance._styles, id, empty, interactive }, styles: { ...instance._styles, id, empty, interactive },
empty, empty,
selected, selected,
props: componentSettings,
name, name,
}) })

View File

@ -1,5 +1,6 @@
import { writable, derived } from "svelte/store" import { writable, derived } from "svelte/store"
import Manifest from "@budibase/standard-components/manifest.json" import Manifest from "@budibase/standard-components/manifest.json"
import { findComponentById, findComponentPathById } from "../utils/components"
const dispatchEvent = (type, data = {}) => { const dispatchEvent = (type, data = {}) => {
window.dispatchEvent( window.dispatchEvent(
@ -9,45 +10,6 @@ const dispatchEvent = (type, data = {}) => {
) )
} }
const findComponentById = (component, componentId) => {
if (!component || !componentId) {
return null
}
if (component._id === componentId) {
return component
}
if (!component._children?.length) {
return null
}
for (let child of component._children) {
const result = findComponentById(child, componentId)
if (result) {
return result
}
}
return null
}
const findComponentIdPath = (component, componentId, path = []) => {
if (!component || !componentId) {
return null
}
path = [...path, component._id]
if (component._id === componentId) {
return path
}
if (!component._children?.length) {
return null
}
for (let child of component._children) {
const result = findComponentIdPath(child, componentId, path)
if (result) {
return result
}
}
return null
}
const createBuilderStore = () => { const createBuilderStore = () => {
const initialState = { const initialState = {
inBuilder: false, inBuilder: false,
@ -75,13 +37,13 @@ const createBuilderStore = () => {
const definition = type ? Manifest[type] : null const definition = type ? Manifest[type] : null
// Derive the selected component path // Derive the selected component path
const path = findComponentIdPath(asset.props, selectedComponentId) || [] const path = findComponentPathById(asset.props, selectedComponentId) || []
return { return {
...$state, ...$state,
selectedComponent: component, selectedComponent: component,
selectedComponentDefinition: definition, selectedComponentDefinition: definition,
selectedComponentPath: path, selectedComponentPath: path?.map(component => component._id),
} }
}) })

View File

@ -1,7 +1,12 @@
import { derived } from "svelte/store" import { derived, get } from "svelte/store"
import { routeStore } from "./routes" import { routeStore } from "./routes"
import { builderStore } from "./builder" import { builderStore } from "./builder"
import { appStore } from "./app" import { appStore } from "./app"
import {
findComponentPathById,
findChildrenByType,
findComponentById,
} from "../utils/components"
const createScreenStore = () => { const createScreenStore = () => {
const store = derived( const store = derived(
@ -36,8 +41,39 @@ const createScreenStore = () => {
} }
) )
// Utils to parse component definitions
const actions = {
findComponentById: componentId => {
const { activeScreen, activeLayout } = get(store)
let result = findComponentById(activeScreen?.props, componentId)
if (result) {
return result
}
return findComponentById(activeLayout?.props)
},
findComponentPathById: componentId => {
const { activeScreen, activeLayout } = get(store)
let result = findComponentPathById(activeScreen?.props, componentId)
if (result) {
return result
}
return findComponentPathById(activeLayout?.props)
},
findChildrenByType: (componentId, type) => {
const component = actions.findComponentById(componentId)
if (!component || !component._children) {
return null
}
let children = []
findChildrenByType(component, type, children)
console.log(children)
return children
},
}
return { return {
subscribe: store.subscribe, subscribe: store.subscribe,
actions,
} }
} }

View File

@ -0,0 +1,62 @@
/**
* Finds a component instance by ID
*/
export const findComponentById = (component, componentId) => {
if (!component || !componentId) {
return null
}
if (component._id === componentId) {
return component
}
if (!component._children?.length) {
return null
}
for (let child of component._children) {
const result = findComponentById(child, componentId)
if (result) {
return result
}
}
return null
}
/**
* Finds the component path to a component
*/
export const findComponentPathById = (component, componentId, path = []) => {
if (!component || !componentId) {
return null
}
path = [...path, component]
if (component._id === componentId) {
return path
}
if (!component._children?.length) {
return null
}
for (let child of component._children) {
const result = findComponentPathById(child, componentId, path)
if (result) {
return result
}
}
return null
}
/**
* Finds all children instances of a certain component type of a given component
*/
export const findChildrenByType = (component, type, children = []) => {
if (!component) {
return
}
if (component._component.endsWith(`/${type}`)) {
children.push(component)
}
if (!component._children?.length) {
return
}
component._children.forEach(child => {
findChildrenByType(child, type, children)
})
}

View File

@ -27,7 +27,7 @@
$: errors = deriveFieldProperty(fields, f => f.fieldState.error) $: errors = deriveFieldProperty(fields, f => f.fieldState.error)
$: valid = !Object.values($errors).some(error => error != null) $: valid = !Object.values($errors).some(error => error != null)
// Derive which fields belong in which steps // Derive whether the current form step is valid
$: currentStepValid = derived( $: currentStepValid = derived(
[currentStep, ...fields], [currentStep, ...fields],
([currentStepValue, ...fieldsValue]) => { ([currentStepValue, ...fieldsValue]) => {