From 2f0a19a15210c5d9e59b6c9fb5df50e2c47c3fbd Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 29 Oct 2020 11:46:26 +0000 Subject: [PATCH 01/21] removing dead code --- .../src/builderStore/buildCodeForScreens.js | 33 -------------- .../src/builderStore/insertCodeMetadata.js | 17 ------- .../builder/src/builderStore/store/index.js | 45 ------------------- .../server/src/utilities/builder/buildPage.js | 3 -- .../src/utilities/builder/deleteCodeMeta.js | 9 ---- 5 files changed, 107 deletions(-) delete mode 100644 packages/builder/src/builderStore/buildCodeForScreens.js delete mode 100644 packages/builder/src/builderStore/insertCodeMetadata.js delete mode 100644 packages/server/src/utilities/builder/deleteCodeMeta.js diff --git a/packages/builder/src/builderStore/buildCodeForScreens.js b/packages/builder/src/builderStore/buildCodeForScreens.js deleted file mode 100644 index 69ef0d6e0b..0000000000 --- a/packages/builder/src/builderStore/buildCodeForScreens.js +++ /dev/null @@ -1,33 +0,0 @@ -const buildCodeForSingleScreen = screen => { - let code = "" - const walkProps = props => { - if (props._code && props._code.trim().length > 0) { - code += buildComponentCode(props) - } - - if (!props._children) return - - for (let child of props._children) { - walkProps(child) - } - } - - walkProps(screen.props) - - return code -} - -export const buildCodeForScreens = screens => { - let allfunctions = "" - for (let screen of screens) { - allfunctions += buildCodeForSingleScreen(screen) - } - - return `({ ${allfunctions} });` -} - -const buildComponentCode = componentProps => - `"${componentProps._id}" : (render, context, state, route) => { -${componentProps._code} -}, -` diff --git a/packages/builder/src/builderStore/insertCodeMetadata.js b/packages/builder/src/builderStore/insertCodeMetadata.js deleted file mode 100644 index 9093c4003d..0000000000 --- a/packages/builder/src/builderStore/insertCodeMetadata.js +++ /dev/null @@ -1,17 +0,0 @@ -export const insertCodeMetadata = props => { - if (props._code && props._code.length > 0) { - props._codeMeta = codeMetaData(props._code) - } - - if (!props._children || props._children.length === 0) return - - for (let child of props._children) { - insertCodeMetadata(child) - } -} - -const codeMetaData = code => { - return { - dependsOnStore: RegExp(/(state.)/g).test(code), - } -} diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 4e7b089f5e..ead1721896 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -11,9 +11,7 @@ import { getBuiltin, } from "components/userInterface/pagesParsing/createProps" import { fetchComponentLibDefinitions } from "../loadComponentLibraries" -import { buildCodeForScreens } from "../buildCodeForScreens" import { generate_screen_css } from "../generate_css" -import { insertCodeMetadata } from "../insertCodeMetadata" import analytics from "analytics" import { uuid } from "../uuid" import { @@ -60,15 +58,12 @@ export const getStore = () => { store.setCurrentPage = setCurrentPage(store) store.createLink = createLink(store) store.createScreen = createScreen(store) - store.addStylesheet = addStylesheet(store) - store.removeStylesheet = removeStylesheet(store) store.savePage = savePage(store) store.addChildComponent = addChildComponent(store) store.selectComponent = selectComponent(store) store.setComponentProp = setComponentProp(store) store.setPageOrScreenProp = setPageOrScreenProp(store) store.setComponentStyle = setComponentStyle(store) - store.setComponentCode = setComponentCode(store) store.setScreenType = setScreenType(store) store.getPathToComponent = getPathToComponent(store) store.addTemplatedComponent = addTemplatedComponent(store) @@ -258,7 +253,6 @@ const setCurrentScreen = store => screenName => { ) screen.props = safeProps s.currentComponentInfo = safeProps - setCurrentPageFunctions(s) return s }) } @@ -295,24 +289,6 @@ const savePage = store => async page => { }) } -const addStylesheet = store => stylesheet => { - store.update(s => { - s.pages.stylesheets.push(stylesheet) - _savePage(s) - return s - }) -} - -const removeStylesheet = store => stylesheet => { - store.update(state => { - state.pages.stylesheets = state.pages.stylesheets.filter( - s => s !== stylesheet - ) - _savePage(state) - return state - }) -} - const setCurrentPage = store => pageName => { store.update(state => { const current_screens = state.pages[pageName]._screens @@ -338,7 +314,6 @@ const setCurrentPage = store => pageName => { screen._css = generate_screen_css([screen.props]) } - setCurrentPageFunctions(state) return state }) } @@ -424,7 +399,6 @@ const addTemplatedComponent = store => props => { ) regenerateCssForCurrentScreen(state) - setCurrentPageFunctions(state) _saveCurrentPreviewItem(state) return state @@ -475,25 +449,6 @@ const setComponentStyle = store => (type, name, value) => { }) } -const setComponentCode = store => code => { - store.update(state => { - state.currentComponentInfo._code = code - - setCurrentPageFunctions(state) - // save without messing with the store - _saveScreenApi(state.currentPreviewItem, state) - - return state - }) -} - -const setCurrentPageFunctions = s => { - s.currentPageFunctions = buildPageCode(s.screens, s.pages[s.currentPageName]) - insertCodeMetadata(s.currentPreviewItem.props) -} - -const buildPageCode = (screens, page) => buildCodeForScreens([page, ...screens]) - const setScreenType = store => type => { store.update(state => { state.currentFrontEndType = type diff --git a/packages/server/src/utilities/builder/buildPage.js b/packages/server/src/utilities/builder/buildPage.js index 7db1299fa2..bf10828115 100644 --- a/packages/server/src/utilities/builder/buildPage.js +++ b/packages/server/src/utilities/builder/buildPage.js @@ -10,7 +10,6 @@ const { join, resolve } = require("../centralPath") const sqrl = require("squirrelly") const { convertCssToFiles } = require("./convertCssToFiles") const publicPath = require("./publicPath") -const deleteCodeMeta = require("./deleteCodeMeta") module.exports = async (config, appId, pageName, pkg) => { const appPath = appPackageFolder(config, appId) @@ -122,8 +121,6 @@ const savePageJson = async (appPath, pageName, pkg) => { delete pkg.page._screens } - deleteCodeMeta(pkg.page.props) - await writeJSON(pageFile, pkg.page, { spaces: 2, }) diff --git a/packages/server/src/utilities/builder/deleteCodeMeta.js b/packages/server/src/utilities/builder/deleteCodeMeta.js deleted file mode 100644 index 07a0bc0349..0000000000 --- a/packages/server/src/utilities/builder/deleteCodeMeta.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = props => { - if (props._codeMeta) { - delete props._codeMeta - } - - for (let child of props._children || []) { - module.exports(child) - } -} From 950e6556d92c55656b0e272e353438c354d39075 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Sun, 1 Nov 2020 15:32:54 +0000 Subject: [PATCH 02/21] started creating APIs for screens --- packages/server/src/api/controllers/screen.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/server/src/api/controllers/screen.js b/packages/server/src/api/controllers/screen.js index 91c3c83dd5..e8e7238257 100644 --- a/packages/server/src/api/controllers/screen.js +++ b/packages/server/src/api/controllers/screen.js @@ -3,11 +3,30 @@ * currently managed as part of the pages API, please look in api/routes/page.js * for routes and controllers. */ +const CouchDB = require("../../db") exports.fetch = async ctx => { ctx.throw(501) } +exports.create = async ctx => { + const db = new CouchDB(ctx.user.appId) + const screen = { + // name: ctx.request.body.name, + // _rev: ctx.request.body._rev, + // permissions: ctx.request.body.permissions || [], + // _id: generateAccessLevelID(), + // type: "accesslevel", + } + + const response = await db.put(screen) + ctx.body = { + ...screen, + ...response, + } + ctx.message = `Screen '${screen.name}' created successfully.` +} + exports.save = async ctx => { ctx.throw(501) } From 74890b13c97c674e04cf204661fa058fda92fb8b Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 2 Nov 2020 14:53:51 +0000 Subject: [PATCH 03/21] pages being stored in couch on initialisation and page save --- .../builder/src/builderStore/storeUtils.js | 2 +- .../server/src/api/controllers/application.js | 40 ++++++++++-- packages/server/src/api/controllers/page.js | 33 ++++++++++ packages/server/src/api/routes/pages.js | 13 +--- packages/server/src/api/routes/pages.new.js | 35 +++++++++++ packages/server/src/db/client.js | 14 +++++ packages/server/src/db/utils.js | 25 ++++++++ .../server/src/utilities/builder/buildPage.js | 62 +++++++++--------- .../server/src/utilities/builder/index.js | 63 +++++++++---------- .../src/utilities/builder/listScreens.js | 6 +- .../server/src/utilities/createAppPackage.js | 3 - 11 files changed, 207 insertions(+), 89 deletions(-) create mode 100644 packages/server/src/api/controllers/page.js create mode 100644 packages/server/src/api/routes/pages.new.js diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 2c486a9bdb..b19df1976e 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -38,7 +38,7 @@ export const saveCurrentPreviewItem = s => export const savePage = async s => { const pageName = s.currentPageName || "main" const page = s.pages[pageName] - await api.post(`/_builder/api/${s.appId}/pages/${pageName}`, { + await api.post(`/api/pages/${pageName}`, { page: { componentLibraries: s.pages.componentLibraries, ...page }, uiFunctions: s.currentPageFunctions, screens: page._screens, diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 66cde54fd6..dc6aecff12 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -1,5 +1,5 @@ const CouchDB = require("../../db") -const { getPackageForBuilder, buildPage } = require("../../utilities/builder") +const { buildPage } = require("../../utilities/builder") const env = require("../../environment") const { copy, existsSync, readFile, writeFile } = require("fs-extra") const { budibaseAppsDir } = require("../../utilities/budibaseDir") @@ -12,10 +12,17 @@ const chmodr = require("chmodr") const packageJson = require("../../../package.json") const { createLinkView } = require("../../db/linkedRows") const { downloadTemplate } = require("../../utilities/templates") -const { generateAppID, DocumentTypes, SEPARATOR } = require("../../db/utils") +const { + generateAppID, + DocumentTypes, + SEPARATOR, + getPageParams, + generatePageID, +} = require("../../db/utils") const { downloadExtractComponentLibraries, } = require("../../utilities/createAppPackage") + const APP_PREFIX = DocumentTypes.APP + SEPARATOR async function createInstance(template) { @@ -60,7 +67,19 @@ exports.fetch = async function(ctx) { exports.fetchAppPackage = async function(ctx) { const db = new CouchDB(ctx.params.appId) const application = await db.get(ctx.params.appId) - ctx.body = await getPackageForBuilder(ctx.config, application) + // ctx.body = await getPackageForBuilder(application) + + const pages = await db.allDocs( + getPageParams(null, { + include_docs: true, + }) + ) + + ctx.body = { + application, + pages, + } + setBuilderToken(ctx, ctx.params.appId, application.version) } @@ -132,6 +151,8 @@ const createEmptyAppPackage = async (ctx, app) => { const appsFolder = budibaseAppsDir() const newAppFolder = resolve(appsFolder, app._id) + const db = new CouchDB(app._id) + if (existsSync(newAppFolder)) { ctx.throw(400, "App folder already exists for this application") } @@ -164,6 +185,8 @@ const createEmptyAppPackage = async (ctx, app) => { app.template.key, "pages" ) + // TODO: write the template page JSON to couch + // iterate over the pages and write them to the db await copy(templatePageDefinitions, join(appsFolder, app._id, "pages")) } @@ -172,7 +195,10 @@ const createEmptyAppPackage = async (ctx, app) => { app ) - await buildPage(ctx.config, app._id, "main", { + mainJson._id = generatePageID() + await db.put(mainJson) + + await buildPage(app._id, "main", { page: mainJson, screens: await loadScreens(newAppFolder, "main"), }) @@ -182,7 +208,11 @@ const createEmptyAppPackage = async (ctx, app) => { app ) - await buildPage(ctx.config, app._id, "unauthenticated", { + // Write to couch + unauthenticatedJson._id = generatePageID() + await db.put(unauthenticatedJson) + + await buildPage(app._id, "unauthenticated", { page: unauthenticatedJson, screens: await loadScreens(newAppFolder, "unauthenticated"), }) diff --git a/packages/server/src/api/controllers/page.js b/packages/server/src/api/controllers/page.js new file mode 100644 index 0000000000..be04a4421e --- /dev/null +++ b/packages/server/src/api/controllers/page.js @@ -0,0 +1,33 @@ +const CouchDB = require("../../db/client") +const { generatePageID } = require("../../db/utils") +const { buildPage } = require("../../utilities/builder") + +exports.save = async function(ctx) { + const db = new CouchDB(ctx.user.appId) + + const appPackage = ctx.request.body + + // TODO: rename to something more descriptive + await buildPage( + ctx.config, + ctx.user.appId, + ctx.params.pageName, + ctx.request.body + ) + + // write the page data to couchDB + // if (pkg.page._css) { + // delete pkg.page._css + // } + + // if (pkg.page.name) { + // delete pkg.page.name + // } + + // if (pkg.page._screens) { + // delete pkg.page._screens + // } + appPackage.page._id = appPackage.page._id || generatePageID() + await db.put(appPackage.page) + ctx.response.status = 200 +} diff --git a/packages/server/src/api/routes/pages.js b/packages/server/src/api/routes/pages.js index 43293a8911..547f0d2eb6 100644 --- a/packages/server/src/api/routes/pages.js +++ b/packages/server/src/api/routes/pages.js @@ -45,12 +45,7 @@ router.post( "/_builder/api/:appId/pages/:pageName", authorized(BUILDER), async ctx => { - await buildPage( - ctx.config, - ctx.params.appId, - ctx.params.pageName, - ctx.request.body - ) + await buildPage(ctx.params.appId, ctx.params.pageName, ctx.request.body) ctx.response.status = StatusCodes.OK } ) @@ -59,11 +54,7 @@ router.get( "/_builder/api/:appId/pages/:pagename/screens", authorized(BUILDER), async ctx => { - ctx.body = await listScreens( - ctx.config, - ctx.params.appId, - ctx.params.pagename - ) + ctx.body = await listScreens(ctx.params.appId, ctx.params.pagename) ctx.response.status = StatusCodes.OK } ) diff --git a/packages/server/src/api/routes/pages.new.js b/packages/server/src/api/routes/pages.new.js new file mode 100644 index 0000000000..8aa95638ae --- /dev/null +++ b/packages/server/src/api/routes/pages.new.js @@ -0,0 +1,35 @@ +const Router = require("@koa/router") +const joiValidator = require("../../middleware/joi-validator") +const Joi = require("joi") +const authorized = require("../../middleware/authorized") +const { BUILDER } = require("../../utilities/accessLevels") +const controller = require("../controllers/page") + +const router = Router() + +function generateSaveValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + _css: Joi.string().allow(""), + name: Joi.string().required(), + route: Joi.string().required(), + props: Joi.object({ + _id: Joi.string().required(), + _component: Joi.string().required(), + _children: Joi.array().required(), + _instanceName: Joi.string().required(), + _styles: Joi.object().required(), + type: Joi.string().optional(), + table: Joi.string().optional(), + }).required().unknown(true), + }).unknown(true)) +} + +router.post( + "/api/pages/:pageName", + authorized(BUILDER), + generateSaveValidation(), + controller.save +) + +module.exports = router diff --git a/packages/server/src/db/client.js b/packages/server/src/db/client.js index a3051eea7f..1d025a1402 100644 --- a/packages/server/src/db/client.js +++ b/packages/server/src/db/client.js @@ -26,4 +26,18 @@ const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS) allDbs(Pouch) +// replicate your local levelDB pouch to a running HTTP compliant couch or pouchdb server. +// eslint-disable-next-line no-unused-vars +function replicateLocal() { + Pouch.allDbs().then(dbs => { + for (let db of dbs) { + new Pouch(db).sync( + new PouchDB(`http://127.0.0.1:5984/${db}`, { live: true }) + ) + } + }) +} + +replicateLocal() + module.exports = Pouch diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 257f367478..b327a5ad12 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -13,6 +13,8 @@ const DocumentTypes = { ACCESS_LEVEL: "ac", WEBHOOK: "wh", INSTANCE: "inst", + PAGE: "page", + SCREEN: "screen", } exports.DocumentTypes = DocumentTypes @@ -175,6 +177,29 @@ exports.generateWebhookID = () => { return `${DocumentTypes.WEBHOOK}${SEPARATOR}${newid()}` } +/** + * Generates a new screen ID. + * @returns {string} The new screen ID which the screen doc can be stored under. + */ +exports.generateScreenID = () => { + return `${DocumentTypes.SCREEN}${SEPARATOR}${newid()}` +} + +/** + * Generates a new page ID. + * @returns {string} The new page ID which the page doc can be stored under. + */ +exports.generatePageID = () => { + return `${DocumentTypes.PAGE}${SEPARATOR}${newid()}` +} + +/** + * Gets parameters for retrieving pages, this is a utility function for the getDocParams function. + */ +exports.getPageParams = (pageId = null, otherProps = {}) => { + return getDocParams(DocumentTypes.PAGE, pageId, otherProps) +} + /** * Gets parameters for retrieving a webhook, this is a utility function for the getDocParams function. */ diff --git a/packages/server/src/utilities/builder/buildPage.js b/packages/server/src/utilities/builder/buildPage.js index bf10828115..2071e767f4 100644 --- a/packages/server/src/utilities/builder/buildPage.js +++ b/packages/server/src/utilities/builder/buildPage.js @@ -1,33 +1,27 @@ -const { appPackageFolder } = require("../createAppPackage") -const { - constants, - copyFile, - writeFile, - readFile, - writeJSON, -} = require("fs-extra") +const { constants, copyFile, writeFile, readFile } = require("fs-extra") const { join, resolve } = require("../centralPath") const sqrl = require("squirrelly") const { convertCssToFiles } = require("./convertCssToFiles") const publicPath = require("./publicPath") +const { budibaseAppsDir } = require("../budibaseDir") -module.exports = async (config, appId, pageName, pkg) => { - const appPath = appPackageFolder(config, appId) +module.exports = async (appId, pageName, pkg) => { + const appPath = join(budibaseAppsDir(), appId) pkg.screens = pkg.screens || [] await convertCssToFiles(publicPath(appPath, pageName), pkg) - await buildIndexHtml(config, appId, pageName, appPath, pkg) + await buildIndexHtml(appId, pageName, appPath, pkg) - await buildFrontendAppDefinition(config, appId, pageName, pkg, appPath) + await buildFrontendAppDefinition(appId, pageName, pkg, appPath) await copyClientLib(appPath, pageName) - await savePageJson(appPath, pageName, pkg) + // await savePageJson(appPath, pageName, pkg) } -const rootPath = (config, appId) => (config.useAppRootPath ? `/${appId}` : "") +// const rootPath = (config, appId) => (config.useAppRootPath ? `/${appId}` : "") const copyClientLib = async (appPath, pageName) => { const sourcepath = require.resolve("@budibase/client") @@ -42,11 +36,10 @@ const copyClientLib = async (appPath, pageName) => { ) } -const buildIndexHtml = async (config, appId, pageName, appPath, pkg) => { +const buildIndexHtml = async (appId, pageName, appPath, pkg) => { const appPublicPath = publicPath(appPath, pageName) - const stylesheetUrl = s => - s.startsWith("http") ? s : `/${rootPath(config, appId)}/${s}` + const stylesheetUrl = s => (s.startsWith("http") ? s : `/${appId}/${s}`) const templateObj = { title: pkg.page.title || "Budibase App", @@ -76,12 +69,13 @@ const buildIndexHtml = async (config, appId, pageName, appPath, pkg) => { await writeFile(deployableHtmlPath, deployableHtml, { flag: "w+" }) } -const buildFrontendAppDefinition = async (config, appId, pageName, pkg) => { - const appPath = appPackageFolder(config, appId) +const buildFrontendAppDefinition = async (appId, pageName, pkg) => { + const appPath = join(budibaseAppsDir(), appId) const appPublicPath = publicPath(appPath, pageName) const filename = join(appPublicPath, "clientFrontendDefinition.js") + // TODO: weird - why if (pkg.page._css) { delete pkg.page._css } @@ -106,22 +100,22 @@ const buildFrontendAppDefinition = async (config, appId, pageName, pkg) => { ) } -const savePageJson = async (appPath, pageName, pkg) => { - const pageFile = join(appPath, "pages", pageName, "page.json") +// const savePageJson = async (appPath, pageName, pkg) => { +// const pageFile = join(appPath, "pages", pageName, "page.json") - if (pkg.page._css) { - delete pkg.page._css - } +// if (pkg.page._css) { +// delete pkg.page._css +// } - if (pkg.page.name) { - delete pkg.page.name - } +// if (pkg.page.name) { +// delete pkg.page.name +// } - if (pkg.page._screens) { - delete pkg.page._screens - } +// if (pkg.page._screens) { +// delete pkg.page._screens +// } - await writeJSON(pageFile, pkg.page, { - spaces: 2, - }) -} +// await writeJSON(pageFile, pkg.page, { +// spaces: 2, +// }) +// } diff --git a/packages/server/src/utilities/builder/index.js b/packages/server/src/utilities/builder/index.js index dbc2ce6bf5..71da152f7b 100644 --- a/packages/server/src/utilities/builder/index.js +++ b/packages/server/src/utilities/builder/index.js @@ -8,36 +8,37 @@ const { unlink, rmdir, } = require("fs-extra") -const { join, resolve } = require("../centralPath") +const { join } = require("../centralPath") const { dirname } = require("path") const buildPage = require("./buildPage") -const getPages = require("./getPages") +// const getPages = require("./getPages") const listScreens = require("./listScreens") -const deleteCodeMeta = require("./deleteCodeMeta") +const { budibaseAppsDir } = require("../budibaseDir") +// const { budibaseAppsDir } = require("../budibaseDir") module.exports.buildPage = buildPage module.exports.listScreens = listScreens -const getAppDefinition = async appPath => - await readJSON(`${appPath}/appDefinition.json`) +// const getAppDefinition = async appPath => +// await readJSON(`${appPath}/appDefinition.json`) -module.exports.getPackageForBuilder = async (config, application) => { - const appPath = resolve(config.latestPackagesFolder, application._id) +// module.exports.getPackageForBuilder = async application => { +// const appPath = resolve(budibaseAppsDir(), application._id) - const pages = await getPages(appPath) +// const pages = await getPages(appPath) - return { - pages, - application, - } -} +// return { +// pages, +// application, +// } +// } const screenPath = (appPath, pageName, name) => join(appPath, "pages", pageName, "screens", name + ".json") -module.exports.saveScreen = async (config, appname, pagename, screen) => { - const appPath = appPackageFolder(config, appname) +module.exports.saveScreen = async (appId, pagename, screen) => { + const appPath = join(budibaseAppsDir(), appId) const compPath = screenPath(appPath, pagename, screen.props._id) await ensureDir(dirname(compPath)) @@ -45,8 +46,6 @@ module.exports.saveScreen = async (config, appname, pagename, screen) => { delete screen._css } - deleteCodeMeta(screen.props) - await writeJSON(compPath, screen, { encoding: "utf8", flag: "w", @@ -57,12 +56,12 @@ module.exports.saveScreen = async (config, appname, pagename, screen) => { module.exports.renameScreen = async ( config, - appname, + appId, pagename, oldName, newName ) => { - const appPath = appPackageFolder(config, appname) + const appPath = join(budibaseAppsDir(), appId) const oldComponentPath = screenPath(appPath, pagename, oldName) @@ -73,7 +72,7 @@ module.exports.renameScreen = async ( } module.exports.deleteScreen = async (config, appId, pagename, name) => { - const appPath = appPackageFolder(config, appId) + const appPath = join(budibaseAppsDir(), appId) const componentFile = screenPath(appPath, pagename, name) await unlink(componentFile) @@ -83,16 +82,16 @@ module.exports.deleteScreen = async (config, appId, pagename, name) => { } } -module.exports.savePage = async (config, appname, pagename, page) => { - const appPath = appPackageFolder(config, appname) - const pageDir = join(appPath, "pages", pagename) +// module.exports.savePage = async (appId, pagename, page) => { +// const appPath = join(budibaseAppsDir(), appId) +// const pageDir = join(appPath, "pages", pagename) - await ensureDir(pageDir) - await writeJSON(join(pageDir, "page.json"), page, { - encoding: "utf8", - flag: "w", - space: 2, - }) - const appDefinition = await getAppDefinition(appPath) - await buildPage(config, appname, appDefinition, pagename, page) -} +// await ensureDir(pageDir) +// await writeJSON(join(pageDir, "page.json"), page, { +// encoding: "utf8", +// flag: "w", +// space: 2, +// }) +// const appDefinition = await getAppDefinition(appPath) +// await buildPage(appId, appDefinition, pagename, page) +// } diff --git a/packages/server/src/utilities/builder/listScreens.js b/packages/server/src/utilities/builder/listScreens.js index 8964ac6cec..80a9afbe78 100644 --- a/packages/server/src/utilities/builder/listScreens.js +++ b/packages/server/src/utilities/builder/listScreens.js @@ -1,10 +1,10 @@ -const { appPackageFolder } = require("../createAppPackage") const { readJSON, readdir, stat } = require("fs-extra") const { join } = require("../centralPath") const { keyBy } = require("lodash/fp") +const { budibaseAppsDir } = require("../budibaseDir") -module.exports = async (config, appname, pagename) => { - const appPath = appPackageFolder(config, appname) +module.exports = async (appId, pagename) => { + const appPath = join(budibaseAppsDir(), appId) return keyBy("name")(await fetchscreens(appPath, pagename)) } diff --git a/packages/server/src/utilities/createAppPackage.js b/packages/server/src/utilities/createAppPackage.js index d2a1840cb2..af943d260e 100644 --- a/packages/server/src/utilities/createAppPackage.js +++ b/packages/server/src/utilities/createAppPackage.js @@ -9,9 +9,6 @@ const packageJson = require("../../package.json") const streamPipeline = promisify(stream.pipeline) -exports.appPackageFolder = (config, appname) => - resolve(cwd(), config.latestPackagesFolder, appname) - exports.downloadExtractComponentLibraries = async appFolder => { const LIBRARIES = ["standard-components"] From 3725a1782ba9832c59e1f20ef2ee6f61172e5cf2 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 3 Nov 2020 16:27:28 +0000 Subject: [PATCH 04/21] screens in DB --- .../server/src/api/controllers/application.js | 21 +- packages/server/src/api/controllers/page.js | 5 +- packages/server/src/api/controllers/screen.js | 28 ++- packages/server/src/api/routes/pages.new.js | 2 +- packages/server/src/api/routes/screen.js | 4 +- packages/server/src/constants/pages.js | 216 ++++++++++++++++++ packages/server/src/constants/screens.js | 103 +++++++++ packages/server/src/db/utils.js | 7 + .../utilities/appDirectoryTemplate/plugins.js | 1 - 9 files changed, 373 insertions(+), 14 deletions(-) create mode 100644 packages/server/src/constants/pages.js create mode 100644 packages/server/src/constants/screens.js delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/plugins.js diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index dc6aecff12..0cc9b7730f 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -22,6 +22,8 @@ const { const { downloadExtractComponentLibraries, } = require("../../utilities/createAppPackage") +const PAGES = require("../../constants/pages") +const { HOME_SCREEN } = require("../../constants/screens") const APP_PREFIX = DocumentTypes.APP + SEPARATOR @@ -157,11 +159,20 @@ const createEmptyAppPackage = async (ctx, app) => { ctx.throw(400, "App folder already exists for this application") } - await fs.ensureDir(join(newAppFolder, "pages", "main", "screens"), 0o777) - await fs.ensureDir( - join(newAppFolder, "pages", "unauthenticated", "screens"), - 0o777 - ) + // await fs.ensureDir(join(newAppFolder, "pages", "main", "screens"), 0o777) + // await fs.ensureDir( + // join(newAppFolder, "pages", "unauthenticated", "screens"), + // 0o777 + // ) + + // TODO: write the main and unauthenticated JSON to couch + // const writes = [] + // for (let pageName in PAGES) { + // PAGES[pageName]._id = generatePageID() + // writes.push({ + + // }) + // } await copy(templateFolder, newAppFolder) diff --git a/packages/server/src/api/controllers/page.js b/packages/server/src/api/controllers/page.js index be04a4421e..4707a66193 100644 --- a/packages/server/src/api/controllers/page.js +++ b/packages/server/src/api/controllers/page.js @@ -11,7 +11,7 @@ exports.save = async function(ctx) { await buildPage( ctx.config, ctx.user.appId, - ctx.params.pageName, + ctx.params.pageId, ctx.request.body ) @@ -29,5 +29,6 @@ exports.save = async function(ctx) { // } appPackage.page._id = appPackage.page._id || generatePageID() await db.put(appPackage.page) - ctx.response.status = 200 + ctx.message = "Page saved successfully." + ctx.status = 200 } diff --git a/packages/server/src/api/controllers/screen.js b/packages/server/src/api/controllers/screen.js index e8e7238257..6500ea48f3 100644 --- a/packages/server/src/api/controllers/screen.js +++ b/packages/server/src/api/controllers/screen.js @@ -4,9 +4,18 @@ * for routes and controllers. */ const CouchDB = require("../../db") +const { getScreenParams, generateScreenID } = require("../../db/utils") exports.fetch = async ctx => { - ctx.throw(501) + const db = new CouchDB(ctx.user.appId) + + const screens = await db.allDocs( + getScreenParams(ctx.params.pageId, null, { + include_docs: true, + }) + ) + + ctx.body = screens.response.rows } exports.create = async ctx => { @@ -28,9 +37,22 @@ exports.create = async ctx => { } exports.save = async ctx => { - ctx.throw(501) + const appId = ctx.user.appId + const db = new CouchDB(appId) + const screen = ctx.request.body + + if (!screen._id) { + screen._id = generateScreenID() + } + + const response = await db.put(screen) + + ctx.message = `Screen ${screen.name} saved.` + ctx.body = response } exports.destroy = async ctx => { - ctx.throw(501) + const db = new CouchDB(ctx.user.appId) + await db.remove(ctx.params.screenId, ctx.params.revId) + ctx.message = "Screen deleted successfully" } diff --git a/packages/server/src/api/routes/pages.new.js b/packages/server/src/api/routes/pages.new.js index 8aa95638ae..e87ac49e9c 100644 --- a/packages/server/src/api/routes/pages.new.js +++ b/packages/server/src/api/routes/pages.new.js @@ -26,7 +26,7 @@ function generateSaveValidation() { } router.post( - "/api/pages/:pageName", + "/api/pages/:pageId", authorized(BUILDER), generateSaveValidation(), controller.save diff --git a/packages/server/src/api/routes/screen.js b/packages/server/src/api/routes/screen.js index 60e29bf363..23da51e616 100644 --- a/packages/server/src/api/routes/screen.js +++ b/packages/server/src/api/routes/screen.js @@ -6,8 +6,8 @@ const { BUILDER } = require("../../utilities/accessLevels") const router = Router() router - .get("/api/screens", authorized(BUILDER), controller.fetch) - .post("/api/screens", authorized(BUILDER), controller.save) + .get("/api/:pageId/screens", authorized(BUILDER), controller.fetch) + .post("/api/:pageId/screens", authorized(BUILDER), controller.save) .delete("/api/:screenId/:revId", authorized(BUILDER), controller.destroy) module.exports = router diff --git a/packages/server/src/constants/pages.js b/packages/server/src/constants/pages.js new file mode 100644 index 0000000000..72d6d263a6 --- /dev/null +++ b/packages/server/src/constants/pages.js @@ -0,0 +1,216 @@ +const MAIN = { + 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: [], + }, + uiFunctions: "", +} + +const UNAUTHENTICATED = { + 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: [], + }, + uiFunctions: "", +} + +module.exports = { MAIN, UNAUTHENTICATED } diff --git a/packages/server/src/constants/screens.js b/packages/server/src/constants/screens.js new file mode 100644 index 0000000000..f9a0fb68dc --- /dev/null +++ b/packages/server/src/constants/screens.js @@ -0,0 +1,103 @@ +exports.HOME_SCREEN = { + 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/db/utils.js b/packages/server/src/db/utils.js index b327a5ad12..a95d6a13be 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -200,6 +200,13 @@ exports.getPageParams = (pageId = null, otherProps = {}) => { return getDocParams(DocumentTypes.PAGE, pageId, otherProps) } +/** + * Gets parameters for retrieving screens for a particular page, this is a utility function for the getDocParams function. + */ +exports.getScreenParams = (pageId = null, otherProps = {}) => { + return getDocParams(DocumentType.SCREEN, pageId, otherProps) +} + /** * Gets parameters for retrieving a webhook, this is a utility function for the getDocParams function. */ diff --git a/packages/server/src/utilities/appDirectoryTemplate/plugins.js b/packages/server/src/utilities/appDirectoryTemplate/plugins.js deleted file mode 100644 index 44368bf6ec..0000000000 --- a/packages/server/src/utilities/appDirectoryTemplate/plugins.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = () => ({}) From 0665e28ca39a957bb96dcf2cd8b9f867317f68e4 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Tue, 3 Nov 2020 17:42:54 +0000 Subject: [PATCH 05/21] Updates to pages so that they are written to DB and retrieved correctly. --- .../server/src/api/controllers/application.js | 101 ++++++++++-------- packages/server/src/constants/pages.js | 9 +- packages/server/src/db/utils.js | 16 +-- 3 files changed, 71 insertions(+), 55 deletions(-) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 0cc9b7730f..811ccabc6d 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -18,12 +18,14 @@ const { SEPARATOR, getPageParams, generatePageID, + generateScreenID, } = require("../../db/utils") const { downloadExtractComponentLibraries, } = require("../../utilities/createAppPackage") -const PAGES = require("../../constants/pages") +const { MAIN, UNAUTHENTICATED, PageTypes } = require("../../constants/pages") const { HOME_SCREEN } = require("../../constants/screens") +const { cloneDeep } = require("lodash/fp") const APP_PREFIX = DocumentTypes.APP + SEPARATOR @@ -69,17 +71,24 @@ exports.fetch = async function(ctx) { exports.fetchAppPackage = async function(ctx) { const db = new CouchDB(ctx.params.appId) const application = await db.get(ctx.params.appId) - // ctx.body = await getPackageForBuilder(application) - const pages = await db.allDocs( + let pages = await db.allDocs( getPageParams(null, { include_docs: true, }) ) + pages = pages.rows.map(row => row.doc) + const mainPage = pages.filter(page => page.name === PageTypes.MAIN)[0] + const unauthPage = pages.filter( + page => page.name === PageTypes.UNAUTHENTICATED + )[0] ctx.body = { application, - pages, + pages: { + main: mainPage, + unauthenticated: unauthPage, + }, } setBuilderToken(ctx, ctx.params.appId, application.version) @@ -165,15 +174,6 @@ const createEmptyAppPackage = async (ctx, app) => { // 0o777 // ) - // TODO: write the main and unauthenticated JSON to couch - // const writes = [] - // for (let pageName in PAGES) { - // PAGES[pageName]._id = generatePageID() - // writes.push({ - - // }) - // } - await copy(templateFolder, newAppFolder) // this line allows full permission on copied files @@ -201,49 +201,58 @@ const createEmptyAppPackage = async (ctx, app) => { await copy(templatePageDefinitions, join(appsFolder, app._id, "pages")) } - const mainJson = await updateJsonFile( - join(appsFolder, app._id, "pages", "main", "page.json"), - app - ) + // const mainJson = await updateJsonFile( + // join(appsFolder, app._id, "pages", "main", "page.json"), + // app + // ) + // + // mainJson._id = generatePageID() + // await db.put(mainJson) - mainJson._id = generatePageID() - await db.put(mainJson) - - await buildPage(app._id, "main", { - page: mainJson, - screens: await loadScreens(newAppFolder, "main"), - }) - - const unauthenticatedJson = await updateJsonFile( - join(appsFolder, app._id, "pages", "unauthenticated", "page.json"), - app - ) + // const unauthenticatedJson = await updateJsonFile( + // join(appsFolder, app._id, "pages", "unauthenticated", "page.json"), + // app + // ) // Write to couch - unauthenticatedJson._id = generatePageID() - await db.put(unauthenticatedJson) + // unauthenticatedJson._id = generatePageID() + // await db.put(unauthenticatedJson) + const mainPage = cloneDeep(MAIN) + mainPage._id = generatePageID() + mainPage.title = app.name + const unauthPage = cloneDeep(UNAUTHENTICATED) + unauthPage._id = generatePageID() + unauthPage.title = app.name + const homeScreen = cloneDeep(HOME_SCREEN) + homeScreen._id = generateScreenID(mainPage._id) + await db.bulkDocs([mainPage, unauthPage, homeScreen]) + + await buildPage(app._id, "main", { + page: mainPage, + screens: [homeScreen], + }) await buildPage(app._id, "unauthenticated", { - page: unauthenticatedJson, - screens: await loadScreens(newAppFolder, "unauthenticated"), + page: unauthPage, + screens: [], }) return newAppFolder } -const loadScreens = async (appFolder, page) => { - const screensFolder = join(appFolder, "pages", page, "screens") - - const screenFiles = (await fs.readdir(screensFolder)).filter(s => - s.endsWith(".json") - ) - - let screens = [] - for (let file of screenFiles) { - screens.push(await fs.readJSON(join(screensFolder, file))) - } - return screens -} +// const loadScreens = async (appFolder, page) => { +// const screensFolder = join(appFolder, "pages", page, "screens") +// +// const screenFiles = (await fs.readdir(screensFolder)).filter(s => +// s.endsWith(".json") +// ) +// +// let screens = [] +// for (let file of screenFiles) { +// screens.push(await fs.readJSON(join(screensFolder, file))) +// } +// return screens +// } const updateJsonFile = async (filePath, app) => { const json = await readFile(filePath, "utf8") diff --git a/packages/server/src/constants/pages.js b/packages/server/src/constants/pages.js index 72d6d263a6..eb52726341 100644 --- a/packages/server/src/constants/pages.js +++ b/packages/server/src/constants/pages.js @@ -1,8 +1,14 @@ +const PageTypes = { + MAIN: "main", + UNAUTHENTICATED: "unauthenticated", +} + const MAIN = { componentLibraries: ["@budibase/standard-components"], title: "{{ name }}", favicon: "./_shared/favicon.png", stylesheets: [], + name: PageTypes.MAIN, props: { _id: "private-master-root", _component: "@budibase/standard-components/container", @@ -148,6 +154,7 @@ const UNAUTHENTICATED = { title: "{{ name }}", favicon: "./_shared/favicon.png", stylesheets: [], + name: PageTypes.UNAUTHENTICATED, props: { _id: "public-master-root", _component: "@budibase/standard-components/container", @@ -213,4 +220,4 @@ const UNAUTHENTICATED = { uiFunctions: "", } -module.exports = { MAIN, UNAUTHENTICATED } +module.exports = { MAIN, UNAUTHENTICATED, PageTypes } diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index a95d6a13be..6c5beee009 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -177,14 +177,6 @@ exports.generateWebhookID = () => { return `${DocumentTypes.WEBHOOK}${SEPARATOR}${newid()}` } -/** - * Generates a new screen ID. - * @returns {string} The new screen ID which the screen doc can be stored under. - */ -exports.generateScreenID = () => { - return `${DocumentTypes.SCREEN}${SEPARATOR}${newid()}` -} - /** * Generates a new page ID. * @returns {string} The new page ID which the page doc can be stored under. @@ -200,6 +192,14 @@ exports.getPageParams = (pageId = null, otherProps = {}) => { return getDocParams(DocumentTypes.PAGE, pageId, otherProps) } +/** + * Generates a new screen ID. + * @returns {string} The new screen ID which the screen doc can be stored under. + */ +exports.generateScreenID = pageId => { + return `${DocumentTypes.SCREEN}${SEPARATOR}${pageId}${SEPARATOR}${newid()}` +} + /** * Gets parameters for retrieving screens for a particular page, this is a utility function for the getDocParams function. */ From c9a1bf1940a9c38b551cf6de86b495a8eeee12ca Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Wed, 4 Nov 2020 12:36:38 +0000 Subject: [PATCH 06/21] Main work to get screens into the DB, fixing up issue with async page updates not being handled in order. --- .../builder/src/builderStore/store/index.js | 81 +++++++++---------- .../builder/src/builderStore/storeUtils.js | 19 +++-- .../server/src/api/controllers/application.js | 1 + packages/server/src/api/controllers/page.js | 25 ++---- packages/server/src/api/controllers/screen.js | 36 ++++----- packages/server/src/api/index.js | 4 + packages/server/src/api/routes/index.js | 4 +- packages/server/src/api/routes/pages.new.js | 27 +------ packages/server/src/api/routes/screen.js | 30 ++++++- packages/server/src/db/utils.js | 2 +- 10 files changed, 107 insertions(+), 122 deletions(-) diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 897dbd96d5..9f1ce9e555 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -77,23 +77,18 @@ export const getStore = () => { export default getStore const setPackage = (store, initial) => async pkg => { - const [main_screens, unauth_screens] = await Promise.all([ - api - .get(`/_builder/api/${pkg.application._id}/pages/main/screens`) - .then(r => r.json()), - api - .get(`/_builder/api/${pkg.application._id}/pages/unauthenticated/screens`) - .then(r => r.json()), - ]) + 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: Object.values(main_screens), + _screens: mainScreens, }, unauthenticated: { ...pkg.pages.unauthenticated, - _screens: Object.values(unauth_screens), + _screens: unauthScreens, }, } @@ -107,7 +102,7 @@ const setPackage = (store, initial) => async pkg => { regenerateCssForScreen(screen) } - await api.post(`/_builder/api/${pkg.application._id}/pages/${name}`, { + await api.post(`/api/pages/${page._id}`, { page: { componentLibraries: pkg.application.componentLibraries, ...page, @@ -115,8 +110,8 @@ const setPackage = (store, initial) => async pkg => { screens: page._screens, }) } - generateInitialPageCss("main") - generateInitialPageCss("unauthenticated") + await generateInitialPageCss("main") + await generateInitialPageCss("unauthenticated") pkg.justCreated = false } @@ -128,8 +123,8 @@ const setPackage = (store, initial) => async pkg => { initial.pages = pkg.pages initial.hasAppPackage = true initial.screens = [ - ...Object.values(main_screens), - ...Object.values(unauth_screens), + ...Object.values(mainScreens), + ...Object.values(unauthScreens), ] initial.builtins = [getBuiltin("##builtin/screenslot")] initial.appInstance = pkg.application.instance @@ -139,40 +134,36 @@ const setPackage = (store, initial) => async pkg => { return initial } -const saveScreen = store => screen => { - store.update(state => { - return _saveScreen(store, state, screen) - }) -} - -const _saveScreen = async (store, s, screen) => { - const pageName = s.currentPageName || "main" - const currentPageScreens = s.pages[pageName]._screens +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 await api - .post(`/_builder/api/${s.appId}/pages/${pageName}/screen`, screen) - .then(() => { - if (currentPageScreens.includes(screen)) return + .post(`/api/${currentPage._id}/screens`, screen) + .then(() => { + if (currentPageScreens.includes(screen)) return - const screens = [...currentPageScreens, screen] + const screens = [...currentPageScreens, screen] - store.update(innerState => { - innerState.pages[pageName]._screens = screens - innerState.screens = screens - innerState.currentPreviewItem = screen - const safeProps = makePropsSafe( - innerState.components[screen.props._component], - screen.props - ) - innerState.currentComponentInfo = safeProps - screen.props = safeProps - - _savePage(innerState) - return innerState + // 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 + }) }) - }) - - return s + await savePromise } const createScreen = store => async screen => { @@ -182,7 +173,7 @@ const createScreen = store => async screen => { state.currentComponentInfo = screen.props state.currentFrontEndType = "screen" regenerateCssForCurrentScreen(state) - savePromise = _saveScreen(store, state, screen) + savePromise = saveScreen(store)(screen) return state }) await savePromise diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index b19df1976e..108bff0e63 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -3,6 +3,7 @@ import { getBuiltin, } from "components/userInterface/pagesParsing/createProps" import api from "./api" +import { store } from "builderStore" import { generate_screen_css } from "./generate_css" import { uuid } from "./uuid" import getNewComponentName from "./getNewComponentName" @@ -35,14 +36,20 @@ export const saveCurrentPreviewItem = s => ? savePage(s) : saveScreenApi(s.currentPreviewItem, s) -export const savePage = async s => { - const pageName = s.currentPageName || "main" - const page = s.pages[pageName] - await api.post(`/api/pages/${pageName}`, { - page: { componentLibraries: s.pages.componentLibraries, ...page }, - uiFunctions: s.currentPageFunctions, +export const savePage = async state => { + const pageName = state.currentPageName || "main" + const page = state.pages[pageName] + + const response = await api.post(`/api/pages/${page._id}`, { + page: { componentLibraries: state.pages.componentLibraries, ...page }, + uiFunctions: state.currentPageFunctions, screens: page._screens, + }).then(response => response.json()) + store.update(innerState => { + innerState.pages[pageName]._rev = response.rev + return innerState }) + return state } export const saveScreenApi = (screen, s) => { diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 40c59755b6..8d07e52f4e 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -140,6 +140,7 @@ exports.delete = async function(ctx) { const result = await db.destroy() // remove top level directory + // TODO: look into why this isn't a callback await fs.rmdir(join(budibaseAppsDir(), ctx.params.appId), { recursive: true, }) diff --git a/packages/server/src/api/controllers/page.js b/packages/server/src/api/controllers/page.js index 4707a66193..06d427f546 100644 --- a/packages/server/src/api/controllers/page.js +++ b/packages/server/src/api/controllers/page.js @@ -8,27 +8,12 @@ exports.save = async function(ctx) { const appPackage = ctx.request.body // TODO: rename to something more descriptive - await buildPage( - ctx.config, - ctx.user.appId, - ctx.params.pageId, - ctx.request.body - ) + await buildPage(ctx.user.appId, ctx.params.pageId, ctx.request.body) - // write the page data to couchDB - // if (pkg.page._css) { - // delete pkg.page._css - // } - - // if (pkg.page.name) { - // delete pkg.page.name - // } - - // if (pkg.page._screens) { - // delete pkg.page._screens - // } + // remove special doc props which couch will complain about + delete appPackage.page._css + delete appPackage.page._screens appPackage.page._id = appPackage.page._id || generatePageID() - await db.put(appPackage.page) - ctx.message = "Page saved successfully." + ctx.body = await db.put(appPackage.page) ctx.status = 200 } diff --git a/packages/server/src/api/controllers/screen.js b/packages/server/src/api/controllers/screen.js index 6500ea48f3..fa7142a42a 100644 --- a/packages/server/src/api/controllers/screen.js +++ b/packages/server/src/api/controllers/screen.js @@ -10,7 +10,19 @@ exports.fetch = async ctx => { const db = new CouchDB(ctx.user.appId) const screens = await db.allDocs( - getScreenParams(ctx.params.pageId, null, { + getScreenParams(null, { + include_docs: true, + }) + ) + + ctx.body = screens.rows.map(element => element.doc) +} + +exports.find = async ctx => { + const db = new CouchDB(ctx.user.appId) + + const screens = await db.allDocs( + getScreenParams(ctx.params.pageId, { include_docs: true, }) ) @@ -18,33 +30,15 @@ exports.fetch = async ctx => { ctx.body = screens.response.rows } -exports.create = async ctx => { - const db = new CouchDB(ctx.user.appId) - const screen = { - // name: ctx.request.body.name, - // _rev: ctx.request.body._rev, - // permissions: ctx.request.body.permissions || [], - // _id: generateAccessLevelID(), - // type: "accesslevel", - } - - const response = await db.put(screen) - ctx.body = { - ...screen, - ...response, - } - ctx.message = `Screen '${screen.name}' created successfully.` -} - exports.save = async ctx => { const appId = ctx.user.appId const db = new CouchDB(appId) const screen = ctx.request.body if (!screen._id) { - screen._id = generateScreenID() + screen._id = generateScreenID(ctx.params.pageId) } - + delete screen._css const response = await db.put(screen) ctx.message = `Screen ${screen.name} saved.` diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 0fbd65501b..631e5a18e4 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -7,6 +7,7 @@ const { isDev } = require("../utilities") const { authRoutes, pageRoutes, + screenRoutes, userRoutes, deployRoutes, applicationRoutes, @@ -97,6 +98,9 @@ router.use(templatesRoutes.allowedMethods()) router.use(pageRoutes.routes()) router.use(pageRoutes.allowedMethods()) +router.use(screenRoutes.routes()) +router.use(screenRoutes.allowedMethods()) + router.use(applicationRoutes.routes()) router.use(applicationRoutes.allowedMethods()) diff --git a/packages/server/src/api/routes/index.js b/packages/server/src/api/routes/index.js index 0025c5fabf..599edaa3e2 100644 --- a/packages/server/src/api/routes/index.js +++ b/packages/server/src/api/routes/index.js @@ -1,5 +1,6 @@ const authRoutes = require("./auth") -const pageRoutes = require("./pages") +const pageRoutes = require("./pages.new") +const screenRoutes = require("./screen") const userRoutes = require("./user") const applicationRoutes = require("./application") const tableRoutes = require("./table") @@ -19,6 +20,7 @@ module.exports = { deployRoutes, authRoutes, pageRoutes, + screenRoutes, userRoutes, applicationRoutes, rowRoutes, diff --git a/packages/server/src/api/routes/pages.new.js b/packages/server/src/api/routes/pages.new.js index e87ac49e9c..1ec01dc780 100644 --- a/packages/server/src/api/routes/pages.new.js +++ b/packages/server/src/api/routes/pages.new.js @@ -1,35 +1,10 @@ const Router = require("@koa/router") -const joiValidator = require("../../middleware/joi-validator") -const Joi = require("joi") const authorized = require("../../middleware/authorized") const { BUILDER } = require("../../utilities/accessLevels") const controller = require("../controllers/page") const router = Router() -function generateSaveValidation() { - // prettier-ignore - return joiValidator.body(Joi.object({ - _css: Joi.string().allow(""), - name: Joi.string().required(), - route: Joi.string().required(), - props: Joi.object({ - _id: Joi.string().required(), - _component: Joi.string().required(), - _children: Joi.array().required(), - _instanceName: Joi.string().required(), - _styles: Joi.object().required(), - type: Joi.string().optional(), - table: Joi.string().optional(), - }).required().unknown(true), - }).unknown(true)) -} - -router.post( - "/api/pages/:pageId", - authorized(BUILDER), - generateSaveValidation(), - controller.save -) +router.post("/api/pages/:pageId", authorized(BUILDER), controller.save) module.exports = router diff --git a/packages/server/src/api/routes/screen.js b/packages/server/src/api/routes/screen.js index 23da51e616..e36a09d610 100644 --- a/packages/server/src/api/routes/screen.js +++ b/packages/server/src/api/routes/screen.js @@ -2,12 +2,38 @@ const Router = require("@koa/router") const controller = require("../controllers/screen") const authorized = require("../../middleware/authorized") const { BUILDER } = require("../../utilities/accessLevels") +const joiValidator = require("../../middleware/joi-validator") +const Joi = require("joi") const router = Router() +function generateSaveValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + _css: Joi.string().allow(""), + name: Joi.string().required(), + route: Joi.string().required(), + props: Joi.object({ + _id: Joi.string().required(), + _component: Joi.string().required(), + _children: Joi.array().required(), + _instanceName: Joi.string().required(), + _styles: Joi.object().required(), + type: Joi.string().optional(), + table: Joi.string().optional(), + }).required().unknown(true), + }).unknown(true)) +} + router - .get("/api/:pageId/screens", authorized(BUILDER), controller.fetch) - .post("/api/:pageId/screens", authorized(BUILDER), controller.save) + .get("/api/screens", authorized(BUILDER), controller.fetch) + .get("/api/:pageId/screens", authorized(BUILDER), controller.find) + .post( + "/api/:pageId/screens", + authorized(BUILDER), + generateSaveValidation(), + controller.save + ) .delete("/api/:screenId/:revId", authorized(BUILDER), controller.destroy) module.exports = router diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 6c5beee009..a213dc9066 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -204,7 +204,7 @@ exports.generateScreenID = pageId => { * Gets parameters for retrieving screens for a particular page, this is a utility function for the getDocParams function. */ exports.getScreenParams = (pageId = null, otherProps = {}) => { - return getDocParams(DocumentType.SCREEN, pageId, otherProps) + return getDocParams(DocumentTypes.SCREEN, pageId, otherProps) } /** From 6bc184f0d61ef9814dda2d6858275ff828238f27 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Wed, 4 Nov 2020 14:05:11 +0000 Subject: [PATCH 07/21] Updating screens API to be prefixed with /api/screens --- packages/builder/src/builderStore/store/index.js | 4 ++-- packages/server/src/api/routes/screen.js | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 9f1ce9e555..44806e09c3 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -142,7 +142,7 @@ const saveScreen = store => async screen => { let savePromise await api - .post(`/api/${currentPage._id}/screens`, screen) + .post(`/api/screens/${currentPage._id}`, screen) .then(() => { if (currentPageScreens.includes(screen)) return @@ -262,7 +262,7 @@ const deleteScreens = store => (screens, pageName = null) => { state.pages[pageName]._screens = state.pages[pageName]._screens.filter( scr => scr.name !== screen.name ) - api.delete(`/_builder/api/pages/${pageName}/screens/${screen.name}`) + api.delete(`/api/screens/${screen._id}/${screen._rev}`) } return state }) diff --git a/packages/server/src/api/routes/screen.js b/packages/server/src/api/routes/screen.js index e36a09d610..407bbd1a94 100644 --- a/packages/server/src/api/routes/screen.js +++ b/packages/server/src/api/routes/screen.js @@ -27,13 +27,17 @@ function generateSaveValidation() { router .get("/api/screens", authorized(BUILDER), controller.fetch) - .get("/api/:pageId/screens", authorized(BUILDER), controller.find) + .get("/api/screens/:pageId", authorized(BUILDER), controller.find) .post( - "/api/:pageId/screens", + "/api/screens/:pageId", authorized(BUILDER), generateSaveValidation(), controller.save ) - .delete("/api/:screenId/:revId", authorized(BUILDER), controller.destroy) + .delete( + "/api/screens/:screenId/:revId", + authorized(BUILDER), + controller.destroy + ) module.exports = router From 333844a1f05c5c6bf12df76559992c78dc688345 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 4 Nov 2020 16:13:50 +0000 Subject: [PATCH 08/21] feature parity with current pages, screens and store setup. Starting main bb store refactor --- packages/builder/src/builderStore/index.js | 2 + .../src/builderStore/store/frontend.js | 483 ++++++++++++++++++ .../builder/src/builderStore/store/index.js | 118 ++--- .../builder/src/builderStore/storeUtils.js | 41 +- .../userInterface/ScreenDropdownMenu.svelte | 2 + .../pagesParsing/searchComponents.js | 7 +- .../server/src/api/controllers/application.js | 2 + packages/server/src/api/controllers/screen.js | 6 +- packages/server/src/api/routes/index.js | 2 +- packages/server/src/api/routes/pages.js | 102 +--- packages/server/src/api/routes/pages.new.js | 10 - packages/server/src/api/routes/pages.old.js | 108 ++++ packages/server/src/constants/pages.js | 2 - .../appDirectoryTemplate/pages/main/page.json | 3 +- .../pages/unauthenticated/page.json | 3 +- .../server/src/utilities/builder/buildPage.js | 5 +- .../server/src/utilities/builder/getPages.js | 34 +- .../server/src/utilities/builder/index.js | 97 ++-- 18 files changed, 725 insertions(+), 302 deletions(-) create mode 100644 packages/builder/src/builderStore/store/frontend.js delete mode 100644 packages/server/src/api/routes/pages.new.js create mode 100644 packages/server/src/api/routes/pages.old.js diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 6317640955..9a93528c33 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -1,10 +1,12 @@ 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 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 new file mode 100644 index 0000000000..8f908ac568 --- /dev/null +++ b/packages/builder/src/builderStore/store/frontend.js @@ -0,0 +1,483 @@ +import { writable, get } from "svelte/store" +import { cloneDeep } from "lodash/fp" +import { + createProps, + makePropsSafe, + getBuiltin, +} from "components/userInterface/pagesParsing/createProps" +import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents" +import { backendUiStore } from "builderStore" +import { generate_screen_css } from "../generate_css" +import { fetchComponentLibDefinitions } from "../loadComponentLibraries" +import api from "../api" +import { DEFAULT_PAGES_OBJECT } from "../../constants" +import getNewComponentName from "../getNewComponentName" +import analytics from "analytics" +import { + getParent, + // saveScreenApi as _saveScreenApi, + generateNewIdsForComponent, + getComponentDefinition, +} from "../storeUtils" + +const INITIAL_FRONTEND_STATE = { + 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: "", +} + +export const getFrontendStore = () => { + const store = writable({ ...INITIAL_FRONTEND_STATE }) + + store.actions = { + // TODO: REFACTOR + initialise: 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) { + for (let pageName of ["main", "unauthenticated"]) { + const page = pkg.pages[pageName] + store.actions.screens.regenerateCss(page) + for (let screen of page._screens) { + store.actions.screens.regenerateCss(screen) + } + + await api.post(`/api/pages/${page._id}`, { + page: { + componentLibraries: pkg.application.componentLibraries, + ...page, + }, + 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) + } + }, + // store.setScreenType + selectPageOrScreen: 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 + }) + }, + screens: { + select: screenName => { + store.update(state => { + const screen = getExactComponent(state.screens, screenName, true) + state.currentPreviewItem = screen + state.currentFrontEndType = "screen" + state.currentView = "detail" + + store.actions.screens.regenerateCssForCurrentScreen() + // this.regenerateCssForCurrentScreen() + // regenerateCssForCurrentScreen(s) + const safeProps = makePropsSafe( + state.components[screen.props._component], + screen.props + ) + screen.props = safeProps + state.currentComponentInfo = safeProps + return state + }) + }, + create: async screen => { + let savePromise + store.update(state => { + state.currentPreviewItem = screen + state.currentComponentInfo = screen.props + state.currentFrontEndType = "screen" + + if (state.currentPreviewItem) { + store.actions.screens.regenerateCss(state.currentPreviewItem) + } + + savePromise = store.actions.screens.save(screen) + return state + }) + + await savePromise + }, + save: 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 = store.actions.pages.save() + return state + }) + await savePromise + }, + regenerateCss: screen => { + screen._css = generate_screen_css([screen.props]) + }, + regenerateCssForCurrentScreen: () => { + const { currentPreviewItem } = get(store) + if (currentPreviewItem) { + store.actions.screens.regenerateCss(currentPreviewItem) + } + }, + delete: async (screensToDelete, pageName) => { + let deletePromise + + store.update(state => { + if (pageName == null) { + pageName = state.pages.main.name + } + for (let screenToDelete of Array.isArray(screenToDelete) + ? screenToDelete + : [screenToDelete]) { + state.screens = state.screens.filter( + screen => screen.name !== screenToDelete.name + ) + // Remove screen from current page as well + // TODO: Should be done server side + state.pages[pageName]._screens = state.pages[ + pageName + ]._screens.filter(scr => scr.name !== screenToDelete.name) + deletePromise = api.delete( + `/api/screens/${screenToDelete._id}/${screenToDelete._rev}` + ) + } + return state + }) + await deletePromise + }, + }, + preview: { + // _saveCurrentPreviewItem + saveSelected: () => { + const state = get(store) + state.currentFrontEndType === "page" + ? store.actions.pages.save() + : store.actions.screens.save(state.currentPreviewItem) + }, + pages: { + select: 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] + store.actions.screens.regenerateCssForCurrentScreen() + + for (let screen of state.screens) { + screen._css = generate_screen_css([screen.props]) + } + + 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) + } + } + + // 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 + }, + }, + }, + } +} diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 44806e09c3..5631ef00c5 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -20,7 +20,7 @@ import { walkProps, savePage as _savePage, saveCurrentPreviewItem as _saveCurrentPreviewItem, - saveScreenApi as _saveScreenApi, + // saveScreenApi as _saveScreenApi, regenerateCssForCurrentScreen, regenerateCssForScreen, generateNewIdsForComponent, @@ -58,7 +58,7 @@ export const getStore = () => { store.setCurrentPage = setCurrentPage(store) store.createLink = createLink(store) store.createScreen = createScreen(store) - store.savePage = savePage(store) + // store.savePage = savePage(store) store.addChildComponent = addChildComponent(store) store.selectComponent = selectComponent(store) store.setComponentProp = setComponentProp(store) @@ -66,9 +66,6 @@ export const getStore = () => { store.setComponentStyle = setComponentStyle(store) store.setScreenType = setScreenType(store) store.getPathToComponent = getPathToComponent(store) - store.addTemplatedComponent = addTemplatedComponent(store) - store.setMetadataProp = setMetadataProp(store) - store.editPageOrScreen = editPageOrScreen(store) store.pasteComponent = pasteComponent(store) store.storeComponentForCopy = storeComponentForCopy(store) return store @@ -79,8 +76,12 @@ 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)) + 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, @@ -141,28 +142,30 @@ const saveScreen = store => async screen => { const currentPageScreens = currentPage._screens let savePromise - await api - .post(`/api/screens/${currentPage._id}`, screen) - .then(() => { - if (currentPageScreens.includes(screen)) return + const response = await api.post(`/api/screens/${currentPage._id}`, screen) + const json = await response.json() - const screens = [...currentPageScreens, screen] + if (currentPageScreens.includes(screen)) return - // 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 - }) - }) + 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 } @@ -268,17 +271,17 @@ const deleteScreens = store => (screens, pageName = null) => { }) } -const savePage = store => async page => { - store.update(state => { - if (state.currentFrontEndType !== "page" || !state.currentPageName) { - 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 - }) -} +// state.pages[state.currentPageName] = page +// _savePage(state) +// return state +// }) +// } const setCurrentPage = store => pageName => { store.update(state => { @@ -365,7 +368,7 @@ const addChildComponent = store => (componentToAdd, presetProps = {}) => { state.currentFrontEndType === "page" ? _savePage(state) - : _saveScreenApi(state.currentPreviewItem, state) + : saveScreen(state.currentPreviewItem) state.currentView = "component" state.currentComponentInfo = newComponent.props @@ -376,26 +379,6 @@ const addChildComponent = store => (componentToAdd, presetProps = {}) => { }) } -/** - * @param {string} props - props to add, as child of current component - */ - -const addTemplatedComponent = store => props => { - store.update(state => { - walkProps(props, p => { - p._id = uuid() - }) - state.currentComponentInfo._children = state.currentComponentInfo._children.concat( - props - ) - regenerateCssForCurrentScreen(state) - - _saveCurrentPreviewItem(state) - - return state - }) -} - const selectComponent = store => component => { store.update(state => { return _selectComponent(state, component) @@ -440,6 +423,7 @@ const setComponentStyle = store => (type, name, value) => { }) } +// Select page or screen const setScreenType = store => type => { store.update(state => { state.currentFrontEndType = type @@ -456,17 +440,6 @@ const setScreenType = store => type => { }) } -const editPageOrScreen = store => (key, value, setOnComponent = false) => { - store.update(state => { - setOnComponent - ? (state.currentPreviewItem.props[key] = value) - : (state.currentPreviewItem[key] = value) - _saveCurrentPreviewItem(state) - - return state - }) -} - const getPathToComponent = store => component => { // Gets all the components to needed to construct a path. const tempStore = get(store) @@ -498,13 +471,6 @@ const getPathToComponent = store => component => { return path } -const setMetadataProp = store => (name, prop) => { - store.update(s => { - s.currentPreviewItem[name] = prop - return s - }) -} - const storeComponentForCopy = store => (component, cut = false) => { store.update(s => { const copiedComponent = cloneDeep(component) diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 108bff0e63..3c85e611dd 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -34,17 +34,18 @@ export const getParent = (rootProps, child) => { export const saveCurrentPreviewItem = s => s.currentFrontEndType === "page" ? savePage(s) - : saveScreenApi(s.currentPreviewItem, s) + : store.saveScreen(s.currentPreviewItem) export const savePage = async state => { const pageName = state.currentPageName || "main" const page = state.pages[pageName] - const response = await api.post(`/api/pages/${page._id}`, { - page: { componentLibraries: state.pages.componentLibraries, ...page }, - uiFunctions: state.currentPageFunctions, - screens: page._screens, - }).then(response => response.json()) + const response = await api + .post(`/api/pages/${page._id}`, { + page: { componentLibraries: state.pages.componentLibraries, ...page }, + screens: page._screens, + }) + .then(response => response.json()) store.update(innerState => { innerState.pages[pageName]._rev = response.rev return innerState @@ -52,25 +53,19 @@ export const savePage = async state => { return state } -export const saveScreenApi = (screen, s) => { - api - .post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen) - .then(() => savePage(s)) -} +// export const saveScreenApi = async (screen, state) => { +// const currentPage = state.pages[state.currentPageName] +// const response = await api.post(`/api/screens/${currentPage._id}`, screen) +// const json = await response.json() -export const renameCurrentScreen = (newname, state) => { - const oldname = state.currentPreviewItem.props._instanceName - state.currentPreviewItem.props._instanceName = newname +// store.update(innerState => { +// // TODO: need to update pages in here +// // innerState.pages[pageName]._rev = response.rev +// return innerState +// }) - api.patch( - `/_builder/api/${state.appId}/pages/${state.currentPageName}/screen`, - { - oldname, - newname, - } - ) - return state -} +// await savePage(state) +// } export const walkProps = (props, action, cancelToken = null) => { cancelToken = cancelToken || { cancelled: false } diff --git a/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte b/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte index 75e2483f31..9f42a9546b 100644 --- a/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte @@ -1,6 +1,7 @@
-
+
+ +
{/if} diff --git a/packages/builder/src/components/userInterface/ComponentSelectionList.svelte b/packages/builder/src/components/userInterface/ComponentSelectionList.svelte index f43faf033d..9609008dbc 100644 --- a/packages/builder/src/components/userInterface/ComponentSelectionList.svelte +++ b/packages/builder/src/components/userInterface/ComponentSelectionList.svelte @@ -25,8 +25,8 @@ } const onComponentChosen = component => { - store.addChildComponent(component._component, component.presetProps) - const path = store.getPathToComponent($store.currentComponentInfo) + store.actions.components.create(component._component, component.presetProps) + const path = store.actions.components.findRoute($store.currentComponentInfo) $goto(`./:page/:screen/${path}`) close() } @@ -39,9 +39,13 @@ class="category" on:click={() => onCategoryChosen(category, idx)} class:active={idx === selectedIndex}> - {#if category.icon}{/if} + {#if category.icon} + + {/if} {category.name} - {#if category.isCategory}{/if} + {#if category.isCategory} + + {/if}
{/each} diff --git a/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte b/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte index 48fe72f8d6..c69d5f7b9b 100644 --- a/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte +++ b/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte @@ -24,15 +24,18 @@ let componentToDelete = "" const normalizedName = name => - pipe(name, [ - trimCharsStart("./"), - trimCharsStart("~/"), - trimCharsStart("../"), - trimChars(" "), - ]) + pipe( + name, + [ + trimCharsStart("./"), + trimCharsStart("~/"), + trimCharsStart("../"), + trimChars(" "), + ] + ) const changeScreen = screen => { - store.setCurrentScreen(screen.props._instanceName) + store.actions.screens.select(screen.props._instanceName) $goto(`./:page/${screen.props._instanceName}`) } diff --git a/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte b/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte index d854c9b906..a9f390900a 100644 --- a/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte +++ b/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte @@ -35,15 +35,19 @@ const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1) const get_name = s => (!s ? "" : last(s.split("/"))) - const get_capitalised_name = name => pipe(name, [get_name, capitalise]) + const get_capitalised_name = name => + pipe( + name, + [get_name, capitalise] + ) const isScreenslot = name => name === "##builtin/screenslot" const selectComponent = component => { // Set current component - store.selectComponent(component) + store.actions.components.select(component) // Get ID path - const path = store.getPathToComponent(component) + const path = store.actions.components.findRoute(component) // Go to correct URL $goto(`./:page/:screen/${path}`) @@ -96,8 +100,8 @@ const drop = () => { if ($dragDropStore.targetComponent !== $dragDropStore.componentToDrop) { - store.storeComponentForCopy($dragDropStore.componentToDrop, true) - store.pasteComponent( + store.actions.components.copy($dragDropStore.componentToDrop, true) + store.actions.components.paste( $dragDropStore.targetComponent, $dragDropStore.dropPosition ) diff --git a/packages/builder/src/components/userInterface/PageLayout.svelte b/packages/builder/src/components/userInterface/PageLayout.svelte index c6ac3b5290..9837e6df35 100644 --- a/packages/builder/src/components/userInterface/PageLayout.svelte +++ b/packages/builder/src/components/userInterface/PageLayout.svelte @@ -22,7 +22,7 @@ } const setCurrentScreenToLayout = () => { - store.setScreenType("page") + store.actions.selectPageOrScreen("page") $goto("./:page/page-layout") } diff --git a/packages/builder/src/components/userInterface/PagesList.svelte b/packages/builder/src/components/userInterface/PagesList.svelte index c26004e44d..477b390149 100644 --- a/packages/builder/src/components/userInterface/PagesList.svelte +++ b/packages/builder/src/components/userInterface/PagesList.svelte @@ -2,8 +2,8 @@ import { params, goto } from "@sveltech/routify" import { store } from "builderStore" - const getPage = (s, name) => { - const props = s.pages[name] + const getPage = (state, name) => { + const props = state.pages[name] return { name, props } } @@ -18,11 +18,12 @@ }, ] + console.log(store) if (!$store.currentPageName) - store.setCurrentPage($params.page ? $params.page : "main") + store.actions.pages.select($params.page ? $params.page : "main") const changePage = id => { - store.setCurrentPage(id) + store.actions.pages.select(id) $goto(`./${id}/page-layout`) } diff --git a/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte b/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte index 9f42a9546b..e675006412 100644 --- a/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ScreenDropdownMenu.svelte @@ -13,11 +13,11 @@ let anchor const deleteScreen = () => { - store.deleteScreens(screen, $store.currentPageName) + store.actions.screens.delete(screen, $store.currentPageName) // update the page if required store.update(state => { if (state.currentPreviewItem.name === screen.name) { - store.setCurrentPage($store.currentPageName) + store.actions.pages.select($store.currentPageName) notifier.success(`Screen ${screen.name} deleted successfully.`) $goto(`./:page/page-layout`) } diff --git a/packages/builder/src/components/userInterface/pagesParsing/createProps.js b/packages/builder/src/components/userInterface/pagesParsing/createProps.js index b628b6e15b..3511fa5b12 100644 --- a/packages/builder/src/components/userInterface/pagesParsing/createProps.js +++ b/packages/builder/src/components/userInterface/pagesParsing/createProps.js @@ -59,6 +59,11 @@ export const createProps = (componentDefinition, derivedFromProps) => { } export const makePropsSafe = (componentDefinition, props) => { + if (!componentDefinition) { + console.error( + "No component definition passed to makePropsSafe. Please check the component definition is being passed correctly." + ) + } const safeProps = createProps(componentDefinition, props).props for (let propName in safeProps) { props[propName] = safeProps[propName] diff --git a/packages/builder/src/components/userInterface/pagesParsing/searchComponents.js b/packages/builder/src/components/userInterface/pagesParsing/searchComponents.js index 84f55f50c4..66ece481f2 100644 --- a/packages/builder/src/components/userInterface/pagesParsing/searchComponents.js +++ b/packages/builder/src/components/userInterface/pagesParsing/searchComponents.js @@ -29,10 +29,9 @@ export const searchAllComponents = (components, phrase) => { } export const getExactComponent = (components, name, isScreen = false) => { - return components.find(comp => { - const { props, _instanceName } = comp - return name === isScreen ? props._instanceName : _instanceName - }) + return components.find(comp => + isScreen ? comp.props._instanceName === name : comp._instanceName === name + ) } export const getAncestorProps = (components, name, found = []) => { diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js index 1b443d1fd7..65df616aec 100644 --- a/packages/builder/src/constants/index.js +++ b/packages/builder/src/constants/index.js @@ -1,19 +1,15 @@ export const DEFAULT_PAGES_OBJECT = { main: { - _props: {}, - _screens: {}, - index: { - _component: "./components/indexHtml", + props: { + _component: "@budibase/standard-components/container", }, - appBody: "bbapp.main.json", + _screens: {}, }, unauthenticated: { - _props: {}, - _screens: {}, - index: { - _component: "./components/indexHtml", + props: { + _component: "@budibase/standard-components/container", }, - appBody: "bbapp.unauthenticated.json", + _screens: {}, }, componentLibraries: [], stylesheets: [], diff --git a/packages/builder/src/pages/[application]/_reset.svelte b/packages/builder/src/pages/[application]/_reset.svelte index 2dd672586f..aeead443eb 100644 --- a/packages/builder/src/pages/[application]/_reset.svelte +++ b/packages/builder/src/pages/[application]/_reset.svelte @@ -18,7 +18,7 @@ if (res.ok) { backendUiStore.actions.reset() - await store.setPackage(pkg) + await store.actions.initialise(pkg) await automationStore.actions.fetch() return pkg } else { diff --git a/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte b/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte index a00f7b4ab0..a61df114db 100644 --- a/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte +++ b/packages/builder/src/pages/[application]/automate/[automation]/_layout.svelte @@ -1,4 +1,4 @@ diff --git a/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte b/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte index 3702e0da45..2e637d62f2 100644 --- a/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte +++ b/packages/builder/src/pages/[application]/design/[page]/[screen]/_layout.svelte @@ -16,11 +16,11 @@ if (!validScreen) { // Go to main layout if URL set to invalid screen - store.setCurrentPage("main") + store.actions.pages.select("main") $goto("../../main") } else { // Otherwise proceed to set screen - store.setCurrentScreen(currentScreenName) + store.actions.screens.select(currentScreenName) // There are leftover stuff, like IDs, so navigate the components and find the ID and select it. if ($leftover) { @@ -35,7 +35,7 @@ } } else { // It's a page, so set the screentype to page. - store.setScreenType("page") + store.actions.selectPageOrScreen("page") // There are leftover stuff, like IDs, so navigate the components and find the ID and select it. if ($leftover) { @@ -64,7 +64,7 @@ }) // Select Component! - if (componentToSelect) store.selectComponent(componentToSelect) + if (componentToSelect) store.actions.components.select(componentToSelect) } diff --git a/packages/builder/src/pages/[application]/design/[page]/_layout.svelte b/packages/builder/src/pages/[application]/design/[page]/_layout.svelte index d379bba574..d07a4c5695 100644 --- a/packages/builder/src/pages/[application]/design/[page]/_layout.svelte +++ b/packages/builder/src/pages/[application]/design/[page]/_layout.svelte @@ -2,7 +2,7 @@ import { params } from "@sveltech/routify" import { store } from "builderStore" - store.setCurrentPage($params.page) + store.actions.pages.select($params.page) diff --git a/packages/server/src/api/routes/pages.old.js b/packages/server/src/api/routes/pages.old.js index 547f0d2eb6..2cd0b5ed66 100644 --- a/packages/server/src/api/routes/pages.old.js +++ b/packages/server/src/api/routes/pages.old.js @@ -6,7 +6,6 @@ const { listScreens, saveScreen, buildPage, - renameScreen, deleteScreen, } = require("../../utilities/builder") const authorized = require("../../middleware/authorized") diff --git a/packages/server/src/utilities/builder/listScreens.js b/packages/server/src/utilities/builder/listScreens.js index 80a9afbe78..0b6fda3ed8 100644 --- a/packages/server/src/utilities/builder/listScreens.js +++ b/packages/server/src/utilities/builder/listScreens.js @@ -3,46 +3,46 @@ const { join } = require("../centralPath") const { keyBy } = require("lodash/fp") const { budibaseAppsDir } = require("../budibaseDir") -module.exports = async (appId, pagename) => { - const appPath = join(budibaseAppsDir(), appId) - return keyBy("name")(await fetchscreens(appPath, pagename)) -} +// module.exports = async (appId, pagename) => { +// const appPath = join(budibaseAppsDir(), appId) +// return keyBy("name")(await fetchscreens(appPath, pagename)) +// } -const fetchscreens = async (appPath, pagename, relativePath = "") => { - const currentDir = join(appPath, "pages", pagename, "screens", relativePath) +// const fetchscreens = async (appPath, pagename, relativePath = "") => { +// const currentDir = join(appPath, "pages", pagename, "screens", relativePath) - const contents = await readdir(currentDir) +// const contents = await readdir(currentDir) - const screens = [] +// const screens = [] - for (let item of contents) { - const itemRelativePath = join(relativePath, item) - const itemFullPath = join(currentDir, item) - const stats = await stat(itemFullPath) +// for (let item of contents) { +// const itemRelativePath = join(relativePath, item) +// const itemFullPath = join(currentDir, item) +// const stats = await stat(itemFullPath) - if (stats.isFile()) { - if (!item.endsWith(".json")) continue +// if (stats.isFile()) { +// if (!item.endsWith(".json")) continue - const component = await readJSON(itemFullPath) +// const component = await readJSON(itemFullPath) - component.name = itemRelativePath - .substring(0, itemRelativePath.length - 5) - .replace(/\\/g, "/") +// component.name = itemRelativePath +// .substring(0, itemRelativePath.length - 5) +// .replace(/\\/g, "/") - component.props = component.props || {} +// component.props = component.props || {} - screens.push(component) - } else { - const childComponents = await fetchscreens( - appPath, - join(relativePath, item) - ) +// screens.push(component) +// } else { +// const childComponents = await fetchscreens( +// appPath, +// join(relativePath, item) +// ) - for (let c of childComponents) { - screens.push(c) - } - } - } +// for (let c of childComponents) { +// screens.push(c) +// } +// } +// } - return screens -} +// return screens +// } From fe637e23099da9e555364ac93a23dcddd4469f68 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 5 Nov 2020 09:18:20 +0000 Subject: [PATCH 10/21] update left hand links on builder home --- packages/builder/src/pages/_layout.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/pages/_layout.svelte b/packages/builder/src/pages/_layout.svelte index 871e94f987..3f8b36d8f4 100644 --- a/packages/builder/src/pages/_layout.svelte +++ b/packages/builder/src/pages/_layout.svelte @@ -28,12 +28,12 @@ + href="https://github.com/Budibase/budibase/discussions" /> + href="https://github.com/Budibase/budibase/issues/new/choose" /> From 707c16c44d17c4b899c685c3c1fafcc4751a48ef Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 5 Nov 2020 11:44:18 +0000 Subject: [PATCH 11/21] Further updates to clear out all usage of the old frontend store functions. --- .../src/builderStore/getNewComponentName.js | 2 +- .../src/builderStore/store/frontend.js | 69 ++++++++++++++++--- .../builder/src/builderStore/store/index.js | 8 +-- .../builder/src/builderStore/storeUtils.js | 16 ++--- .../modals/CreateTableModal.svelte | 4 +- .../ComponentDropdownMenu.svelte | 32 ++++----- .../ComponentPropertiesPanel.svelte | 14 +++- .../userInterface/NewScreenModal.svelte | 4 +- .../components/userInterface/PagesList.svelte | 1 - .../server/src/api/controllers/deploy/aws.js | 10 ++- 10 files changed, 116 insertions(+), 44 deletions(-) diff --git a/packages/builder/src/builderStore/getNewComponentName.js b/packages/builder/src/builderStore/getNewComponentName.js index a4565c2296..963c66ebce 100644 --- a/packages/builder/src/builderStore/getNewComponentName.js +++ b/packages/builder/src/builderStore/getNewComponentName.js @@ -33,7 +33,7 @@ export default function(component, state) { let index = 1 let name while (!name) { - const tryName = `${capitalised} ${index}` + const tryName = `${capitalised || "Copy"} ${index}` if (!matchingComponents.includes(tryName)) name = tryName index++ } diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index ec41627f54..488158586b 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -17,7 +17,7 @@ import { getParent, // saveScreenApi as _saveScreenApi, generateNewIdsForComponent, - getComponentDefinition, + getComponentDefinition, findChildComponentType, regenerateCssForScreen, savePage as _savePage, } from "../storeUtils" const INITIAL_FRONTEND_STATE = { @@ -171,18 +171,18 @@ export const getFrontendStore = () => { screen ) const json = await response.json() - - if (currentPageScreens.includes(screen)) return - screen._rev = json.rev screen._id = json.id - - const screens = [...currentPageScreens, screen] + const foundScreen = currentPageScreens.findIndex(el => el._id === screen._id) + if (currentPageScreens !== -1) { + currentPageScreens.splice(foundScreen, 1) + } + currentPageScreens.push(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.pages[pageName]._screens = currentPageScreens + state.screens = currentPageScreens state.currentPreviewItem = screen const safeProps = makePropsSafe( state.components[screen.props._component], @@ -481,6 +481,59 @@ export const getFrontendStore = () => { return path }, + links: { + save: 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" + store.actions.screens.regenerateCss(state.pages.main) + for (let screen of state.pages.main._screens) { + store.actions.screens.regenerateCss(screen) + } + savePromise = store.actions.pages.save() + } + return state + }) + await savePromise + }, + }, }, } diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index 638e0788dc..ee5f1b4b73 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -391,7 +391,7 @@ const setComponentProp = store => (name, value) => { current_component[name] = value state.currentComponentInfo = current_component - _saveCurrentPreviewItem(state) + //_saveCurrentPreviewItem(state) return state }) } @@ -403,7 +403,7 @@ const setPageOrScreenProp = store => (name, value) => { } else { state.currentPreviewItem[name] = value } - _saveCurrentPreviewItem(state) + //_saveCurrentPreviewItem(state) return state }) } @@ -418,7 +418,7 @@ const setComponentStyle = store => (type, name, value) => { regenerateCssForCurrentScreen(state) // save without messing with the store - _saveCurrentPreviewItem(state) + //_saveCurrentPreviewItem(state) return state }) } @@ -511,7 +511,7 @@ const pasteComponent = store => (targetComponent, mode) => { const index = mode === "above" ? targetIndex : targetIndex + 1 parent._children.splice(index, 0, cloneDeep(componentToPaste)) regenerateCssForCurrentScreen(s) - _saveCurrentPreviewItem(s) + //_saveCurrentPreviewItem(s) selectComponent(s, componentToPaste) return s diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 3c85e611dd..6b98ac8dc3 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -31,10 +31,10 @@ export const getParent = (rootProps, child) => { return parent } -export const saveCurrentPreviewItem = s => - s.currentFrontEndType === "page" - ? savePage(s) - : store.saveScreen(s.currentPreviewItem) +// export const saveCurrentPreviewItem = s => +// s.currentFrontEndType === "page" +// ? savePage(s) +// : store.actions.screens.save(s.currentPreviewItem) export const savePage = async state => { const pageName = state.currentPageName || "main" @@ -92,10 +92,10 @@ export const regenerateCssForCurrentScreen = state => { return state } -export const generateNewIdsForComponent = (c, state, changeName = true) => - walkProps(c, p => { - p._id = uuid() - if (changeName) p._instanceName = getNewComponentName(p._component, state) +export const generateNewIdsForComponent = (component, state, changeName = true) => + walkProps(component, prop => { + prop._id = uuid() + if (changeName) prop._instanceName = getNewComponentName(prop, state) }) export const getComponentDefinition = (state, name) => diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte index 146f881b2b..0fe19f9bc0 100644 --- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte +++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte @@ -55,7 +55,7 @@ // Record the table that created this screen so we can link it later screen.autoTableId = table._id try { - await store.createScreen(screen) + await store.actions.screens.create(screen) } catch (_) { // TODO: this is temporary // a cypress test is failing, because I added the @@ -70,7 +70,7 @@ const listPage = screens.find(screen => screen.props._instanceName.endsWith("List") ) - await store.createLink(listPage.route, table.name) + await store.actions.components.links.save(listPage.route, table.name) // Navigate to new table $goto(`./table/${table._id}`) diff --git a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte index 87df51cd16..8d119e8ec3 100644 --- a/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte +++ b/packages/builder/src/components/userInterface/ComponentDropdownMenu.svelte @@ -4,7 +4,7 @@ import { getComponentDefinition } from "builderStore/storeUtils" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import { last } from "lodash/fp" - import { getParent, saveCurrentPreviewItem } from "builderStore/storeUtils" + import { getParent } from "builderStore/storeUtils" import { DropdownMenu } from "@budibase/bbui" import { DropdownContainer, DropdownItem } from "components/common/Dropdowns" @@ -31,44 +31,44 @@ } const moveUpComponent = () => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) + store.update(state => { + const parent = getParent(state.currentPreviewItem.props, component) if (parent) { const currentIndex = parent._children.indexOf(component) - if (currentIndex === 0) return s + if (currentIndex === 0) return state const newChildren = parent._children.filter(c => c !== component) newChildren.splice(currentIndex - 1, 0, component) parent._children = newChildren } - s.currentComponentInfo = component - saveCurrentPreviewItem(s) + state.currentComponentInfo = component + store.actions.preview.saveSelected() - return s + return state }) } const moveDownComponent = () => { - store.update(s => { - const parent = getParent(s.currentPreviewItem.props, component) + store.update(state => { + const parent = getParent(state.currentPreviewItem.props, component) if (parent) { const currentIndex = parent._children.indexOf(component) - if (currentIndex === parent._children.length - 1) return s + if (currentIndex === parent._children.length - 1) return state const newChildren = parent._children.filter(c => c !== component) newChildren.splice(currentIndex + 1, 0, component) parent._children = newChildren } - s.currentComponentInfo = component - saveCurrentPreviewItem(s) + state.currentComponentInfo = component + store.actions.preview.saveSelected() - return s + return state }) } - const copyComponent = () => { + const duplicateComponent = () => { storeComponentForCopy(false) pasteComponent("below") } @@ -82,7 +82,7 @@ selectComponent(parent) } - saveCurrentPreviewItem(state) + store.actions.preview.saveSelected() return state }) } @@ -119,7 +119,7 @@ + on:click={duplicateComponent} /> { + if (name === "_instanceName" && state.currentFrontEndType === "screen") { + state.currentPreviewItem.props[name] = value + } else { + state.currentPreviewItem[name] = value + } + store.actions.preview.saveSelected() + return state + }) + } + function getProps(obj, keys) { return keys.map((key, i) => [key, obj[key], obj.props._id + i]) } @@ -82,7 +94,7 @@ {panelDefinition} displayNameField={displayName} onChange={store.actions.components.updateProp} - onScreenPropChange={store.setPageOrScreenProp} + onScreenPropChange={setPageOrScreenProp} screenOrPageInstance={$store.currentView !== 'component' && $store.currentPreviewItem} /> {/if} diff --git a/packages/builder/src/components/userInterface/NewScreenModal.svelte b/packages/builder/src/components/userInterface/NewScreenModal.svelte index 7d6677ce17..73313773e9 100644 --- a/packages/builder/src/components/userInterface/NewScreenModal.svelte +++ b/packages/builder/src/components/userInterface/NewScreenModal.svelte @@ -71,9 +71,9 @@ draftScreen.props._component = baseComponent draftScreen.route = route - await store.createScreen(draftScreen) + await store.actions.screens.create(draftScreen) if (createLink) { - await store.createLink(route, name) + await store.actions.components.links.save(route, name) } if (templateIndex !== undefined) { diff --git a/packages/builder/src/components/userInterface/PagesList.svelte b/packages/builder/src/components/userInterface/PagesList.svelte index 477b390149..fa22ccfa1b 100644 --- a/packages/builder/src/components/userInterface/PagesList.svelte +++ b/packages/builder/src/components/userInterface/PagesList.svelte @@ -18,7 +18,6 @@ }, ] - console.log(store) if (!$store.currentPageName) store.actions.pages.select($params.page ? $params.page : "main") diff --git a/packages/server/src/api/controllers/deploy/aws.js b/packages/server/src/api/controllers/deploy/aws.js index 3e19812a00..e6cd514cac 100644 --- a/packages/server/src/api/controllers/deploy/aws.js +++ b/packages/server/src/api/controllers/deploy/aws.js @@ -42,6 +42,13 @@ exports.isInvalidationComplete = async function( return resp.Invalidation.Status === "Completed" } +/** + * Finalises the deployment, updating the quota for the user API key + * The verification process returns the levels to update to. + * Calls the "deployment-success" lambda. + * @param {object} quota The usage quota levels returned from the verifyDeploy + * @returns {Promise} The usage has been updated against the user API key. + */ exports.updateDeploymentQuota = async function(quota) { const DEPLOYMENT_SUCCESS_URL = env.DEPLOYMENT_CREDENTIALS_URL + "deploy/success" @@ -67,7 +74,8 @@ exports.updateDeploymentQuota = async function(quota) { /** * Verifies the users API key and - * Verifies that the deployment fits within the quota of the user, + * Verifies that the deployment fits within the quota of the user + * Links to the "check-api-key" lambda. * @param {String} appId - appId being deployed * @param {String} appId - appId being deployed * @param {quota} quota - current quota being changed with this application From 76cc7d897cca6c71a95da652810b4cbc2dc19167 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 5 Nov 2020 12:43:03 +0000 Subject: [PATCH 12/21] More cleanup, removing template app pages that were unused and fixing a bug with auth not being configured correctly when app created. --- .../builder/src/builderStore/store/index.js | 519 ------------------ .../server/src/api/controllers/application.js | 4 +- .../appDirectoryTemplate/pages/main/page.json | 143 ----- .../pages/main/screens/.gitkeep | 0 .../d834fea2-1b3e-4320-ab34-f9009f5ecc59.json | 102 ---- .../pages/unauthenticated/page.json | 67 --- .../pages/unauthenticated/screens/.gitkeep | 0 .../pages/unauthenticated/screens/placeholder | 0 8 files changed, 3 insertions(+), 832 deletions(-) delete mode 100644 packages/builder/src/builderStore/store/index.js delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/pages/main/page.json delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/.gitkeep delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/pages/main/screens/d834fea2-1b3e-4320-ab34-f9009f5ecc59.json delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/screens/.gitkeep delete mode 100644 packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/screens/placeholder 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 From 3847c058dccdc2b597d19c1d392e838b53bef669 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 5 Nov 2020 13:41:16 +0000 Subject: [PATCH 13/21] rename buildPage --- packages/server/src/api/controllers/application.js | 8 ++++---- packages/server/src/api/controllers/page.js | 9 ++++++--- packages/server/src/api/routes/pages.old.js | 8 ++++++-- packages/server/src/utilities/builder/index.js | 6 +++--- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index b10b8d82c0..5a494d4734 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -1,5 +1,5 @@ const CouchDB = require("../../db") -const { buildPage } = require("../../utilities/builder") +const { compileStaticAssetsForPage } = require("../../utilities/builder") const env = require("../../environment") const { copy, existsSync, readFile, writeFile } = require("fs-extra") const { budibaseAppsDir } = require("../../utilities/budibaseDir") @@ -230,13 +230,13 @@ 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) - const response = await db.bulkDocs([mainPage, unauthPage, homeScreen]) + await db.bulkDocs([mainPage, unauthPage, homeScreen]) - await buildPage(app._id, "main", { + await compileStaticAssetsForPage(app._id, "main", { page: mainPage, screens: [homeScreen], }) - await buildPage(app._id, "unauthenticated", { + await compileStaticAssetsForPage(app._id, "unauthenticated", { page: unauthPage, screens: [], }) diff --git a/packages/server/src/api/controllers/page.js b/packages/server/src/api/controllers/page.js index 06d427f546..0455a4cf45 100644 --- a/packages/server/src/api/controllers/page.js +++ b/packages/server/src/api/controllers/page.js @@ -1,14 +1,17 @@ const CouchDB = require("../../db/client") const { generatePageID } = require("../../db/utils") -const { buildPage } = require("../../utilities/builder") +const { compileStaticAssetsForPage } = require("../../utilities/builder") exports.save = async function(ctx) { const db = new CouchDB(ctx.user.appId) const appPackage = ctx.request.body - // TODO: rename to something more descriptive - await buildPage(ctx.user.appId, ctx.params.pageId, ctx.request.body) + await compileStaticAssetsForPage( + ctx.user.appId, + ctx.params.pageId, + ctx.request.body + ) // remove special doc props which couch will complain about delete appPackage.page._css diff --git a/packages/server/src/api/routes/pages.old.js b/packages/server/src/api/routes/pages.old.js index 2cd0b5ed66..5d23264c10 100644 --- a/packages/server/src/api/routes/pages.old.js +++ b/packages/server/src/api/routes/pages.old.js @@ -5,7 +5,7 @@ const Joi = require("joi") const { listScreens, saveScreen, - buildPage, + compileStaticAssetsForPage, deleteScreen, } = require("../../utilities/builder") const authorized = require("../../middleware/authorized") @@ -44,7 +44,11 @@ router.post( "/_builder/api/:appId/pages/:pageName", authorized(BUILDER), async ctx => { - await buildPage(ctx.params.appId, ctx.params.pageName, ctx.request.body) + await compileStaticAssetsForPage( + ctx.params.appId, + ctx.params.pageName, + ctx.request.body + ) ctx.response.status = StatusCodes.OK } ) diff --git a/packages/server/src/utilities/builder/index.js b/packages/server/src/utilities/builder/index.js index 155ad5b197..015e40244e 100644 --- a/packages/server/src/utilities/builder/index.js +++ b/packages/server/src/utilities/builder/index.js @@ -11,13 +11,13 @@ // const { join } = require("../centralPath") // const { dirname } = require("path") -const buildPage = require("./buildPage") +const compileStaticAssetsForPage = require("./compileStaticAssetsForPage") // const getPages = require("./getPages") // const listScreens = require("./listScreens") // const { budibaseAppsDir } = require("../budibaseDir") // const { budibaseAppsDir } = require("../budibaseDir") -module.exports.buildPage = buildPage +module.exports.compileStaticAssetsForPage = compileStaticAssetsForPage // module.exports.listScreens = listScreens // const getAppDefinition = async appPath => @@ -76,5 +76,5 @@ module.exports.buildPage = buildPage // space: 2, // }) // const appDefinition = await getAppDefinition(appPath) -// await buildPage(appId, appDefinition, pagename, page) +// await compileStaticAssetsForPage(appId, appDefinition, pagename, page) // } From a9ac8d06324b4624331391fa8d84621df4c77f12 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 5 Nov 2020 14:38:44 +0000 Subject: [PATCH 14/21] Fixing some bugs that have been found. --- .../src/builderStore/store/frontend.js | 4 + .../src/builderStore/store/frontend/index.js | 0 .../store/frontend/pages/index.js | 70 ++++++++++++++++ .../server/src/api/controllers/application.js | 79 +------------------ packages/server/src/api/controllers/page.js | 3 +- ...dPage.js => compileStaticAssetsForPage.js} | 0 .../src/utilities/builder/setBuilderToken.js | 1 + 7 files changed, 80 insertions(+), 77 deletions(-) create mode 100644 packages/builder/src/builderStore/store/frontend/index.js create mode 100644 packages/builder/src/builderStore/store/frontend/pages/index.js rename packages/server/src/utilities/builder/{buildPage.js => compileStaticAssetsForPage.js} (100%) diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 488158586b..ffd0dcfdca 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -45,6 +45,10 @@ export const getFrontendStore = () => { store.actions = { // TODO: REFACTOR initialise: async pkg => { + store.update(state => { + state.appId = pkg.application._id + return state + }) const screens = await api.get("/api/screens").then(r => r.json()) const mainScreens = screens.filter(screen => diff --git a/packages/builder/src/builderStore/store/frontend/index.js b/packages/builder/src/builderStore/store/frontend/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/builder/src/builderStore/store/frontend/pages/index.js b/packages/builder/src/builderStore/store/frontend/pages/index.js new file mode 100644 index 0000000000..4ce8105e7d --- /dev/null +++ b/packages/builder/src/builderStore/store/frontend/pages/index.js @@ -0,0 +1,70 @@ +import {makePropsSafe} from "../../../../components/userInterface/pagesParsing/createProps" +import {generate_screen_css} from "../../../generate_css" +import {get} from "svelte/store" +import api from "../../../api" +import { store } from "builderStore" + +class Page { + constructor(page) { + this.pageName = page.name + this.pageObj = page + } + + select() { + store.update(state => { + const pageName = this.pageName + 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) + + // 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() + + for (let screen of state.screens) { + screen._css = generate_screen_css([screen.props]) + } + + return state + }) + } + + async save() { + const page = this.pageObj + 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 + }) + } +} \ No newline at end of file diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 5a494d4734..cf26dfa766 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -1,14 +1,11 @@ const CouchDB = require("../../db") const { compileStaticAssetsForPage } = require("../../utilities/builder") const env = require("../../environment") -const { copy, existsSync, readFile, writeFile } = require("fs-extra") +const { copy, existsSync } = require("fs-extra") const { budibaseAppsDir } = require("../../utilities/budibaseDir") -const sqrl = require("squirrelly") const setBuilderToken = require("../../utilities/builder/setBuilderToken") const fs = require("fs-extra") const { join, resolve } = require("../../utilities/centralPath") -const { promisify } = require("util") -const chmodr = require("chmodr") const packageJson = require("../../../package.json") const { createLinkView } = require("../../db/linkedRows") const { downloadTemplate } = require("../../utilities/templates") @@ -153,14 +150,6 @@ exports.delete = async function(ctx) { } const createEmptyAppPackage = async (ctx, app) => { - const templateFolder = resolve( - __dirname, - "..", - "..", - "utilities", - "appDirectoryTemplate" - ) - const appsFolder = budibaseAppsDir() const newAppFolder = resolve(appsFolder, app._id) @@ -170,24 +159,7 @@ const createEmptyAppPackage = async (ctx, app) => { ctx.throw(400, "App folder already exists for this application") } - // await fs.ensureDir(join(newAppFolder, "pages", "main", "screens"), 0o777) - // await fs.ensureDir( - // join(newAppFolder, "pages", "unauthenticated", "screens"), - // 0o777 - // ) - - await copy(templateFolder, newAppFolder) - - // this line allows full permission on copied files - // we have an unknown problem without this, whereby the - // files get weird permissions and cant be written to :( - const chmodrPromise = promisify(chmodr) - await chmodrPromise(newAppFolder, 0o777) - - await updateJsonFile(join(appsFolder, app._id, "package.json"), { - name: npmFriendlyAppName(app.name), - }) - + fs.mkdirpSync(newAppFolder) // if this app is being created from a template, // copy the frontend page definition files from // the template directory. @@ -203,23 +175,6 @@ const createEmptyAppPackage = async (ctx, app) => { await copy(templatePageDefinitions, join(appsFolder, app._id, "pages")) } - // const mainJson = await updateJsonFile( - // join(appsFolder, app._id, "pages", "main", "page.json"), - // app - // ) - // - // mainJson._id = generatePageID() - // await db.put(mainJson) - - // const unauthenticatedJson = await updateJsonFile( - // join(appsFolder, app._id, "pages", "unauthenticated", "page.json"), - // app - // ) - - // Write to couch - // unauthenticatedJson._id = generatePageID() - // await db.put(unauthenticatedJson) - const mainPage = cloneDeep(MAIN) mainPage._id = generatePageID() mainPage.title = app.name @@ -227,7 +182,7 @@ const createEmptyAppPackage = async (ctx, app) => { unauthPage._id = generatePageID() // TODO: fix - handlebars etc unauthPage.title = app.name - unauthPage.props._children[0]._children.title = `Log in to ${app.name}` + unauthPage.props._children[0].title = `Log in to ${app.name}` const homeScreen = cloneDeep(HOME_SCREEN) homeScreen._id = generateScreenID(mainPage._id) await db.bulkDocs([mainPage, unauthPage, homeScreen]) @@ -243,31 +198,3 @@ const createEmptyAppPackage = async (ctx, app) => { return newAppFolder } - -// const loadScreens = async (appFolder, page) => { -// const screensFolder = join(appFolder, "pages", page, "screens") -// -// const screenFiles = (await fs.readdir(screensFolder)).filter(s => -// s.endsWith(".json") -// ) -// -// let screens = [] -// for (let file of screenFiles) { -// screens.push(await fs.readJSON(join(screensFolder, file))) -// } -// return screens -// } - -const updateJsonFile = async (filePath, app) => { - const json = await readFile(filePath, "utf8") - const newJson = sqrl.Render(json, app) - await writeFile(filePath, newJson, "utf8") - return JSON.parse(newJson) -} - -const npmFriendlyAppName = name => - name - .replace(/_/g, "") - .replace(/./g, "") - .replace(/ /g, "") - .toLowerCase() diff --git a/packages/server/src/api/controllers/page.js b/packages/server/src/api/controllers/page.js index 0455a4cf45..009d167856 100644 --- a/packages/server/src/api/controllers/page.js +++ b/packages/server/src/api/controllers/page.js @@ -7,9 +7,10 @@ exports.save = async function(ctx) { const appPackage = ctx.request.body + const page = await db.get(ctx.params.pageId) await compileStaticAssetsForPage( ctx.user.appId, - ctx.params.pageId, + page.name, ctx.request.body ) diff --git a/packages/server/src/utilities/builder/buildPage.js b/packages/server/src/utilities/builder/compileStaticAssetsForPage.js similarity index 100% rename from packages/server/src/utilities/builder/buildPage.js rename to packages/server/src/utilities/builder/compileStaticAssetsForPage.js diff --git a/packages/server/src/utilities/builder/setBuilderToken.js b/packages/server/src/utilities/builder/setBuilderToken.js index 2986a805a9..8cf6c44379 100644 --- a/packages/server/src/utilities/builder/setBuilderToken.js +++ b/packages/server/src/utilities/builder/setBuilderToken.js @@ -21,6 +21,7 @@ module.exports = async (ctx, appId, version) => { // set the builder token setCookie(ctx, "builder", token) + setCookie(ctx, "currentapp", appId) // need to clear all app tokens or else unable to use the app in the builder let allDbNames = await CouchDB.allDbs() allDbNames.map(dbName => { From 2008bfff709ce21bb69d6c19548028311c5b13d2 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 5 Nov 2020 14:56:23 +0000 Subject: [PATCH 15/21] Getting started into removing screens from store. --- .../src/builderStore/store/frontend.js | 17 ++++-- .../builder/src/builderStore/storeUtils.js | 56 ------------------- 2 files changed, 13 insertions(+), 60 deletions(-) diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index ffd0dcfdca..c860098a8c 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -1,4 +1,4 @@ -import { writable, get } from "svelte/store" +import { writable, get, derived } from "svelte/store" import { cloneDeep } from "lodash/fp" import { createProps, @@ -15,9 +15,8 @@ import getNewComponentName from "../getNewComponentName" import analytics from "analytics" import { getParent, - // saveScreenApi as _saveScreenApi, generateNewIdsForComponent, - getComponentDefinition, findChildComponentType, regenerateCssForScreen, savePage as _savePage, + getComponentDefinition, findChildComponentType, } from "../storeUtils" const INITIAL_FRONTEND_STATE = { @@ -42,6 +41,16 @@ const INITIAL_FRONTEND_STATE = { export const getFrontendStore = () => { const store = writable({ ...INITIAL_FRONTEND_STATE }) + store.allScreens = derived(store.pages, $pages => { + let screens = [] + if ($pages) { + for (let page of Object.values($pages)) { + screens = screens.concat(page._screens) + } + } + return screens + }) + store.actions = { // TODO: REFACTOR initialise: async pkg => { @@ -129,7 +138,7 @@ export const getFrontendStore = () => { screens: { select: screenName => { store.update(state => { - const screen = getExactComponent(state.screens, screenName, true) + const screen = getExactComponent(state.allScreens, screenName, true) state.currentPreviewItem = screen state.currentFrontEndType = "screen" state.currentView = "detail" diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 6b98ac8dc3..69050e1b87 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -8,15 +8,6 @@ import { generate_screen_css } from "./generate_css" import { uuid } from "./uuid" import getNewComponentName from "./getNewComponentName" -export const selectComponent = (state, component) => { - const componentDef = component._component.startsWith("##") - ? component - : state.components[component._component] - state.currentComponentInfo = makePropsSafe(componentDef, component) - state.currentView = "component" - return state -} - export const getParent = (rootProps, child) => { let parent walkProps(rootProps, (p, breakWalk) => { @@ -31,42 +22,6 @@ export const getParent = (rootProps, child) => { return parent } -// export const saveCurrentPreviewItem = s => -// s.currentFrontEndType === "page" -// ? savePage(s) -// : store.actions.screens.save(s.currentPreviewItem) - -export const savePage = async state => { - const pageName = state.currentPageName || "main" - const page = state.pages[pageName] - - const response = await api - .post(`/api/pages/${page._id}`, { - page: { componentLibraries: state.pages.componentLibraries, ...page }, - screens: page._screens, - }) - .then(response => response.json()) - store.update(innerState => { - innerState.pages[pageName]._rev = response.rev - return innerState - }) - return state -} - -// export const saveScreenApi = async (screen, state) => { -// const currentPage = state.pages[state.currentPageName] -// const response = await api.post(`/api/screens/${currentPage._id}`, screen) -// const json = await response.json() - -// store.update(innerState => { -// // TODO: need to update pages in here -// // innerState.pages[pageName]._rev = response.rev -// return innerState -// }) - -// await savePage(state) -// } - export const walkProps = (props, action, cancelToken = null) => { cancelToken = cancelToken || { cancelled: false } action(props, () => { @@ -81,17 +36,6 @@ export const walkProps = (props, action, cancelToken = null) => { } } -export const regenerateCssForScreen = screen => { - screen._css = generate_screen_css([screen.props]) -} - -export const regenerateCssForCurrentScreen = state => { - if (state.currentPreviewItem) { - regenerateCssForScreen(state.currentPreviewItem) - } - return state -} - export const generateNewIdsForComponent = (component, state, changeName = true) => walkProps(component, prop => { prop._id = uuid() From 542b003f7e5f1c14162d820d6206ac39fe3936b4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 5 Nov 2020 17:47:27 +0000 Subject: [PATCH 16/21] Refactoring to replace the use of frontend store.screens with derived allScreens and currentScreens. --- .../src/builderStore/getNewComponentName.js | 4 +- packages/builder/src/builderStore/index.js | 22 +++++- .../src/builderStore/store/frontend.js | 33 ++------- .../src/builderStore/store/frontend/index.js | 0 .../store/frontend/pages/index.js | 70 ------------------- .../popovers/EditTablePopover.svelte | 4 +- .../ComponentsPaneSwitcher.svelte | 4 +- .../userInterface/DetailScreenSelect.svelte | 4 +- .../EventsEditor/StateBindingCascader.svelte | 4 +- .../EventsEditor/actions/NavigateTo.svelte | 4 +- .../userInterface/FrontendNavigatePane.svelte | 4 +- .../userInterface/NewScreenModal.svelte | 6 +- .../userInterface/ScreenSelect.svelte | 6 +- .../userInterface/SettingsView.svelte | 4 +- .../design/[page]/[screen]/_layout.svelte | 4 +- 15 files changed, 51 insertions(+), 122 deletions(-) delete mode 100644 packages/builder/src/builderStore/store/frontend/index.js delete mode 100644 packages/builder/src/builderStore/store/frontend/pages/index.js diff --git a/packages/builder/src/builderStore/getNewComponentName.js b/packages/builder/src/builderStore/getNewComponentName.js index 963c66ebce..a69bec21ad 100644 --- a/packages/builder/src/builderStore/getNewComponentName.js +++ b/packages/builder/src/builderStore/getNewComponentName.js @@ -1,5 +1,7 @@ import { walkProps } from "./storeUtils" import { get_capitalised_name } from "../helpers" +import { get } from "svelte/store" +import { allScreens } from "builderStore" export default function(component, state) { const capitalised = get_capitalised_name( @@ -25,7 +27,7 @@ export default function(component, state) { findMatches(state.currentPreviewItem.props) } else { // viewing master page - need to find against all screens - for (let screen of state.screens) { + for (let screen of get(allScreens)) { findMatches(screen.props) } } diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index f4e0cf0f8b..61f816196e 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -1,16 +1,34 @@ -// 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 { derived } from "svelte/store" import analytics from "analytics" -// export const store = getStore() export const store = getFrontendStore() export const backendUiStore = getBackendUiStore() export const automationStore = getAutomationStore() export const themeStore = getThemeStore() +export const allScreens = derived(store, $store => { + let screens = [] + if ($store.pages == null) { + return screens + } + for (let page of Object.values($store.pages)) { + screens = screens.concat(page._screens) + } + return screens +}) + +export const currentScreens = derived(store, $store => { + const currentScreens = $store.pages[$store.currentPageName]?._screens + if (currentScreens == null) { + return [] + } + return Array.isArray(currentScreens) ? currentScreens : Object.values(currentScreens) +}) + export const initialise = async () => { try { await analytics.activate() diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index c860098a8c..7d788ff5ee 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -1,4 +1,4 @@ -import { writable, get, derived } from "svelte/store" +import { writable, get } from "svelte/store" import { cloneDeep } from "lodash/fp" import { createProps, @@ -6,7 +6,7 @@ import { getBuiltin, } from "components/userInterface/pagesParsing/createProps" import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents" -import { backendUiStore } from "builderStore" +import { backendUiStore, allScreens } from "builderStore" import { generate_screen_css } from "../generate_css" import { fetchComponentLibDefinitions } from "../loadComponentLibraries" import api from "../api" @@ -41,16 +41,6 @@ const INITIAL_FRONTEND_STATE = { export const getFrontendStore = () => { const store = writable({ ...INITIAL_FRONTEND_STATE }) - store.allScreens = derived(store.pages, $pages => { - let screens = [] - if ($pages) { - for (let page of Object.values($pages)) { - screens = screens.concat(page._screens) - } - } - return screens - }) - store.actions = { // TODO: REFACTOR initialise: async pkg => { @@ -110,10 +100,7 @@ export const getFrontendStore = () => { appId: pkg.application._id, pages: pkg.pages, hasAppPackage: true, - screens: [ - ...Object.values(mainScreens), - ...Object.values(unauthScreens), - ], + currentScreens: [], builtins: [getBuiltin("##builtin/screenslot")], appInstance: pkg.application.instance, })) @@ -138,7 +125,7 @@ export const getFrontendStore = () => { screens: { select: screenName => { store.update(state => { - const screen = getExactComponent(state.allScreens, screenName, true) + const screen = getExactComponent(get(allScreens), screenName, true) state.currentPreviewItem = screen state.currentFrontEndType = "screen" state.currentView = "detail" @@ -195,7 +182,6 @@ export const getFrontendStore = () => { // TODO: should carry out all server updates to screen in a single call store.update(state => { state.pages[pageName]._screens = currentPageScreens - state.screens = currentPageScreens state.currentPreviewItem = screen const safeProps = makePropsSafe( state.components[screen.props._component], @@ -227,9 +213,6 @@ export const getFrontendStore = () => { for (let screenToDelete of Array.isArray(screenToDelete) ? screenToDelete : [screenToDelete]) { - state.screens = state.screens.filter( - screen => screen.name !== screenToDelete.name - ) // Remove screen from current page as well // TODO: Should be done server side state.pages[pageName]._screens = state.pages[ @@ -256,16 +239,12 @@ export const getFrontendStore = () => { pages: { select: pageName => { store.update(state => { - const current_screens = state.pages[pageName]._screens - const currentPage = state.pages[pageName] + state.currentScreens = currentPage._screens state.currentFrontEndType = "page" state.currentView = "detail" state.currentPageName = pageName - state.screens = Array.isArray(current_screens) - ? current_screens - : Object.values(current_screens) // This is the root of many problems. // Uncaught (in promise) TypeError: Cannot read property '_component' of undefined @@ -280,7 +259,7 @@ export const getFrontendStore = () => { state.currentPreviewItem = state.pages[pageName] store.actions.screens.regenerateCssForCurrentScreen() - for (let screen of state.screens) { + for (let screen of get(allScreens)) { screen._css = generate_screen_css([screen.props]) } diff --git a/packages/builder/src/builderStore/store/frontend/index.js b/packages/builder/src/builderStore/store/frontend/index.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/builder/src/builderStore/store/frontend/pages/index.js b/packages/builder/src/builderStore/store/frontend/pages/index.js deleted file mode 100644 index 4ce8105e7d..0000000000 --- a/packages/builder/src/builderStore/store/frontend/pages/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import {makePropsSafe} from "../../../../components/userInterface/pagesParsing/createProps" -import {generate_screen_css} from "../../../generate_css" -import {get} from "svelte/store" -import api from "../../../api" -import { store } from "builderStore" - -class Page { - constructor(page) { - this.pageName = page.name - this.pageObj = page - } - - select() { - store.update(state => { - const pageName = this.pageName - 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) - - // 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() - - for (let screen of state.screens) { - screen._css = generate_screen_css([screen.props]) - } - - return state - }) - } - - async save() { - const page = this.pageObj - 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 - }) - } -} \ No newline at end of file diff --git a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte index 46f53af4d3..1fdbe35151 100644 --- a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte +++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte @@ -1,5 +1,5 @@
- {#if $store.currentFrontEndType === 'page' || $store.screens.length} + {#if $store.currentFrontEndType === 'page' || $allScreens.length}
diff --git a/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte b/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte index c69d5f7b9b..a9140e2978 100644 --- a/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte +++ b/packages/builder/src/components/userInterface/ComponentsHierarchy.svelte @@ -24,15 +24,12 @@ let componentToDelete = "" const normalizedName = name => - pipe( - name, - [ - trimCharsStart("./"), - trimCharsStart("~/"), - trimCharsStart("../"), - trimChars(" "), - ] - ) + pipe(name, [ + trimCharsStart("./"), + trimCharsStart("~/"), + trimCharsStart("../"), + trimChars(" "), + ]) const changeScreen = screen => { store.actions.screens.select(screen.props._instanceName) diff --git a/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte b/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte index a9f390900a..7bedf5e6a8 100644 --- a/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte +++ b/packages/builder/src/components/userInterface/ComponentsHierarchyChildren.svelte @@ -35,11 +35,7 @@ const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1) const get_name = s => (!s ? "" : last(s.split("/"))) - const get_capitalised_name = name => - pipe( - name, - [get_name, capitalise] - ) + const get_capitalised_name = name => pipe(name, [get_name, capitalise]) const isScreenslot = name => name === "##builtin/screenslot" const selectComponent = component => { From 9544d2d20509346db4361fb6915310fc219cf9a5 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Nov 2020 12:38:59 +0000 Subject: [PATCH 19/21] Changing signup function to createNewApp for clarity. --- .../builder/src/components/start/CreateAppModal.svelte | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 1fa7cdab7b..c8a894d9d9 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -128,7 +128,7 @@ } } - async function signUp() { + async function createNewApp() { submitting = true try { // Add API key if there is none. @@ -193,10 +193,6 @@ $: checkValidity($createAppStore.values, $createAppStore.currentStep) let onChange = () => {} - - async function _onOkay() { - await createNewApp() - }
@@ -239,7 +235,7 @@ From aab4f60d76649d366e99413d2110fb0d477b45ee Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Fri, 6 Nov 2020 13:40:00 +0000 Subject: [PATCH 20/21] small tidy ups --- packages/builder/src/pages/index.svelte | 2 +- packages/server/src/api/controllers/application.js | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/pages/index.svelte b/packages/builder/src/pages/index.svelte index 5462494397..fcf0f5af52 100644 --- a/packages/builder/src/pages/index.svelte +++ b/packages/builder/src/pages/index.svelte @@ -62,7 +62,7 @@
- + diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 3894ed85a0..8b931d14c8 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -76,10 +76,8 @@ exports.fetchAppPackage = async function(ctx) { ) pages = pages.rows.map(row => row.doc) - const mainPage = pages.filter(page => page.name === PageTypes.MAIN)[0] - const unauthPage = pages.filter( - page => page.name === PageTypes.UNAUTHENTICATED - )[0] + const mainPage = pages.find(page => page.name === PageTypes.MAIN) + const unauthPage = pages.find(page => page.name === PageTypes.UNAUTHENTICATED) ctx.body = { application, pages: { @@ -139,7 +137,6 @@ exports.delete = async function(ctx) { const result = await db.destroy() // remove top level directory - // TODO: look into why this isn't a callback await fs.rmdir(join(budibaseAppsDir(), ctx.params.appId), { recursive: true, }) @@ -160,14 +157,16 @@ const createEmptyAppPackage = async (ctx, app) => { } fs.mkdirpSync(newAppFolder) + const mainPage = cloneDeep(MAIN) mainPage._id = generatePageID() mainPage.title = app.name + const unauthPage = cloneDeep(UNAUTHENTICATED) unauthPage._id = generatePageID() - // TODO: fix - handlebars etc unauthPage.title = app.name unauthPage.props._children[0].title = `Log in to ${app.name}` + const homeScreen = cloneDeep(HOME_SCREEN) homeScreen._id = generateScreenID(mainPage._id) await db.bulkDocs([mainPage, unauthPage, homeScreen]) From 596940371e4760c41dfff9056090b3c0bb1e79b6 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Fri, 6 Nov 2020 13:46:19 +0000 Subject: [PATCH 21/21] remove superfluous files --- .../builder/src/builderStore/storeUtils.js | 8 +- .../server/src/api/controllers/application.js | 2 +- packages/server/src/api/controllers/page.js | 2 +- .../builder/compileStaticAssetsForPage.js | 24 ------ .../server/src/utilities/builder/getPages.js | 20 ----- .../server/src/utilities/builder/index.js | 80 ------------------- .../src/utilities/builder/listScreens.js | 48 ----------- .../server/src/utilities/createAppPackage.js | 2 - 8 files changed, 3 insertions(+), 183 deletions(-) delete mode 100644 packages/server/src/utilities/builder/getPages.js delete mode 100644 packages/server/src/utilities/builder/index.js delete mode 100644 packages/server/src/utilities/builder/listScreens.js diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 97b780de69..9c9d1ef940 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -1,10 +1,4 @@ -import { - makePropsSafe, - getBuiltin, -} from "components/userInterface/pagesParsing/createProps" -import api from "./api" -import { store } from "builderStore" -import { generate_screen_css } from "./generate_css" +import { getBuiltin } from "components/userInterface/pagesParsing/createProps" import { uuid } from "./uuid" import getNewComponentName from "./getNewComponentName" diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 8b931d14c8..2185293352 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -1,5 +1,5 @@ const CouchDB = require("../../db") -const { compileStaticAssetsForPage } = require("../../utilities/builder") +const compileStaticAssetsForPage = require("../../utilities/builder/compileStaticAssetsForPage") const env = require("../../environment") const { existsSync } = require("fs-extra") const { budibaseAppsDir } = require("../../utilities/budibaseDir") diff --git a/packages/server/src/api/controllers/page.js b/packages/server/src/api/controllers/page.js index 06bd887453..4f3989ae90 100644 --- a/packages/server/src/api/controllers/page.js +++ b/packages/server/src/api/controllers/page.js @@ -1,6 +1,6 @@ const CouchDB = require("../../db/client") const { generatePageID } = require("../../db/utils") -const { compileStaticAssetsForPage } = require("../../utilities/builder") +const compileStaticAssetsForPage = require("../../utilities/builder/compileStaticAssetsForPage") exports.save = async function(ctx) { const db = new CouchDB(ctx.user.appId) diff --git a/packages/server/src/utilities/builder/compileStaticAssetsForPage.js b/packages/server/src/utilities/builder/compileStaticAssetsForPage.js index f912195b06..598f7745fb 100644 --- a/packages/server/src/utilities/builder/compileStaticAssetsForPage.js +++ b/packages/server/src/utilities/builder/compileStaticAssetsForPage.js @@ -17,12 +17,8 @@ module.exports = async (appId, pageName, pkg) => { await buildFrontendAppDefinition(appId, pageName, pkg, appPath) await copyClientLib(appPath, pageName) - - // await savePageJson(appPath, pageName, pkg) } -// const rootPath = (config, appId) => (config.useAppRootPath ? `/${appId}` : "") - const copyClientLib = async (appPath, pageName) => { const sourcepath = require.resolve("@budibase/client") const destPath = join(publicPath(appPath, pageName), "budibase-client.js") @@ -96,23 +92,3 @@ const buildFrontendAppDefinition = async (appId, pageName, pkg) => { ` ) } - -// const savePageJson = async (appPath, pageName, pkg) => { -// const pageFile = join(appPath, "pages", pageName, "page.json") - -// if (pkg.page._css) { -// delete pkg.page._css -// } - -// if (pkg.page.name) { -// delete pkg.page.name -// } - -// if (pkg.page._screens) { -// delete pkg.page._screens -// } - -// await writeJSON(pageFile, pkg.page, { -// spaces: 2, -// }) -// } diff --git a/packages/server/src/utilities/builder/getPages.js b/packages/server/src/utilities/builder/getPages.js deleted file mode 100644 index e7d4856d0a..0000000000 --- a/packages/server/src/utilities/builder/getPages.js +++ /dev/null @@ -1,20 +0,0 @@ -// const { readJSON, readdir } = require("fs-extra") -// const { join } = require("../centralPath") - -// module.exports = async appPath => { -// const pages = {} - -// const pageFolders = await readdir(join(appPath, "pages")) -// for (let pageFolder of pageFolders) { -// try { -// pages[pageFolder] = await readJSON( -// join(appPath, "pages", pageFolder, "page.json") -// ) -// pages[pageFolder].name = pageFolder -// } catch (_) { -// // ignore error -// } -// } - -// return pages -// } diff --git a/packages/server/src/utilities/builder/index.js b/packages/server/src/utilities/builder/index.js deleted file mode 100644 index 015e40244e..0000000000 --- a/packages/server/src/utilities/builder/index.js +++ /dev/null @@ -1,80 +0,0 @@ -// const { appPackageFolder } = require("../createAppPackage") -// const { -// readJSON, -// writeJSON, -// readdir, -// ensureDir, -// rename, -// unlink, -// rmdir, -// } = require("fs-extra") -// const { join } = require("../centralPath") -// const { dirname } = require("path") - -const compileStaticAssetsForPage = require("./compileStaticAssetsForPage") -// const getPages = require("./getPages") -// const listScreens = require("./listScreens") -// const { budibaseAppsDir } = require("../budibaseDir") -// const { budibaseAppsDir } = require("../budibaseDir") - -module.exports.compileStaticAssetsForPage = compileStaticAssetsForPage -// module.exports.listScreens = listScreens - -// const getAppDefinition = async appPath => -// await readJSON(`${appPath}/appDefinition.json`) - -// module.exports.getPackageForBuilder = async application => { -// const appPath = resolve(budibaseAppsDir(), application._id) - -// const pages = await getPages(appPath) - -// return { -// pages, -// application, -// } -// } - -// const screenPath = (appPath, pageName, name) => -// join(appPath, "pages", pageName, "screens", name + ".json") - -// module.exports.saveScreen = async (appId, pagename, screen) => { -// const appPath = join(budibaseAppsDir(), appId) -// const compPath = screenPath(appPath, pagename, screen.props._id) - -// await ensureDir(dirname(compPath)) -// if (screen._css) { -// delete screen._css -// } - -// await writeJSON(compPath, screen, { -// encoding: "utf8", -// flag: "w", -// spaces: 2, -// }) -// return screen -// } - -// module.exports.deleteScreen = async (config, appId, pagename, name) => { -// const appPath = join(budibaseAppsDir(), appId) -// const componentFile = screenPath(appPath, pagename, name) -// await unlink(componentFile) - -// const dir = dirname(componentFile) -// if ((await readdir(dir)).length === 0) { -// await rmdir(dir) -// } -// } - -// module.exports.savePage = async (appId, pagename, page) => { -// const appPath = join(budibaseAppsDir(), appId) -// const pageDir = join(appPath, "pages", pagename) - -// await ensureDir(pageDir) -// await writeJSON(join(pageDir, "page.json"), page, { -// encoding: "utf8", -// flag: "w", -// space: 2, -// }) -// const appDefinition = await getAppDefinition(appPath) -// await compileStaticAssetsForPage(appId, appDefinition, pagename, page) -// } diff --git a/packages/server/src/utilities/builder/listScreens.js b/packages/server/src/utilities/builder/listScreens.js deleted file mode 100644 index 0b6fda3ed8..0000000000 --- a/packages/server/src/utilities/builder/listScreens.js +++ /dev/null @@ -1,48 +0,0 @@ -const { readJSON, readdir, stat } = require("fs-extra") -const { join } = require("../centralPath") -const { keyBy } = require("lodash/fp") -const { budibaseAppsDir } = require("../budibaseDir") - -// module.exports = async (appId, pagename) => { -// const appPath = join(budibaseAppsDir(), appId) -// return keyBy("name")(await fetchscreens(appPath, pagename)) -// } - -// const fetchscreens = async (appPath, pagename, relativePath = "") => { -// const currentDir = join(appPath, "pages", pagename, "screens", relativePath) - -// const contents = await readdir(currentDir) - -// const screens = [] - -// for (let item of contents) { -// const itemRelativePath = join(relativePath, item) -// const itemFullPath = join(currentDir, item) -// const stats = await stat(itemFullPath) - -// if (stats.isFile()) { -// if (!item.endsWith(".json")) continue - -// const component = await readJSON(itemFullPath) - -// component.name = itemRelativePath -// .substring(0, itemRelativePath.length - 5) -// .replace(/\\/g, "/") - -// component.props = component.props || {} - -// screens.push(component) -// } else { -// const childComponents = await fetchscreens( -// appPath, -// join(relativePath, item) -// ) - -// for (let c of childComponents) { -// screens.push(c) -// } -// } -// } - -// return screens -// } diff --git a/packages/server/src/utilities/createAppPackage.js b/packages/server/src/utilities/createAppPackage.js index af943d260e..a62e8c96df 100644 --- a/packages/server/src/utilities/createAppPackage.js +++ b/packages/server/src/utilities/createAppPackage.js @@ -1,5 +1,3 @@ -const { resolve } = require("./centralPath") -const { cwd } = require("process") const stream = require("stream") const fetch = require("node-fetch") const tar = require("tar-fs")