diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 9a93528c33..f4e0cf0f8b 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -1,12 +1,12 @@ -import { getStore } from "./store" -// import { getFrontendStore } from "./store/frontend" +// import { getStore } from "./store" +import { getFrontendStore } from "./store/frontend" import { getBackendUiStore } from "./store/backend" import { getAutomationStore } from "./store/automation/" import { getThemeStore } from "./store/theme" import analytics from "analytics" -export const store = getStore() -// export const store = getFrontendStore() +// export const store = getStore() +export const store = getFrontendStore() export const backendUiStore = getBackendUiStore() export const automationStore = getAutomationStore() export const themeStore = getThemeStore() diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 8f908ac568..ec41627f54 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -82,33 +82,31 @@ export const getFrontendStore = () => { screens: page._screens, }) } - pkg.justCreated = false - - const components = await fetchComponentLibDefinitions( - pkg.application._id - ) - - store.update(state => ({ - ...state, - libraries: pkg.application.componentLibraries, - components, - name: pkg.application.name, - description: pkg.application.description, - appId: pkg.application._id, - pages: pkg.pages, - hasAppPackage: true, - screens: [ - ...Object.values(mainScreens), - ...Object.values(unauthScreens), - ], - builtins: [getBuiltin("##builtin/screenslot")], - appInstance: pkg.application.instance, - })) - - await backendUiStore.actions.database.select(pkg.application.instance) } + + pkg.justCreated = false + + const components = await fetchComponentLibDefinitions(pkg.application._id) + + store.update(state => ({ + ...state, + libraries: pkg.application.componentLibraries, + components, + name: pkg.application.name, + description: pkg.application.description, + appId: pkg.application._id, + pages: pkg.pages, + hasAppPackage: true, + screens: [ + ...Object.values(mainScreens), + ...Object.values(unauthScreens), + ], + builtins: [getBuiltin("##builtin/screenslot")], + appInstance: pkg.application.instance, + })) + + await backendUiStore.actions.database.select(pkg.application.instance) }, - // store.setScreenType selectPageOrScreen: type => { store.update(state => { state.currentFrontEndType = type @@ -241,243 +239,250 @@ export const getFrontendStore = () => { ? store.actions.pages.save() : store.actions.screens.save(state.currentPreviewItem) }, - pages: { - select: pageName => { - store.update(state => { - const current_screens = state.pages[pageName]._screens + }, + pages: { + select: pageName => { + store.update(state => { + const current_screens = state.pages[pageName]._screens - const currentPage = state.pages[pageName] + const currentPage = state.pages[pageName] - state.currentFrontEndType = "page" - state.currentView = "detail" - state.currentPageName = pageName - state.screens = Array.isArray(current_screens) - ? current_screens - : Object.values(current_screens) - const safeProps = makePropsSafe( - state.components[currentPage.props._component], - currentPage.props - ) - state.currentComponentInfo = safeProps - currentPage.props = safeProps - state.currentPreviewItem = state.pages[pageName] - store.actions.screens.regenerateCssForCurrentScreen() + state.currentFrontEndType = "page" + state.currentView = "detail" + state.currentPageName = pageName + state.screens = Array.isArray(current_screens) + ? current_screens + : Object.values(current_screens) - for (let screen of state.screens) { - screen._css = generate_screen_css([screen.props]) - } + // This is the root of many problems. + // Uncaught (in promise) TypeError: Cannot read property '_component' of undefined + // it appears that the currentPage sometimes has _props instead of props + // why + const safeProps = makePropsSafe( + state.components[currentPage.props._component], + currentPage.props + ) + state.currentComponentInfo = safeProps + currentPage.props = safeProps + state.currentPreviewItem = state.pages[pageName] + store.actions.screens.regenerateCssForCurrentScreen() - return state - }) - }, - save: async page => { - const storeContents = get(store) - const pageName = storeContents.currentPageName || "main" - const pageToSave = page || storeContents.pages[pageName] - - // TODO: revisit. This sends down a very weird payload - const response = await api - .post(`/api/pages/${pageToSave._id}`, { - page: { - componentLibraries: storeContents.pages.componentLibraries, - ...pageToSave, - }, - screens: pageToSave._screens, - }) - .then(response => response.json()) - - store.update(state => { - state.pages[pageName]._rev = response.rev - return state - }) - }, - }, - components: { - select: component => { - store.update(state => { - const componentDef = component._component.startsWith("##") - ? component - : state.components[component._component] - state.currentComponentInfo = makePropsSafe(componentDef, component) - state.currentView = "component" - return state - }) - }, - // addChildComponent - create: (componentToAdd, presetProps) => { - store.update(state => { - function findSlot(component_array) { - for (let i = 0; i < component_array.length; i += 1) { - if (component_array[i]._component === "##builtin/screenslot") { - return true - } - - if (component_array[i]._children) findSlot(component_array[i]) - } - - return false - } - - if ( - componentToAdd.startsWith("##") && - findSlot(state.pages[state.currentPageName].props._children) - ) { - return state - } - - const component = getComponentDefinition(state, componentToAdd) - - const instanceId = get(backendUiStore).selectedDatabase._id - const instanceName = getNewComponentName(component, state) - - const newComponent = createProps( - component, - { - ...presetProps, - _instanceId: instanceId, - _instanceName: instanceName, - }, - state - ) - - const currentComponent = - state.components[state.currentComponentInfo._component] - - const targetParent = currentComponent.children - ? state.currentComponentInfo - : getParent( - state.currentPreviewItem.props, - state.currentComponentInfo - ) - - // Don't continue if there's no parent - if (!targetParent) { - return state - } - - targetParent._children = targetParent._children.concat( - newComponent.props - ) - - store.actions.preview.saveSelected() - - state.currentView = "component" - state.currentComponentInfo = newComponent.props - analytics.captureEvent("Added Component", { - name: newComponent.props._component, - }) - return state - }) - }, - copy: (component, cut = false) => { - store.update(state => { - const copiedComponent = cloneDeep(component) - state.componentToPaste = copiedComponent - state.componentToPaste.isCut = cut - if (cut) { - const parent = getParent( - state.currentPreviewItem.props, - component._id - ) - parent._children = parent._children.filter( - c => c._id !== component._id - ) - store.actions.components.select(parent) - } - - return state - }) - }, - paste: (targetComponent, mode) => { - store.update(state => { - if (!state.componentToPaste) return state - - const componentToPaste = cloneDeep(state.componentToPaste) - // retain the same ids as things may be referencing this component - if (componentToPaste.isCut) { - // in case we paste a second time - state.componentToPaste.isCut = false - } else { - generateNewIdsForComponent(componentToPaste, state) - } - delete componentToPaste.isCut - - if (mode === "inside") { - targetComponent._children.push(componentToPaste) - return state - } - - const parent = getParent( - state.currentPreviewItem.props, - targetComponent - ) - - const targetIndex = parent._children.indexOf(targetComponent) - const index = mode === "above" ? targetIndex : targetIndex + 1 - parent._children.splice(index, 0, cloneDeep(componentToPaste)) - - store.actions.screens.regenerateCssForCurrentScreen() - store.actions.preview.saveSelected() - store.actions.components.select(componentToPaste) - - return state - }) - }, - updateStyle: (type, name, value) => { - store.update(state => { - if (!state.currentComponentInfo._styles) { - state.currentComponentInfo._styles = {} - } - state.currentComponentInfo._styles[type][name] = value - - store.actions.screens.regenerateCssForCurrentScreen() - - // save without messing with the store - store.actions.preview.saveSelected() - return state - }) - }, - updateProp: (name, value) => { - store.update(state => { - let current_component = state.currentComponentInfo - current_component[name] = value - - state.currentComponentInfo = current_component - store.actions.preview.saveSelected() - return state - }) - }, - findRoute: component => { - // Gets all the components to needed to construct a path. - const tempStore = get(store) - let pathComponents = [] - let parent = component - let root = false - while (!root) { - parent = getParent(tempStore.currentPreviewItem.props, parent) - if (!parent) { - root = true - } else { - pathComponents.push(parent) - } + for (let screen of state.screens) { + screen._css = generate_screen_css([screen.props]) } - // Remove root entry since it's the screen or page layout. - // Reverse array since we need the correct order of the IDs - const reversedComponents = pathComponents.reverse().slice(1) + return state + }) + }, + save: async page => { + const storeContents = get(store) + const pageName = storeContents.currentPageName || "main" + const pageToSave = page || storeContents.pages[pageName] - // Add component - const allComponents = [...reversedComponents, component] + // TODO: revisit. This sends down a very weird payload + const response = await api + .post(`/api/pages/${pageToSave._id}`, { + page: { + componentLibraries: storeContents.pages.componentLibraries, + ...pageToSave, + }, + screens: pageToSave._screens, + }) + .then(response => response.json()) - // Map IDs - const IdList = allComponents.map(c => c._id) + store.update(state => { + state.pages[pageName]._rev = response.rev + return state + }) + }, + }, + components: { + select: component => { + store.update(state => { + const componentDef = component._component.startsWith("##") + ? component + : state.components[component._component] + state.currentComponentInfo = makePropsSafe(componentDef, component) + state.currentView = "component" + return state + }) + }, + // addChildComponent + create: (componentToAdd, presetProps) => { + store.update(state => { + function findSlot(component_array) { + for (let i = 0; i < component_array.length; i += 1) { + if (component_array[i]._component === "##builtin/screenslot") { + return true + } - // Construct ID Path: - const path = IdList.join("/") + if (component_array[i]._children) findSlot(component_array[i]) + } - return path - }, + return false + } + + if ( + componentToAdd.startsWith("##") && + findSlot(state.pages[state.currentPageName].props._children) + ) { + return state + } + + const component = getComponentDefinition(state, componentToAdd) + + const instanceId = get(backendUiStore).selectedDatabase._id + const instanceName = getNewComponentName(component, state) + + const newComponent = createProps( + component, + { + ...presetProps, + _instanceId: instanceId, + _instanceName: instanceName, + }, + state + ) + + const currentComponent = + state.components[state.currentComponentInfo._component] + + const targetParent = currentComponent.children + ? state.currentComponentInfo + : getParent( + state.currentPreviewItem.props, + state.currentComponentInfo + ) + + // Don't continue if there's no parent + if (!targetParent) { + return state + } + + targetParent._children = targetParent._children.concat( + newComponent.props + ) + + store.actions.preview.saveSelected() + + state.currentView = "component" + state.currentComponentInfo = newComponent.props + analytics.captureEvent("Added Component", { + name: newComponent.props._component, + }) + return state + }) + }, + copy: (component, cut = false) => { + store.update(state => { + const copiedComponent = cloneDeep(component) + state.componentToPaste = copiedComponent + state.componentToPaste.isCut = cut + if (cut) { + const parent = getParent( + state.currentPreviewItem.props, + component._id + ) + parent._children = parent._children.filter( + c => c._id !== component._id + ) + store.actions.components.select(parent) + } + + return state + }) + }, + paste: (targetComponent, mode) => { + store.update(state => { + if (!state.componentToPaste) return state + + const componentToPaste = cloneDeep(state.componentToPaste) + // retain the same ids as things may be referencing this component + if (componentToPaste.isCut) { + // in case we paste a second time + state.componentToPaste.isCut = false + } else { + generateNewIdsForComponent(componentToPaste, state) + } + delete componentToPaste.isCut + + if (mode === "inside") { + targetComponent._children.push(componentToPaste) + return state + } + + const parent = getParent( + state.currentPreviewItem.props, + targetComponent + ) + + const targetIndex = parent._children.indexOf(targetComponent) + const index = mode === "above" ? targetIndex : targetIndex + 1 + parent._children.splice(index, 0, cloneDeep(componentToPaste)) + + store.actions.screens.regenerateCssForCurrentScreen() + store.actions.preview.saveSelected() + store.actions.components.select(componentToPaste) + + return state + }) + }, + updateStyle: (type, name, value) => { + store.update(state => { + if (!state.currentComponentInfo._styles) { + state.currentComponentInfo._styles = {} + } + state.currentComponentInfo._styles[type][name] = value + + store.actions.screens.regenerateCssForCurrentScreen() + + // save without messing with the store + store.actions.preview.saveSelected() + return state + }) + }, + updateProp: (name, value) => { + store.update(state => { + let current_component = state.currentComponentInfo + current_component[name] = value + + state.currentComponentInfo = current_component + store.actions.preview.saveSelected() + return state + }) + }, + findRoute: component => { + // Gets all the components to needed to construct a path. + const tempStore = get(store) + let pathComponents = [] + let parent = component + let root = false + while (!root) { + parent = getParent(tempStore.currentPreviewItem.props, parent) + if (!parent) { + root = true + } else { + pathComponents.push(parent) + } + } + + // Remove root entry since it's the screen or page layout. + // Reverse array since we need the correct order of the IDs + const reversedComponents = pathComponents.reverse().slice(1) + + // Add component + const allComponents = [...reversedComponents, component] + + // Map IDs + const IdList = allComponents.map(c => c._id) + + // Construct ID Path: + const path = IdList.join("/") + + return path }, }, } + + return store } diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 5631ef00c5..638e0788dc 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -53,21 +53,21 @@ export const getStore = () => { store.setPackage = setPackage(store, initial) store.saveScreen = saveScreen(store) - store.setCurrentScreen = setCurrentScreen(store) - store.deleteScreens = deleteScreens(store) - store.setCurrentPage = setCurrentPage(store) + store.actions.screens.select = setCurrentScreen(store) + store.store.actions.screens.delete = store.actions.screens.delete(store) + store.actions.pages.select = setCurrentPage(store) store.createLink = createLink(store) store.createScreen = createScreen(store) // store.savePage = savePage(store) store.addChildComponent = addChildComponent(store) - store.selectComponent = selectComponent(store) + store.actions.components.select = selectComponent(store) store.setComponentProp = setComponentProp(store) store.setPageOrScreenProp = setPageOrScreenProp(store) - store.setComponentStyle = setComponentStyle(store) - store.setScreenType = setScreenType(store) - store.getPathToComponent = getPathToComponent(store) - store.pasteComponent = pasteComponent(store) - store.storeComponentForCopy = storeComponentForCopy(store) + store.actions.components.updateStyle = setComponentStyle(store) + store.actions.selectPageOrScreen = setScreenType(store) + store.actions.components.findRoute = getPathToComponent(store) + store.actions.components.paste = pasteComponent(store) + store.actions.components.copy = storeComponentForCopy(store) return store } @@ -251,7 +251,7 @@ const setCurrentScreen = store => screenName => { }) } -const deleteScreens = store => (screens, pageName = null) => { +const store.actions.screens.delete = store => (screens, pageName = null) => { if (!(screens instanceof Array)) { screens = [screens] } diff --git a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte index c794999ac7..46f53af4d3 100644 --- a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte +++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte @@ -39,7 +39,7 @@ async function deleteTable() { await backendUiStore.actions.tables.delete(table) - store.deleteScreens(templateScreens) + store.store.actions.screens.delete(templateScreens) await backendUiStore.actions.tables.fetch() notifier.success("Table deleted") hideEditor() diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 793ef84bbf..1fa7cdab7b 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -154,7 +154,7 @@ if (applicationPkg.ok) { backendUiStore.actions.reset() pkg.justCreated = true - await store.setPackage(pkg) + await store.actions.initialise(pkg) automationStore.actions.fetch() } else { throw new Error(pkg) diff --git a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte index 62eb49145d..87df51cd16 100644 --- a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte @@ -25,8 +25,8 @@ } const selectComponent = component => { - store.selectComponent(component) - const path = store.getPathToComponent(component) + store.actions.components.select(component) + const path = store.actions.components.findRoute(component) $goto(`./:page/:screen/${path}`) } @@ -89,17 +89,19 @@ const storeComponentForCopy = (cut = false) => { // lives in store - also used by drag drop - store.storeComponentForCopy(component, cut) + store.actions.components.copy(component, cut) } const pasteComponent = mode => { // lives in store - also used by drag drop - store.pasteComponent(component, mode) + store.actions.components.paste(component, mode) }