diff --git a/packages/builder/src/builder/dataBinding.js b/packages/builder/src/builder/dataBinding.js
index ca0c51af98..1f33b64b8c 100644
--- a/packages/builder/src/builder/dataBinding.js
+++ b/packages/builder/src/builder/dataBinding.js
@@ -11,6 +11,7 @@ import {
componentStore,
screenStore,
appStore,
+ layoutStore,
} from "stores/frontend"
import {
queries as queriesStores,
@@ -1048,7 +1049,7 @@ export const getAllStateVariables = () => {
export const getAllAssets = () => {
// Get all component containing assets
let allAssets = []
- allAssets = allAssets.concat(get(appStore).layouts || [])
+ allAssets = allAssets.concat(get(layoutStore).layouts || [])
allAssets = allAssets.concat(get(screenStore).screens || [])
return allAssets
diff --git a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte
index 324418511b..f3cddf3e09 100644
--- a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte
+++ b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonConfiguration.svelte
@@ -2,8 +2,8 @@
import DraggableList from "../DraggableList/DraggableList.svelte"
import ButtonSetting from "./ButtonSetting.svelte"
import { createEventDispatcher } from "svelte"
- import { store } from "builderStore"
import { Helpers } from "@budibase/bbui"
+ import { componentStore } from "stores/frontend"
export let componentBindings
export let bindings
@@ -47,7 +47,7 @@
}
const buildPseudoInstance = cfg => {
- return store.actions.components.createInstance(
+ return componentStore.createInstance(
`@budibase/standard-components/button`,
{
_instanceName: Helpers.uuid(),
diff --git a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte
index a05fd9a39b..c8dd0558f6 100644
--- a/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte
+++ b/packages/builder/src/components/design/settings/controls/ButtonConfiguration/ButtonSetting.svelte
@@ -1,7 +1,7 @@
diff --git a/packages/builder/src/components/portal/onboarding/tourHandler.js b/packages/builder/src/components/portal/onboarding/tourHandler.js
index 80abf3bc01..cbb967164e 100644
--- a/packages/builder/src/components/portal/onboarding/tourHandler.js
+++ b/packages/builder/src/components/portal/onboarding/tourHandler.js
@@ -11,16 +11,7 @@ const registerNode = async (node, tourStepKey) => {
return
}
- builderStore.update(state => {
- const update = {
- ...state,
- tourNodes: {
- ...state.tourNodes,
- [tourStepKey]: node,
- },
- }
- return update
- })
+ builderStore.registerTourNode(tourStepKey, node)
}
export function tourHandler(node, tourStepKey) {
@@ -29,19 +20,7 @@ export function tourHandler(node, tourStepKey) {
}
return {
destroy: () => {
- const updatedTourNodes = get(builderStore).tourNodes
- if (updatedTourNodes && updatedTourNodes[tourStepKey]) {
- delete updatedTourNodes[tourStepKey]
- builderStore.update(state => {
- const update = {
- ...state,
- tourNodes: {
- ...updatedTourNodes,
- },
- }
- return update
- })
- }
+ builderStore.destroyTourNode(tourStepKey)
},
}
}
diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
index 3bd608b5a0..57af165c2b 100644
--- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
@@ -91,20 +91,13 @@
// Check if onboarding is enabled.
if (isEnabled(TENANT_FEATURE_FLAGS.ONBOARDING_TOUR)) {
if (!$auth.user?.onboardedAt) {
- await builderStore.update(state => ({
- ...state,
- onboarding: true,
- tourKey: TOUR_KEYS.TOUR_BUILDER_ONBOARDING,
- }))
+ builderStore.startBuilderOnboarding()
} else {
// Feature tour date
const release_date = new Date("2023-03-01T00:00:00.000Z")
const onboarded = new Date($auth.user?.onboardedAt)
if (onboarded < release_date) {
- await builderStore.update(state => ({
- ...state,
- tourKey: TOUR_KEYS.FEATURE_ONBOARDING,
- }))
+ builderStore.startTour(TOUR_KEYS.FEATURE_ONBOARDING)
}
}
}
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte
index bbc038dffc..f76d924123 100644
--- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte
@@ -20,7 +20,7 @@
const onUpdateName = async value => {
try {
- await store.actions.components.updateSetting("_instanceName", value)
+ await componentStore.updateSetting("_instanceName", value)
} catch (error) {
notifications.error("Error updating component name")
}
diff --git a/packages/builder/src/stores/frontend/builder.js b/packages/builder/src/stores/frontend/builder.js
index 68a0a714a1..16e3d0370b 100644
--- a/packages/builder/src/stores/frontend/builder.js
+++ b/packages/builder/src/stores/frontend/builder.js
@@ -2,6 +2,7 @@ import { writable } from "svelte/store"
import { createBuilderWebsocket } from "./websocket.js"
import { BuilderSocketEvent } from "@budibase/shared-core"
import BudiStore from "./BudiStore"
+import { TOUR_KEYS } from "components/portal/onboarding/tours.js"
export const INITIAL_BUILDER_STATE = {
previousTopNavPath: {},
@@ -69,11 +70,13 @@ export class BuilderStore extends BudiStore {
}
setPreviousTopNavPath(route, url) {
- this.update(state => {
- if (!state.previousTopNavPath) state.previousTopNavPath = {}
- state.previousTopNavPath[route] = url
- return state
- })
+ this.update(state => ({
+ ...state,
+ previousTopNavPath: {
+ ...(state.previousTopNavPath || {}),
+ [route]: url,
+ },
+ }))
}
selectResource(id) {
@@ -82,9 +85,8 @@ export class BuilderStore extends BudiStore {
})
}
- /*
- register
- update(state => {
+ registerTourNode(tourStepKey, node) {
+ this.update(state => {
const update = {
...state,
tourNodes: {
@@ -94,7 +96,34 @@ export class BuilderStore extends BudiStore {
}
return update
})
- */
+ }
+
+ destroyTourNode(tourStepKey) {
+ if (this.tourNodes[tourStepKey]) {
+ this.update(state => ({
+ ...state,
+ tourNodes: {
+ [tourStepKey]: _,
+ ...this.tourNodes,
+ },
+ }))
+ }
+ }
+
+ startBuilderOnboarding() {
+ this.update(state => ({
+ ...state,
+ onboarding: true,
+ tourKey: TOUR_KEYS.TOUR_BUILDER_ONBOARDING,
+ }))
+ }
+
+ startTour(tourKey) {
+ this.update(state => ({
+ ...state,
+ tourKey: tourKey,
+ }))
+ }
}
export const builderStore = new BuilderStore()
diff --git a/packages/builder/src/stores/frontend/components/index.js b/packages/builder/src/stores/frontend/components/index.js
index 72a774fd60..d58a1dc6b7 100644
--- a/packages/builder/src/stores/frontend/components/index.js
+++ b/packages/builder/src/stores/frontend/components/index.js
@@ -1,4 +1,4 @@
-import { writable, get, derived } from "svelte/store"
+import { get, derived } from "svelte/store"
import { cloneDeep } from "lodash/fp"
import { API } from "api"
import { Helpers } from "@budibase/bbui"
@@ -23,26 +23,93 @@ import {
DB_TYPE_INTERNAL,
DB_TYPE_EXTERNAL,
} from "constants/backend"
+import BudiStore from "../BudiStore"
-const INITIAL_COMPONENTS_STATE = {
+export const INITIAL_COMPONENTS_STATE = {
components: [],
customComponents: [],
selectedComponentId: null,
componentToPaste: null,
}
-export const createComponentStore = () => {
- const store = writable({
- ...INITIAL_COMPONENTS_STATE,
- })
+export class ComponentStore extends BudiStore {
+ constructor() {
+ super(INITIAL_COMPONENTS_STATE)
- const reset = () => {
- store.set({ ...INITIAL_COMPONENTS_STATE })
+ this.reset = this.reset.bind(this)
+ this.refreshDefinitions = this.refreshDefinitions.bind(this)
+ this.getDefinition = this.getDefinition.bind(this)
+ this.getDefaultDatasource = this.getDefaultDatasource.bind(this)
+ this.enrichEmptySettings = this.enrichEmptySettings.bind(this)
+ this.createInstance = this.createInstance.bind(this)
+ this.create = this.create.bind(this)
+ this.patch = this.patch.bind(this)
+ this.delete = this.delete.bind(this)
+ this.copy = this.copy.bind(this)
+ this.paste = this.paste.bind(this)
+ this.select = this.select.bind(this)
+ this.getPrevious = this.getPrevious.bind(this)
+ this.getNext = this.getNext.bind(this)
+ this.selectPrevious = this.selectPrevious.bind(this)
+ this.selectNext = this.selectNext.bind(this)
+ this.moveUp = this.moveUp.bind(this)
+ this.moveDown = this.moveDown.bind(this)
+ this.updateStyle = this.updateStyle.bind(this)
+ this.updateStyles = this.updateStyles.bind(this)
+ this.updateCustomStyle = this.updateCustomStyle.bind(this)
+ this.updateConditions = this.updateConditions.bind(this)
+ this.requestEjectBlock = this.requestEjectBlock.bind(this)
+ this.handleEjectBlock = this.handleEjectBlock.bind(this)
+ this.updateSetting = this.updateSetting.bind(this)
+ this.updateComponentSetting = this.updateComponentSetting.bind(this)
+ this.addParent = this.addParent.bind(this)
+
+ this.selected = derived(
+ [this.store, selectedScreen],
+ ([$store, $selectedScreen]) => {
+ if (
+ $selectedScreen &&
+ $store.selectedComponentId?.startsWith(`${$selectedScreen._id}-`)
+ ) {
+ return $selectedScreen?.props
+ }
+ if (!$selectedScreen || !$store.selectedComponentId) {
+ return null
+ }
+ return findComponent($selectedScreen?.props, $store.selectedComponentId)
+ }
+ )
+
+ this.selectedComponentPath = derived(
+ [this.store, selectedScreen],
+ ([$store, $selectedScreen]) => {
+ return findComponentPath(
+ $selectedScreen?.props,
+ $store.selectedComponentId
+ ).map(component => component._id)
+ }
+ )
+
+ this.subscribe(state => {
+ console.log("debug ", state)
+ })
}
- const refreshDefinitions = async appId => {
+ /**
+ * Reset the component store to default values
+ */
+ reset() {
+ this.store.set({ ...INITIAL_COMPONENTS_STATE })
+ }
+
+ /**
+ *
+ * @param {string} appId
+ * @returns
+ */
+ async refreshDefinitions(appId) {
if (!appId) {
- appId = get(store).appId
+ appId = get(this.store).appId
}
// Fetch definitions and filter out custom component definitions so we
@@ -53,7 +120,7 @@ export const createComponentStore = () => {
)
// Update store
- store.update(state => ({
+ this.update(state => ({
...state,
components,
customComponents,
@@ -65,14 +132,25 @@ export const createComponentStore = () => {
return components
}
- const getDefinition = componentName => {
+ /**
+ *
+ * @param {string} componentName
+ * @example
+ * '@budibase/standard-components/container'
+ * @returns {object}
+ */
+ getDefinition(componentName) {
if (!componentName) {
return null
}
- return get(store).components[componentName]
+ return get(this.store).components[componentName]
}
- const getDefaultDatasource = () => {
+ /**
+ *
+ * @returns {object}
+ */
+ getDefaultDatasource() {
// Ignore users table
const validTables = get(tables).list.filter(x => x._id !== "ta_users")
@@ -102,11 +180,17 @@ export const createComponentStore = () => {
return validTables.find(table => table.type === DB_TYPE_EXTERNAL)
}
- const enrichEmptySettings = (component, opts) => {
+ /**
+ *
+ * @param {object} component
+ * @param {object} opts
+ * @returns
+ */
+ enrichEmptySettings(component, opts) {
if (!component?._component) {
return
}
- const defaultDS = getDefaultDatasource()
+ const defaultDS = this.getDefaultDatasource()
const settings = getComponentSettings(component._component)
const { parent, screen, useDefaultValues } = opts || {}
const treeId = parent?._id || component._id
@@ -198,8 +282,15 @@ export const createComponentStore = () => {
})
}
- const createInstance = (componentName, presetProps, parent) => {
- const definition = getDefinition(componentName)
+ /**
+ *
+ * @param {string} componentName
+ * @param {object} presetProps
+ * @param {object} parent
+ * @returns
+ */
+ createInstance(componentName, presetProps, parent) {
+ const definition = this.getDefinition(componentName)
if (!definition) {
return null
}
@@ -218,7 +309,7 @@ export const createComponentStore = () => {
}
// Enrich empty settings
- enrichEmptySettings(instance, {
+ this.enrichEmptySettings(instance, {
parent,
screen: get(selectedScreen),
useDefaultValues: true,
@@ -247,9 +338,21 @@ export const createComponentStore = () => {
}
}
- const create = async (componentName, presetProps, parent, index) => {
- const state = get(store)
- const componentInstance = createInstance(componentName, presetProps, parent)
+ /**
+ *
+ * @param {string} componentName
+ * @param {object} presetProps
+ * @param {object} parent
+ * @param {number} index
+ * @returns
+ */
+ async create(componentName, presetProps, parent, index) {
+ const state = get(this.store)
+ const componentInstance = this.createInstance(
+ componentName,
+ presetProps,
+ parent
+ )
if (!componentInstance) {
return
}
@@ -286,7 +389,7 @@ export const createComponentStore = () => {
let parentComponent
if (currentComponent) {
// Use selected component as parent if one is selected
- const definition = getDefinition(currentComponent._component)
+ const definition = this.getDefinition(currentComponent._component)
if (definition?.hasChildren) {
// Use selected component if it allows children
parentComponent = currentComponent
@@ -314,7 +417,7 @@ export const createComponentStore = () => {
}
// Select new component
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = componentInstance._id
return state
})
@@ -327,10 +430,17 @@ export const createComponentStore = () => {
return componentInstance
}
- const patch = async (patchFn, componentId, screenId) => {
+ /**
+ *
+ * @param {function} patchFn
+ * @param {string} componentId
+ * @param {string} screenId
+ * @returns
+ */
+ async patch(patchFn, componentId, screenId) {
// Use selected component by default
if (!componentId || !screenId) {
- const state = get(store)
+ const state = get(this.store)
componentId = componentId || state.selectedComponentId
const screenState = get(screenStore)
@@ -350,18 +460,23 @@ export const createComponentStore = () => {
await screenStore.patch(patchScreen, screenId)
}
- const deleteComponent = async component => {
+ /**
+ *
+ * @param {object} component
+ * @returns
+ */
+ async delete(component) {
if (!component) {
return
}
// Determine the next component to select after deletion
- const state = get(store)
+ const state = get(this.store)
let nextSelectedComponentId
if (state.selectedComponentId === component._id) {
- nextSelectedComponentId = getNext()
+ nextSelectedComponentId = this.getNext()
if (!nextSelectedComponentId) {
- nextSelectedComponentId = getPrevious()
+ nextSelectedComponentId = this.getPrevious()
}
}
@@ -385,16 +500,16 @@ export const createComponentStore = () => {
// Update selected component if required
if (nextSelectedComponentId) {
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = nextSelectedComponentId
return state
})
}
}
- const copy = (component, cut = false, selectParent = true) => {
+ copy(component, cut = false, selectParent = true) {
// Update store with copied component
- store.update(state => {
+ this.update(state => {
state.componentToPaste = cloneDeep(component)
state.componentToPaste.isCut = cut
return state
@@ -405,7 +520,7 @@ export const createComponentStore = () => {
const screen = get(selectedScreen)
const parent = findComponentParent(screen?.props, component._id)
if (parent) {
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = parent._id
return state
})
@@ -413,15 +528,26 @@ export const createComponentStore = () => {
}
}
- const select = componentId => {
- store.update(state => {
+ /**
+ *
+ * @param {string} componentId
+ */
+ select(componentId) {
+ this.update(state => {
state.selectedComponentId = componentId
return state
})
}
- const paste = async (targetComponent, mode, targetScreen) => {
- const state = get(store)
+ /**
+ *
+ * @param {object} targetComponent
+ * @param {string} mode
+ * @param {object} targetScreen
+ * @returns
+ */
+ async paste(targetComponent, mode, targetScreen) {
+ const state = get(this.store)
if (!state.componentToPaste) {
return
}
@@ -430,7 +556,7 @@ export const createComponentStore = () => {
// Remove copied component if cutting, regardless if pasting works
let componentToPaste = cloneDeep(state.componentToPaste)
if (componentToPaste.isCut) {
- store.update(state => {
+ this.update(state => {
delete state.componentToPaste
return state
})
@@ -465,7 +591,7 @@ export const createComponentStore = () => {
// Check inside is valid
if (mode === "inside") {
- const definition = getDefinition(targetComponent._component)
+ const definition = this.getDefinition(targetComponent._component)
if (!definition.hasChildren) {
mode = "below"
}
@@ -495,15 +621,15 @@ export const createComponentStore = () => {
await screenStore.patch(patch, targetScreenId)
// Select the new component
- store.update(state => {
+ this.update(state => {
state.selectedScreenId = targetScreenId
state.selectedComponentId = newComponentId
return state
})
}
- const getPrevious = () => {
- const state = get(store)
+ getPrevious() {
+ const state = get(this.store)
const componentId = state.selectedComponentId
const screen = get(selectedScreen)
const parent = findComponentParent(screen.props, componentId)
@@ -542,8 +668,8 @@ export const createComponentStore = () => {
return parent._id
}
- const getNext = () => {
- const state = get(store)
+ getNext() {
+ const state = get(this.store)
const component = get(selectedComponent)
const componentId = component?._id
const screen = get(selectedScreen)
@@ -593,27 +719,27 @@ export const createComponentStore = () => {
}
}
- const selectPrevious = () => {
- const previousId = getPrevious()
+ selectPrevious() {
+ const previousId = this.getPrevious()
if (previousId) {
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = previousId
return state
})
}
}
- const selectNext = () => {
- const nextId = getNext()
+ selectNext() {
+ const nextId = this.getNext()
if (nextId) {
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = nextId
return state
})
}
}
- const moveUp = async component => {
+ async moveUp(component) {
await screenStore.patch(screen => {
const componentId = component?._id
const parent = findComponentParent(screen.props, componentId)
@@ -635,7 +761,7 @@ export const createComponentStore = () => {
// If sibling before us accepts children, move to last child of
// sibling
const previousSibling = parent._children[index - 1]
- const definition = getDefinition(previousSibling._component)
+ const definition = this.getDefinition(previousSibling._component)
if (definition.hasChildren) {
previousSibling._children.push(originalComponent)
}
@@ -658,7 +784,7 @@ export const createComponentStore = () => {
})
}
- const moveDown = async component => {
+ async moveDown(component) {
await screenStore.patch(screen => {
const componentId = component?._id
const parent = findComponentParent(screen.props, componentId)
@@ -687,7 +813,7 @@ export const createComponentStore = () => {
if (index < parent._children.length) {
// If the next sibling has children, become the first child
const nextSibling = parent._children[index]
- const definition = getDefinition(nextSibling._component)
+ const definition = this.getDefinition(nextSibling._component)
if (definition.hasChildren) {
nextSibling._children.splice(0, 0, originalComponent)
}
@@ -709,8 +835,8 @@ export const createComponentStore = () => {
})
}
- const updateStyle = async (name, value) => {
- await patch(component => {
+ async updateStyle(name, value) {
+ await this.patch(component => {
if (value == null || value === "") {
delete component._styles.normal[name]
} else {
@@ -719,33 +845,33 @@ export const createComponentStore = () => {
})
}
- const updateStyles = async (styles, id) => {
+ async updateStyles(styles, id) {
const patchFn = component => {
component._styles.normal = {
...component._styles.normal,
...styles,
}
}
- await patch(patchFn, id)
+ await this.patch(patchFn, id)
}
- const updateCustomStyle = async style => {
- await patch(component => {
+ async updateCustomStyle(style) {
+ await this.patch(component => {
component._styles.custom = style
})
}
- const updateConditions = async conditions => {
- await patch(component => {
+ async updateConditions(conditions) {
+ await this.patch(component => {
component._conditions = conditions
})
}
- const updateSetting = async (name, value) => {
- await patch(updateComponentSetting(name, value))
+ async updateSetting(name, value) {
+ await this.patch(this.updateComponentSetting(name, value))
}
- const updateComponentSetting = (name, value) => {
+ updateComponentSetting(name, value) {
return component => {
if (!name || !component) {
return false
@@ -783,11 +909,11 @@ export const createComponentStore = () => {
}
}
- const requestEjectBlock = componentId => {
+ requestEjectBlock(componentId) {
previewStore.sendEvent("eject-block", componentId)
}
- const handleEjectBlock = async (componentId, ejectedDefinition) => {
+ async handleEjectBlock(componentId, ejectedDefinition) {
let nextSelectedComponentId
await screenStore.patch(screen => {
@@ -827,20 +953,20 @@ export const createComponentStore = () => {
// Select new root component
if (nextSelectedComponentId) {
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = nextSelectedComponentId
return state
})
}
}
- const addParent = async (componentId, parentType) => {
+ async addParent(componentId, parentType) {
if (!componentId || !parentType) {
return
}
// Create new parent instance
- const newParentDefinition = createInstance(parentType, null, parent)
+ const newParentDefinition = this.createInstance(parentType, null, parent)
if (!newParentDefinition) {
return
}
@@ -868,71 +994,15 @@ export const createComponentStore = () => {
})
// Select the new parent
- store.update(state => {
+ this.update(state => {
state.selectedComponentId = newParentDefinition._id
return state
})
}
- return {
- subscribe: store.subscribe,
- reset,
- update: store.update,
- refreshDefinitions,
- getDefinition,
- getDefaultDatasource,
- enrichEmptySettings,
- createInstance,
- create,
- patch,
- delete: deleteComponent,
- copy,
- paste,
- select,
- getPrevious,
- getNext,
- selectPrevious,
- selectNext,
- moveUp,
- moveDown,
- updateStyle,
- updateStyles,
- updateCustomStyle,
- updateConditions,
- requestEjectBlock,
- handleEjectBlock,
- updateSetting,
- updateComponentSetting,
- addParent,
- }
}
-export const componentStore = createComponentStore()
+export const componentStore = new ComponentStore()
-export const selectedComponent = derived(
- [componentStore, selectedScreen],
- ([$componentStore, $selectedScreen]) => {
- if (
- $selectedScreen &&
- $componentStore.selectedComponentId?.startsWith(`${$selectedScreen._id}-`)
- ) {
- return $selectedScreen?.props
- }
- if (!$selectedScreen || !$componentStore.selectedComponentId) {
- return null
- }
- return findComponent(
- $selectedScreen?.props,
- $componentStore.selectedComponentId
- )
- }
-)
+export const selectedComponent = componentStore.selected
-export const selectedComponentPath = derived(
- [componentStore, selectedScreen],
- ([$componentStore, $selectedScreen]) => {
- return findComponentPath(
- $selectedScreen?.props,
- $componentStore.selectedComponentId
- ).map(component => component._id)
- }
-)
+export const selectedComponentPath = componentStore.selectedComponentPath
diff --git a/packages/builder/src/stores/frontend/index.js b/packages/builder/src/stores/frontend/index.js
index a0d02270b8..e161ddb6e5 100644
--- a/packages/builder/src/stores/frontend/index.js
+++ b/packages/builder/src/stores/frontend/index.js
@@ -1,3 +1,4 @@
+import { layoutStore } from "./layouts.js"
import { appStore } from "./app.js"
import {
componentStore,
@@ -14,7 +15,6 @@ import {
} from "./screens.js"
import { builderStore, screensHeight } from "./builder.js"
import { previewStore } from "./preview.js"
-import { layoutStore } from "./layouts.js"
import {
automationStore,
selectedAutomation,
@@ -25,6 +25,7 @@ import { deploymentStore } from "./deployments.js"
import { database } from "./database.js"
export {
+ layoutStore,
database,
appStore,
componentStore,
@@ -40,7 +41,6 @@ export {
automationHistoryStore,
currentAsset,
sortedScreens,
- layoutStore,
userStore,
isOnlyUser,
screensHeight,
diff --git a/packages/builder/src/stores/frontend/layouts.js b/packages/builder/src/stores/frontend/layouts.js
index fc2e11d1a4..51fbb99588 100644
--- a/packages/builder/src/stores/frontend/layouts.js
+++ b/packages/builder/src/stores/frontend/layouts.js
@@ -1,32 +1,43 @@
-import { writable, derived, get } from "svelte/store"
+import { derived, get } from "svelte/store"
import { componentStore } from "stores/frontend"
+import BudiStore from "./BudiStore"
import { API } from "api"
-// Review the purpose of these
-const INITIAL_LAYOUT_STATE = {
+export const INITIAL_LAYOUT_STATE = {
layouts: [],
selectedLayoutId: null,
}
-export const createLayoutStore = () => {
- const store = writable({
- ...INITIAL_LAYOUT_STATE,
- })
+export class LayoutStore extends BudiStore {
+ constructor() {
+ super(INITIAL_LAYOUT_STATE)
- const reset = () => {
- store.set({ ...INITIAL_LAYOUT_STATE })
+ this.reset = this.reset.bind(this)
+ this.syncAppLayouts = this.syncAppLayouts.bind(this)
+ this.select = this.select.bind(this)
+ this.deleteLayout = this.deleteLayout.bind(this)
+
+ this.selectedLayout = derived(this.store, $store => {
+ return $store.layouts?.find(
+ layout => layout._id === $store.selectedLayoutId
+ )
+ })
}
- const syncAppLayouts = pkg => {
- store.update(state => ({
+ reset() {
+ this.store.set({ ...INITIAL_LAYOUT_STATE })
+ }
+
+ syncAppLayouts(pkg) {
+ this.update(state => ({
...state,
layouts: [...pkg.layouts],
}))
}
- const select = layoutId => {
+ select(layoutId) {
// Check this layout exists
- const state = get(store)
+ const state = get(this.store)
const componentState = get(componentStore)
const layout = state.layouts.find(layout => layout._id === layoutId)
if (!layout) {
@@ -42,7 +53,7 @@ export const createLayoutStore = () => {
}
// Select new layout
- store.update(state => {
+ this.update(state => {
state.selectedLayoutId = layout._id
return state
})
@@ -50,7 +61,7 @@ export const createLayoutStore = () => {
componentStore.select(layout.props?._id)
}
- const deleteLayout = async layout => {
+ async deleteLayout(layout) {
if (!layout?._id) {
return
}
@@ -58,25 +69,13 @@ export const createLayoutStore = () => {
layoutId: layout._id,
layoutRev: layout._rev,
})
- store.update(state => {
+ this.update(state => {
state.layouts = state.layouts.filter(x => x._id !== layout._id)
return state
})
}
-
- return {
- subscribe: store.subscribe,
- syncAppLayouts,
- select,
- delete: deleteLayout,
- reset,
- }
}
-export const layoutStore = createLayoutStore()
+export const layoutStore = new LayoutStore()
-export const selectedLayout = derived(layoutStore, $layoutStore => {
- return $layoutStore.layouts?.find(
- layout => layout._id === $layoutStore.selectedLayoutId
- )
-})
+export const selectedLayout = layoutStore.selectedLayout
diff --git a/packages/builder/src/stores/frontend/screens.js b/packages/builder/src/stores/frontend/screens.js
index 2acff8b521..ae29238785 100644
--- a/packages/builder/src/stores/frontend/screens.js
+++ b/packages/builder/src/stores/frontend/screens.js
@@ -4,6 +4,7 @@ import { Helpers } from "@budibase/bbui"
import { RoleUtils, Utils } from "@budibase/frontend-core"
import { findAllMatchingComponents } from "stores/frontend/components/utils"
import {
+ layoutStore,
appStore,
componentStore,
navigationStore,
@@ -36,7 +37,7 @@ export class ScreenStore extends BudiStore {
this.syncScreenData = this.syncScreenData.bind(this)
this.updateSetting = this.updateSetting.bind(this)
this.sequentialScreenPatch = this.sequentialScreenPatch.bind(this)
- // this.removeCustomLayout = this.removeCustomLayout(this)
+ this.removeCustomLayout = this.removeCustomLayout(this)
this.selected = derived(this.store, $store => {
return get(this.store).screens.find(
@@ -452,16 +453,16 @@ export class ScreenStore extends BudiStore {
}
// Move to layouts store
- // async removeCustomLayout(screen) {
- // // Pull relevant settings from old layout, if required
- // const layout = get(this.store).layouts.find(x => x._id === screen.layoutId)
- // const patchFn = screen => {
- // screen.layoutId = null
- // screen.showNavigation = layout?.props.navigation !== "None"
- // screen.width = layout?.props.width || "Large"
- // }
- // await this.patch(patchFn, screen._id)
- // }
+ async removeCustomLayout(screen) {
+ // Pull relevant settings from old layout, if required
+ const layout = get(layoutStore).layouts.find(x => x._id === screen.layoutId)
+ const patchFn = screen => {
+ screen.layoutId = null
+ screen.showNavigation = layout?.props.navigation !== "None"
+ screen.width = layout?.props.width || "Large"
+ }
+ await this.patch(patchFn, screen._id)
+ }
/**
* Parse the entire screen component tree and ensure settings are valid
diff --git a/packages/builder/src/stores/frontend/tests/builder.test.js b/packages/builder/src/stores/frontend/tests/builder.test.js
index 68657ca2fe..6e0bc608e3 100644
--- a/packages/builder/src/stores/frontend/tests/builder.test.js
+++ b/packages/builder/src/stores/frontend/tests/builder.test.js
@@ -9,12 +9,13 @@ vi.mock("../websocket.js")
describe("Builder store", () => {
beforeEach(ctx => {
vi.clearAllMocks()
- const builderStorex = new BuilderStore()
+ const builderStore = new BuilderStore()
+ ctx.test = {}
ctx.test = {
get store() {
- return get(builderStorex)
+ return get(builderStore)
},
- builderStorex,
+ builderStore,
}
})
@@ -147,13 +148,13 @@ describe("Builder store", () => {
const designURL =
"/builder/app/app_dev_123/design/screen_456/screen_456-screen"
- ctx.test.builderStorex.setPreviousTopNavPath(dataRoute, dataURL)
+ ctx.test.builderStore.setPreviousTopNavPath(dataRoute, dataURL)
expect(ctx.test.store.previousTopNavPath).toStrictEqual({
[dataRoute]: dataURL,
})
- ctx.test.builderStorex.setPreviousTopNavPath(designRoute, designURL)
+ ctx.test.builderStore.setPreviousTopNavPath(designRoute, designURL)
expect(ctx.test.store.previousTopNavPath).toStrictEqual({
[dataRoute]: dataURL,
@@ -161,24 +162,47 @@ describe("Builder store", () => {
})
})
- it("Overrite an existing route/path mapping with a new URL", () => {
- // expect(ctx.test.store.previousTopNavPath).toStrictEqual({})
- // ctx.test.builderStore.refresh()
+ it("Overrite an existing route/path mapping with a new URL", ctx => {
+ expect(ctx.test.store.previousTopNavPath).toStrictEqual({})
console.log(INITIAL_BUILDER_STATE)
- // const dataRoute = "/builder/app/:application/data"
- // const dataURL = "/builder/app/app_dev_123/data/table/ta_users"
- // const updatedURL = "/builder/app/app_dev_123/data/table/ta_employees"
+ const dataRoute = "/builder/app/:application/data"
+ const dataURL = "/builder/app/app_dev_123/data/table/ta_users"
+ const updatedURL = "/builder/app/app_dev_123/data/table/ta_employees"
- // ctx.test.builderStore.setPreviousTopNavPath(dataRoute, dataURL)
+ ctx.test.builderStore.setPreviousTopNavPath(dataRoute, dataURL)
- // expect(ctx.test.store.previousTopNavPath).toStrictEqual({
- // [dataRoute]: dataURL,
- // })
+ expect(ctx.test.store.previousTopNavPath).toStrictEqual({
+ [dataRoute]: dataURL,
+ })
- // ctx.test.builderStore.setPreviousTopNavPath(dataRoute, updatedURL)
+ ctx.test.builderStore.setPreviousTopNavPath(dataRoute, updatedURL)
- // expect(ctx.test.store.previousTopNavPath).toStrictEqual({
- // [dataRoute]: updatedURL,
- // })
+ expect(ctx.test.store.previousTopNavPath).toStrictEqual({
+ [dataRoute]: updatedURL,
+ })
+ })
+
+ it("Register a builder tour node", ctx => {
+ const fakeNode = { name: "node" }
+ ctx.test.builderStore.registerTourNode("sampleKey", fakeNode)
+
+ const registeredNodes = ctx.test.store.tourNodes
+
+ expect(registeredNodes).not.toBeNull()
+ expect(Object.keys(registeredNodes).length).toBe(1)
+ expect(registeredNodes["sampleKey"]).toStrictEqual(fakeNode)
+ })
+
+ it("Clear a destroyed tour node", ctx => {
+ const fakeNode = { name: "node" }
+ ctx.test.builderStore.registerTourNode("sampleKey", fakeNode)
+
+ const registeredNodes = ctx.test.store.tourNodes
+
+ expect(registeredNodes).not.toBeNull()
+ expect(Object.keys(registeredNodes).length).toBe(1)
+
+ ctx.test.builderStore.destroyTourNode("sampleKey")
+ expect(registeredNodes).toBe({})
})
})