diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js deleted file mode 100644 index ee5f1b4b73..0000000000 --- a/packages/builder/src/builderStore/store/index.js +++ /dev/null @@ -1,519 +0,0 @@ -import { cloneDeep } from "lodash/fp" -import getNewComponentName from "../getNewComponentName" -import { backendUiStore } from "builderStore" -import { writable, get } from "svelte/store" -import api from "../api" -import { DEFAULT_PAGES_OBJECT } from "../../constants" -import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents" -import { - createProps, - makePropsSafe, - getBuiltin, -} from "components/userInterface/pagesParsing/createProps" -import { fetchComponentLibDefinitions } from "../loadComponentLibraries" -import { generate_screen_css } from "../generate_css" -import analytics from "analytics" -import { uuid } from "../uuid" -import { - selectComponent as _selectComponent, - getParent, - walkProps, - savePage as _savePage, - saveCurrentPreviewItem as _saveCurrentPreviewItem, - // saveScreenApi as _saveScreenApi, - regenerateCssForCurrentScreen, - regenerateCssForScreen, - generateNewIdsForComponent, - getComponentDefinition, - findChildComponentType, -} from "../storeUtils" - -export const getStore = () => { - const initial = { - apps: [], - name: "", - description: "", - pages: DEFAULT_PAGES_OBJECT, - mainUi: {}, - unauthenticatedUi: {}, - components: [], - currentPreviewItem: null, - currentComponentInfo: null, - currentFrontEndType: "none", - currentPageName: "", - currentComponentProps: null, - errors: [], - hasAppPackage: false, - libraries: null, - appId: "", - } - - const store = writable(initial) - - store.setPackage = setPackage(store, initial) - - store.saveScreen = saveScreen(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.actions.components.select = selectComponent(store) - store.setComponentProp = setComponentProp(store) - store.setPageOrScreenProp = setPageOrScreenProp(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 -} - -export default getStore - -const setPackage = (store, initial) => async pkg => { - const screens = await api.get("/api/screens").then(r => r.json()) - - const mainScreens = screens.filter(screen => - screen._id.includes(pkg.pages.main._id) - ), - unauthScreens = screens.filter(screen => - screen._id.includes(pkg.pages.unauthenticated._id) - ) - pkg.pages = { - main: { - ...pkg.pages.main, - _screens: mainScreens, - }, - unauthenticated: { - ...pkg.pages.unauthenticated, - _screens: unauthScreens, - }, - } - - // if the app has just been created - // we need to build the CSS and save - if (pkg.justCreated) { - const generateInitialPageCss = async name => { - const page = pkg.pages[name] - regenerateCssForScreen(page) - for (let screen of page._screens) { - regenerateCssForScreen(screen) - } - - await api.post(`/api/pages/${page._id}`, { - page: { - componentLibraries: pkg.application.componentLibraries, - ...page, - }, - screens: page._screens, - }) - } - await generateInitialPageCss("main") - await generateInitialPageCss("unauthenticated") - pkg.justCreated = false - } - - initial.libraries = pkg.application.componentLibraries - initial.components = await fetchComponentLibDefinitions(pkg.application._id) - initial.name = pkg.application.name - initial.description = pkg.application.description - initial.appId = pkg.application._id - initial.pages = pkg.pages - initial.hasAppPackage = true - initial.screens = [ - ...Object.values(mainScreens), - ...Object.values(unauthScreens), - ] - initial.builtins = [getBuiltin("##builtin/screenslot")] - initial.appInstance = pkg.application.instance - initial.appId = pkg.application._id - store.set(initial) - await backendUiStore.actions.database.select(initial.appInstance) - return initial -} - -const saveScreen = store => async screen => { - const storeContents = get(store) - const pageName = storeContents.currentPageName || "main" - const currentPage = storeContents.pages[pageName] - const currentPageScreens = currentPage._screens - - let savePromise - const response = await api.post(`/api/screens/${currentPage._id}`, screen) - const json = await response.json() - - if (currentPageScreens.includes(screen)) return - - screen._rev = json.rev - screen._id = json.id - - const screens = [...currentPageScreens, screen] - - // TODO: should carry out all server updates to screen in a single call - store.update(state => { - state.pages[pageName]._screens = screens - state.screens = screens - state.currentPreviewItem = screen - const safeProps = makePropsSafe( - state.components[screen.props._component], - screen.props - ) - state.currentComponentInfo = safeProps - screen.props = safeProps - savePromise = _savePage(state) - return state - }) - await savePromise -} - -const createScreen = store => async screen => { - let savePromise - store.update(state => { - state.currentPreviewItem = screen - state.currentComponentInfo = screen.props - state.currentFrontEndType = "screen" - regenerateCssForCurrentScreen(state) - savePromise = saveScreen(store)(screen) - return state - }) - await savePromise -} - -const createLink = store => async (url, title) => { - let savePromise - store.update(state => { - // Try to extract a nav component from the master screen - const nav = findChildComponentType( - state.pages.main, - "@budibase/standard-components/Navigation" - ) - if (nav) { - let newLink - - // Clone an existing link if one exists - if (nav._children && nav._children.length) { - // Clone existing link style - newLink = cloneDeep(nav._children[0]) - - // Manipulate IDs to ensure uniqueness - generateNewIdsForComponent(newLink, state, false) - - // Set our new props - newLink._instanceName = `${title} Link` - newLink.url = url - newLink.text = title - } else { - // Otherwise create vanilla new link - const component = getComponentDefinition( - state, - "@budibase/standard-components/link" - ) - const instanceId = get(backendUiStore).selectedDatabase._id - newLink = createProps(component, { - url, - text: title, - _instanceName: `${title} Link`, - _instanceId: instanceId, - }).props - } - - // Save page and regenerate all CSS because otherwise weird things happen - nav._children = [...nav._children, newLink] - state.currentPageName = "main" - regenerateCssForScreen(state.pages.main) - for (let screen of state.pages.main._screens) { - regenerateCssForScreen(screen) - } - savePromise = _savePage(state) - } - return state - }) - await savePromise -} - -const setCurrentScreen = store => screenName => { - store.update(s => { - const screen = getExactComponent(s.screens, screenName, true) - s.currentPreviewItem = screen - s.currentFrontEndType = "screen" - s.currentView = "detail" - regenerateCssForCurrentScreen(s) - const safeProps = makePropsSafe( - s.components[screen.props._component], - screen.props - ) - screen.props = safeProps - s.currentComponentInfo = safeProps - return s - }) -} - -const store.actions.screens.delete = store => (screens, pageName = null) => { - if (!(screens instanceof Array)) { - screens = [screens] - } - store.update(state => { - if (pageName == null) { - pageName = state.pages.main.name - } - for (let screen of screens) { - state.screens = state.screens.filter(c => c.name !== screen.name) - // Remove screen from current page as well - state.pages[pageName]._screens = state.pages[pageName]._screens.filter( - scr => scr.name !== screen.name - ) - api.delete(`/api/screens/${screen._id}/${screen._rev}`) - } - return state - }) -} - -// const savePage = store => async page => { -// store.update(state => { -// if (state.currentFrontEndType !== "page" || !state.currentPageName) { -// return state -// } - -// state.pages[state.currentPageName] = page -// _savePage(state) -// return state -// }) -// } - -const setCurrentPage = store => pageName => { - store.update(state => { - const current_screens = state.pages[pageName]._screens - - 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] - regenerateCssForCurrentScreen(state) - - for (let screen of state.screens) { - screen._css = generate_screen_css([screen.props]) - } - - return state - }) -} - -/** - * @param {string} componentToAdd - name of the component to add to the application - * @param {string} presetName - name of the component preset if defined - */ -const addChildComponent = store => (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) - - state.currentFrontEndType === "page" - ? _savePage(state) - : saveScreen(state.currentPreviewItem) - - state.currentView = "component" - state.currentComponentInfo = newComponent.props - analytics.captureEvent("Added Component", { - name: newComponent.props._component, - }) - return state - }) -} - -const selectComponent = store => component => { - store.update(state => { - return _selectComponent(state, component) - }) -} - -const setComponentProp = store => (name, value) => { - store.update(state => { - let current_component = state.currentComponentInfo - current_component[name] = value - - state.currentComponentInfo = current_component - //_saveCurrentPreviewItem(state) - return state - }) -} - -const setPageOrScreenProp = store => (name, value) => { - store.update(state => { - if (name === "_instanceName" && state.currentFrontEndType === "screen") { - state.currentPreviewItem.props[name] = value - } else { - state.currentPreviewItem[name] = value - } - //_saveCurrentPreviewItem(state) - return state - }) -} - -const setComponentStyle = store => (type, name, value) => { - store.update(state => { - if (!state.currentComponentInfo._styles) { - state.currentComponentInfo._styles = {} - } - state.currentComponentInfo._styles[type][name] = value - - regenerateCssForCurrentScreen(state) - - // save without messing with the store - //_saveCurrentPreviewItem(state) - return state - }) -} - -// Select page or screen -const setScreenType = store => type => { - store.update(state => { - state.currentFrontEndType = type - - const pageOrScreen = - type === "page" - ? state.pages[state.currentPageName] - : state.pages[state.currentPageName]._screens[0] - - state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null - state.currentPreviewItem = pageOrScreen - state.currentView = "detail" - return state - }) -} - -const getPathToComponent = store => 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 -} - -const storeComponentForCopy = store => (component, cut = false) => { - store.update(s => { - const copiedComponent = cloneDeep(component) - s.componentToPaste = copiedComponent - s.componentToPaste.isCut = cut - if (cut) { - const parent = getParent(s.currentPreviewItem.props, component._id) - parent._children = parent._children.filter(c => c._id !== component._id) - selectComponent(s, parent) - } - - return s - }) -} - -const pasteComponent = store => (targetComponent, mode) => { - store.update(s => { - if (!s.componentToPaste) return s - - const componentToPaste = cloneDeep(s.componentToPaste) - // retain the same ids as things may be referencing this component - if (componentToPaste.isCut) { - // in case we paste a second time - s.componentToPaste.isCut = false - } else { - generateNewIdsForComponent(componentToPaste, s) - } - delete componentToPaste.isCut - - if (mode === "inside") { - targetComponent._children.push(componentToPaste) - return s - } - - const parent = getParent(s.currentPreviewItem.props, targetComponent) - - const targetIndex = parent._children.indexOf(targetComponent) - const index = mode === "above" ? targetIndex : targetIndex + 1 - parent._children.splice(index, 0, cloneDeep(componentToPaste)) - regenerateCssForCurrentScreen(s) - //_saveCurrentPreviewItem(s) - selectComponent(s, componentToPaste) - - return s - }) -} diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 53a083db7c..b10b8d82c0 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -97,6 +97,7 @@ exports.fetchAppPackage = async function(ctx) { exports.create = async function(ctx) { const instance = await createInstance(ctx.request.body.template) const appId = instance._id + const version = packageJson.version const newApplication = { _id: appId, type: "app", @@ -114,6 +115,7 @@ exports.create = async function(ctx) { await downloadExtractComponentLibraries(newAppFolder) } + await setBuilderToken(ctx, appId, version) ctx.status = 200 ctx.body = newApplication ctx.message = `Application ${ctx.request.body.name} created successfully` @@ -228,7 +230,7 @@ const createEmptyAppPackage = async (ctx, app) => { unauthPage.props._children[0]._children.title = `Log in to ${app.name}` const homeScreen = cloneDeep(HOME_SCREEN) homeScreen._id = generateScreenID(mainPage._id) - await db.bulkDocs([mainPage, unauthPage, homeScreen]) + const response = await db.bulkDocs([mainPage, unauthPage, homeScreen]) await buildPage(app._id, "main", { page: mainPage, diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/main/page.json b/packages/server/src/utilities/appDirectoryTemplate/pages/main/page.json deleted file mode 100644 index 19ab2dca03..0000000000 --- a/packages/server/src/utilities/appDirectoryTemplate/pages/main/page.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "componentLibraries": [ - "@budibase/standard-components" - ], - "title": "{{ name }}", - "favicon": "./_shared/favicon.png", - "stylesheets": [], - "props": { - "_id": "private-master-root", - "_component": "@budibase/standard-components/container", - "_children": [ - { - "_id": "c74f07266980c4b6eafc33e2a6caa783d", - "_component": "@budibase/standard-components/container", - "_styles": { - "normal": { - "display": "flex", - "flex-direction": "row", - "justify-content": "flex-start", - "align-items": "flex-start", - "background": "#fff", - "width": "100%", - "box-shadow": "0 1px 2px 0 rgba(0, 0, 0, 0.05)" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "className": "", - "onLoad": [], - "type": "div", - "_appId": "inst_app_80b_f158d4057d2c4bedb0042d42fda8abaf", - "_instanceName": "Header", - "_children": [ - { - "_id": "49e0e519-9e5e-4127-885a-ee6a0a49e2c1", - "_component": "@budibase/standard-components/Navigation", - "_styles": { - "normal": { - "max-width": "1400px", - "margin-left": "auto", - "margin-right": "auto", - "padding": "20px", - "color": "#757575", - "font-weight": "400", - "font-size": "16px", - "flex": "1 1 auto" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "logoUrl": "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg", - "title": "", - "backgroundColor": "", - "color": "", - "borderWidth": "", - "borderColor": "", - "borderStyle": "", - "_appId": "inst_cf8ace4_69efc0d72e6f443db2d4c902c14d9394", - "_instanceName": "Navigation", - "_children": [ - { - "_id": "48b35328-4c91-4343-a6a3-1a1fd77b3386", - "_component": "@budibase/standard-components/link", - "_styles": { - "normal": { - "font-family": "Inter", - "font-weight": "500", - "color": "#000000", - "text-decoration-line": "none", - "font-size": "16px" - }, - "hover": { - "color": "#4285f4" - }, - "active": {}, - "selected": {} - }, - "_code": "", - "url": "/", - "openInNewTab": false, - "text": "Home", - "color": "", - "hoverColor": "", - "underline": false, - "fontSize": "", - "fontFamily": "initial", - "_appId": "inst_cf8ace4_69efc0d72e6f443db2d4c902c14d9394", - "_instanceName": "Home Link", - "_children": [] - } - ] - } - ] - }, - { - "_id": "7fcf11e4-6f5b-4085-8e0d-9f3d44c98967", - "_component": "##builtin/screenslot", - "_styles": { - "normal": { - "flex": "1 1 auto", - "display": "flex", - "flex-direction": "column", - "justify-content": "flex-start", - "align-items": "stretch", - "max-width": "100%", - "margin-left": "20px", - "margin-right": "20px", - "width": "1400px", - "padding": "20px" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "_children": [] - } - ], - "type": "div", - "_styles": { - "active": {}, - "hover": {}, - "normal": { - "display": "flex", - "flex-direction": "column", - "align-items": "center", - "justify-content": "flex-start", - "margin-right": "auto", - "margin-left": "auto", - "min-height": "100%", - "background-image": "linear-gradient(135deg, rgba(252,215,212,1) 20%, rgba(207,218,255,1) 100%);" - }, - "selected": {} - }, - "_code": "", - "className": "", - "onLoad": [] - } -} diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/.gitkeep b/packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/d834fea2-1b3e-4320-ab34-f9009f5ecc59.json b/packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/d834fea2-1b3e-4320-ab34-f9009f5ecc59.json deleted file mode 100644 index 4104dcdb1e..0000000000 --- a/packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/d834fea2-1b3e-4320-ab34-f9009f5ecc59.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "description": "", - "url": "", - "props": { - "_id": "d834fea2-1b3e-4320-ab34-f9009f5ecc59", - "_component": "@budibase/standard-components/container", - "_styles": { - "normal": { - "flex": "1 1 auto", - "display": "flex", - "flex-direction": "column", - "justify-content": "flex-start", - "align-items": "stretch" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "className": "", - "onLoad": [], - "type": "div", - "_children": [ - { - "_id": "ef60083f-4a02-4df3-80f3-a0d3d16847e7", - "_component": "@budibase/standard-components/heading", - "_styles": { - "normal": { - "text-align": "left" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "className": "", - "text": "Welcome to your Budibase App 👋", - "type": "h2", - "_appId": "inst_cf8ace4_69efc0d72e6f443db2d4c902c14d9394", - "_instanceName": "Heading", - "_children": [] - }, - { - "_id": "cbbf41b27c2b44d1abba38bb694880c6a", - "_component": "@budibase/standard-components/container", - "_styles": { - "normal": { - "display": "flex", - "flex-direction": "column", - "justify-content": "center", - "align-items": "stretch", - "flex": "1 1 auto", - "border-width": "4px", - "border-style": "Dashed", - "margin-bottom": "32px" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "className": "", - "onLoad": [], - "type": "div", - "_appId": "inst_app_2cc_ca3383f896034e9295345c05f7dfca0c", - "_instanceName": "Video Container", - "_children": [ - { - "_id": "c07d752cb3e544b418088fa9be84ba2e4", - "_component": "@budibase/standard-components/embed", - "_styles": { - "normal": { - "width": "100%", - "flex": "1 1 auto", - "opacity": "0", - "transition-property": "Opacity", - "transition-duration": "1s", - "transition-timing-function:": "ease-in" - }, - "hover": { - "transition-property": "Opacity", - "transition-duration": "1s", - "transition-timing-function:": "ease-out", - "opacity": "1" - }, - "active": {}, - "selected": {} - }, - "_code": "", - "embed": "", - "_appId": "inst_app_2cc_ca3383f896034e9295345c05f7dfca0c", - "_instanceName": "Rick Astley Video", - "_children": [] - } - ] - } - ], - "_instanceName": "Home" - }, - "route": "/", - "name": "d834fea2-1b3e-4320-ab34-f9009f5ecc59" -} diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json b/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json deleted file mode 100644 index f4a195d526..0000000000 --- a/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "componentLibraries": [ - "@budibase/standard-components" - ], - "title": "{{ name }}", - "favicon": "./_shared/favicon.png", - "stylesheets": [], - "props": { - "_id": "public-master-root", - "_component": "@budibase/standard-components/container", - "_children": [ - { - "_id": "686c252d-dbf2-4e28-9078-414ba4719759", - "_component": "@budibase/standard-components/login", - "_styles": { - "normal": { - "padding": "64px", - "background": "rgba(255, 255, 255, 0.4)", - "border-radius": "0.5rem", - "margin-top": "0px", - "margin": "0px", - "line-height": "1", - "box-shadow": "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)", - "font-size": "16px", - "font-family": "Inter", - "flex": "0 1 auto", - "transform": "0" - }, - "hover": {}, - "active": {}, - "selected": {} - }, - "_code": "", - "loginRedirect": "", - "usernameLabel": "Username", - "passwordLabel": "Password", - "loginButtonLabel": "Login", - "buttonClass": "", - "_instanceName": "Login", - "inputClass": "", - "_children": [], - "title": "Log in to {{ name }}", - "buttonText": "Log In", - "logo": "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" - } - ], - "type": "div", - "_styles": { - "active": {}, - "hover": {}, - "normal": { - "display": "flex", - "flex-direction": "column", - "align-items": "center", - "justify-content": "center", - "margin-right": "auto", - "margin-left": "auto", - "min-height": "100%", - "background-image": "linear-gradient(135deg, rgba(252,215,212,1) 20%, rgba(207,218,255,1) 100%);" - }, - "selected": {} - }, - "_code": "", - "className": "", - "onLoad": [] - } -} diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/screens/.gitkeep b/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/screens/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/screens/placeholder b/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/screens/placeholder deleted file mode 100644 index e69de29bb2..0000000000