Main work to get screens into the DB, fixing up issue with async page updates not being handled in order.

This commit is contained in:
Michael Drury 2020-11-04 12:36:38 +00:00
parent 9e72e122b6
commit c9a1bf1940
10 changed files with 107 additions and 122 deletions

View File

@ -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)
.post(`/api/${currentPage._id}/screens`, screen)
.then(() => {
if (currentPageScreens.includes(screen)) return
const screens = [...currentPageScreens, screen]
store.update(innerState => {
innerState.pages[pageName]._screens = screens
innerState.screens = screens
innerState.currentPreviewItem = 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(
innerState.components[screen.props._component],
state.components[screen.props._component],
screen.props
)
innerState.currentComponentInfo = safeProps
state.currentComponentInfo = safeProps
screen.props = safeProps
_savePage(innerState)
return innerState
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

View File

@ -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) => {

View File

@ -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,
})

View File

@ -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
}

View File

@ -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.`

View File

@ -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())

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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)
}
/**