Updating templates to be able to run locally with an environment variable LOCAL_TEMPLATES and making them work using the DB. Users are also no longer included in the db dump.
This commit is contained in:
parent
d57368eb8b
commit
e353c2a1c4
|
@ -1,23 +1,15 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { get, writable } from "svelte/store"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import {cloneDeep} from "lodash/fp"
|
||||||
import {
|
import { createProps, getBuiltin, makePropsSafe } from "components/userInterface/pagesParsing/createProps"
|
||||||
createProps,
|
|
||||||
makePropsSafe,
|
|
||||||
getBuiltin,
|
|
||||||
} from "components/userInterface/pagesParsing/createProps"
|
|
||||||
import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents"
|
import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents"
|
||||||
import { backendUiStore, allScreens } from "builderStore"
|
import {allScreens, backendUiStore } from "builderStore"
|
||||||
import { generate_screen_css } from "../generate_css"
|
import { generate_screen_css } from "../generate_css"
|
||||||
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
import { DEFAULT_PAGES_OBJECT } from "../../constants"
|
import { DEFAULT_PAGES_OBJECT } from "../../constants"
|
||||||
import getNewComponentName from "../getNewComponentName"
|
import getNewComponentName from "../getNewComponentName"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import {
|
import { findChildComponentType, generateNewIdsForComponent, getComponentDefinition, getParent } from "../storeUtils"
|
||||||
getParent,
|
|
||||||
generateNewIdsForComponent,
|
|
||||||
getComponentDefinition, findChildComponentType,
|
|
||||||
} from "../storeUtils"
|
|
||||||
|
|
||||||
const INITIAL_FRONTEND_STATE = {
|
const INITIAL_FRONTEND_STATE = {
|
||||||
apps: [],
|
apps: [],
|
||||||
|
@ -332,8 +324,7 @@ export const getFrontendStore = () => {
|
||||||
...presetProps,
|
...presetProps,
|
||||||
_instanceId: instanceId,
|
_instanceId: instanceId,
|
||||||
_instanceName: instanceName,
|
_instanceName: instanceName,
|
||||||
},
|
}
|
||||||
state
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const currentComponent =
|
const currentComponent =
|
||||||
|
@ -367,8 +358,7 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
copy: (component, cut = false) => {
|
copy: (component, cut = false) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const copiedComponent = cloneDeep(component)
|
state.componentToPaste = cloneDeep(component)
|
||||||
state.componentToPaste = copiedComponent
|
|
||||||
state.componentToPaste.isCut = cut
|
state.componentToPaste.isCut = cut
|
||||||
if (cut) {
|
if (cut) {
|
||||||
const parent = getParent(
|
const parent = getParent(
|
||||||
|
@ -469,9 +459,7 @@ export const getFrontendStore = () => {
|
||||||
const IdList = allComponents.map(c => c._id)
|
const IdList = allComponents.map(c => c._id)
|
||||||
|
|
||||||
// Construct ID Path:
|
// Construct ID Path:
|
||||||
const path = IdList.join("/")
|
return IdList.join("/")
|
||||||
|
|
||||||
return path
|
|
||||||
},
|
},
|
||||||
links: {
|
links: {
|
||||||
save: async (url, title) => {
|
save: async (url, title) => {
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <TemplateList onSelect={selectTemplate} /> -->
|
<TemplateList onSelect={selectTemplate} />
|
||||||
|
|
||||||
<AppList />
|
<AppList />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
import { buildCodeForScreens } from "../src/builderStore/buildCodeForScreens"
|
|
||||||
|
|
||||||
describe("buildCodeForScreen", () => {
|
|
||||||
it("should package _code into runnable function, for simple screen props", () => {
|
|
||||||
const screen = {
|
|
||||||
props: {
|
|
||||||
_id: "1234",
|
|
||||||
_code: "render('render argument');",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderArg
|
|
||||||
const render = arg => {
|
|
||||||
renderArg = arg
|
|
||||||
}
|
|
||||||
const uiFunctions = getFunctions(screen)
|
|
||||||
|
|
||||||
const targetfunction = uiFunctions[screen.props._id]
|
|
||||||
expect(targetfunction).toBeDefined()
|
|
||||||
|
|
||||||
targetfunction(render)
|
|
||||||
|
|
||||||
expect(renderArg).toBe("render argument")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should package _code into runnable function, for _children ", () => {
|
|
||||||
const screen = {
|
|
||||||
props: {
|
|
||||||
_id: "parent",
|
|
||||||
_code: "render('parent argument');",
|
|
||||||
_children: [
|
|
||||||
{
|
|
||||||
_id: "child1",
|
|
||||||
_code: "render('child 1 argument');",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "child2",
|
|
||||||
_code: "render('child 2 argument');",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderArg
|
|
||||||
const render = arg => {
|
|
||||||
renderArg = arg
|
|
||||||
}
|
|
||||||
const uiFunctions = getFunctions(screen)
|
|
||||||
|
|
||||||
const targetfunction = uiFunctions["child2"]
|
|
||||||
expect(targetfunction).toBeDefined()
|
|
||||||
|
|
||||||
targetfunction(render)
|
|
||||||
|
|
||||||
expect(renderArg).toBe("child 2 argument")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const getFunctions = screen => {
|
|
||||||
const code = buildCodeForScreens([screen])
|
|
||||||
const func = new Function(`return ${code}`)()
|
|
||||||
return func
|
|
||||||
}
|
|
|
@ -23,6 +23,12 @@ yargs
|
||||||
},
|
},
|
||||||
async args => {
|
async args => {
|
||||||
console.log("Exporting app..")
|
console.log("Exporting app..")
|
||||||
|
if (args.name == null || args.appId == null) {
|
||||||
|
console.error(
|
||||||
|
"Unable to export without a name and app ID being specified, check help for more info."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
const exportPath = await exportTemplateFromApp({
|
const exportPath = await exportTemplateFromApp({
|
||||||
templateName: args.name,
|
templateName: args.name,
|
||||||
appId: args.appId,
|
appId: args.appId,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
const { compileStaticAssetsForPage } = require("../../utilities/builder")
|
const { compileStaticAssetsForPage } = require("../../utilities/builder")
|
||||||
const env = require("../../environment")
|
const env = require("../../environment")
|
||||||
const { copy, existsSync } = require("fs-extra")
|
const { existsSync } = require("fs-extra")
|
||||||
const { budibaseAppsDir } = require("../../utilities/budibaseDir")
|
const { budibaseAppsDir } = require("../../utilities/budibaseDir")
|
||||||
const setBuilderToken = require("../../utilities/builder/setBuilderToken")
|
const setBuilderToken = require("../../utilities/builder/setBuilderToken")
|
||||||
const fs = require("fs-extra")
|
const fs = require("fs-extra")
|
||||||
|
@ -160,21 +160,6 @@ const createEmptyAppPackage = async (ctx, app) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.mkdirpSync(newAppFolder)
|
fs.mkdirpSync(newAppFolder)
|
||||||
// if this app is being created from a template,
|
|
||||||
// copy the frontend page definition files from
|
|
||||||
// the template directory.
|
|
||||||
if (app.template) {
|
|
||||||
const templatePageDefinitions = join(
|
|
||||||
appsFolder,
|
|
||||||
"templates",
|
|
||||||
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"))
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainPage = cloneDeep(MAIN)
|
const mainPage = cloneDeep(MAIN)
|
||||||
mainPage._id = generatePageID()
|
mainPage._id = generatePageID()
|
||||||
mainPage.title = app.name
|
mainPage.title = app.name
|
||||||
|
|
|
@ -8,11 +8,7 @@ exports.save = async function(ctx) {
|
||||||
const appPackage = ctx.request.body
|
const appPackage = ctx.request.body
|
||||||
|
|
||||||
const page = await db.get(ctx.params.pageId)
|
const page = await db.get(ctx.params.pageId)
|
||||||
await compileStaticAssetsForPage(
|
await compileStaticAssetsForPage(ctx.user.appId, page.name, ctx.request.body)
|
||||||
ctx.user.appId,
|
|
||||||
page.name,
|
|
||||||
ctx.request.body
|
|
||||||
)
|
|
||||||
|
|
||||||
// remove special doc props which couch will complain about
|
// remove special doc props which couch will complain about
|
||||||
delete appPackage.page._css
|
delete appPackage.page._css
|
||||||
|
|
|
@ -2,25 +2,34 @@ const fetch = require("node-fetch")
|
||||||
const {
|
const {
|
||||||
downloadTemplate,
|
downloadTemplate,
|
||||||
exportTemplateFromApp,
|
exportTemplateFromApp,
|
||||||
|
getLocalTemplates,
|
||||||
} = require("../../utilities/templates")
|
} = require("../../utilities/templates")
|
||||||
|
const env = require("../../environment")
|
||||||
|
|
||||||
|
// development flag, can be used to test against templates exported locally
|
||||||
const DEFAULT_TEMPLATES_BUCKET =
|
const DEFAULT_TEMPLATES_BUCKET =
|
||||||
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
||||||
|
|
||||||
exports.fetch = async function(ctx) {
|
exports.fetch = async function(ctx) {
|
||||||
const { type = "app" } = ctx.query
|
const { type = "app" } = ctx.query
|
||||||
|
|
||||||
const response = await fetch(
|
if (env.LOCAL_TEMPLATES) {
|
||||||
`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`
|
ctx.body = Object.values(getLocalTemplates()[type])
|
||||||
)
|
} else {
|
||||||
const json = await response.json()
|
const response = await fetch(
|
||||||
ctx.body = Object.values(json.templates[type])
|
`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`
|
||||||
|
)
|
||||||
|
const json = await response.json()
|
||||||
|
ctx.body = Object.values(json.templates[type])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.downloadTemplate = async function(ctx) {
|
exports.downloadTemplate = async function(ctx) {
|
||||||
const { type, name } = ctx.params
|
const { type, name } = ctx.params
|
||||||
|
|
||||||
await downloadTemplate(type, name)
|
if (!env.LOCAL_TEMPLATES) {
|
||||||
|
await downloadTemplate(type, name)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
message: `template ${type}:${name} downloaded successfully.`,
|
message: `template ${type}:${name} downloaded successfully.`,
|
||||||
|
|
|
@ -37,15 +37,22 @@ exports.create = async function(ctx) {
|
||||||
accessLevelId,
|
accessLevelId,
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.post(user)
|
try {
|
||||||
|
const response = await db.post(user)
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.message = "User created successfully."
|
ctx.message = "User created successfully."
|
||||||
ctx.userId = response._id
|
ctx.userId = response._id
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
_rev: response.rev,
|
_rev: response.rev,
|
||||||
username,
|
username,
|
||||||
name,
|
name,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.status === 409) {
|
||||||
|
ctx.throw(400, "User exists already")
|
||||||
|
} else {
|
||||||
|
ctx.throw(err.status, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
const Router = require("@koa/router")
|
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const joiValidator = require("../../middleware/joi-validator")
|
|
||||||
const Joi = require("joi")
|
|
||||||
const {
|
|
||||||
listScreens,
|
|
||||||
saveScreen,
|
|
||||||
compileStaticAssetsForPage,
|
|
||||||
deleteScreen,
|
|
||||||
} = require("../../utilities/builder")
|
|
||||||
const authorized = require("../../middleware/authorized")
|
|
||||||
const { BUILDER } = require("../../utilities/accessLevels")
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
function generatePatchValidation() {
|
|
||||||
return joiValidator.body(
|
|
||||||
Joi.object({
|
|
||||||
oldname: Joi.string().required(),
|
|
||||||
newname: Joi.string().required(),
|
|
||||||
}).unknown(true)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
"/_builder/api/:appId/pages/:pageName",
|
|
||||||
authorized(BUILDER),
|
|
||||||
async ctx => {
|
|
||||||
await compileStaticAssetsForPage(
|
|
||||||
ctx.params.appId,
|
|
||||||
ctx.params.pageName,
|
|
||||||
ctx.request.body
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
"/_builder/api/:appId/pages/:pagename/screens",
|
|
||||||
authorized(BUILDER),
|
|
||||||
async ctx => {
|
|
||||||
ctx.body = await listScreens(ctx.params.appId, ctx.params.pagename)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
"/_builder/api/:appId/pages/:pagename/screen",
|
|
||||||
authorized(BUILDER),
|
|
||||||
generateSaveValidation(),
|
|
||||||
async ctx => {
|
|
||||||
ctx.body = await saveScreen(
|
|
||||||
ctx.config,
|
|
||||||
ctx.params.appId,
|
|
||||||
ctx.params.pagename,
|
|
||||||
ctx.request.body
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.patch(
|
|
||||||
"/_builder/api/:appname/pages/:pagename/screen",
|
|
||||||
authorized(BUILDER),
|
|
||||||
generatePatchValidation(),
|
|
||||||
async ctx => {
|
|
||||||
await renameScreen(
|
|
||||||
ctx.config,
|
|
||||||
ctx.params.appname,
|
|
||||||
ctx.params.pagename,
|
|
||||||
ctx.request.body.oldname,
|
|
||||||
ctx.request.body.newname
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.delete(
|
|
||||||
"/_builder/api/pages/:pagename/screens/:id",
|
|
||||||
authorized(BUILDER),
|
|
||||||
async ctx => {
|
|
||||||
await deleteScreen(
|
|
||||||
ctx.config,
|
|
||||||
ctx.user.appId,
|
|
||||||
ctx.params.pagename,
|
|
||||||
ctx.params.id
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
module.exports = router
|
|
|
@ -34,6 +34,7 @@ module.exports = {
|
||||||
USERID_API_KEY: process.env.USERID_API_KEY,
|
USERID_API_KEY: process.env.USERID_API_KEY,
|
||||||
ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
|
ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
|
||||||
DEPLOYMENT_DB_URL: process.env.DEPLOYMENT_DB_URL,
|
DEPLOYMENT_DB_URL: process.env.DEPLOYMENT_DB_URL,
|
||||||
|
LOCAL_TEMPLATES: process.env.LOCAL_TEMPLATES,
|
||||||
_set(key, value) {
|
_set(key, value) {
|
||||||
process.env[key] = value
|
process.env[key] = value
|
||||||
module.exports[key] = value
|
module.exports[key] = value
|
||||||
|
|
|
@ -8,12 +8,35 @@ const zlib = require("zlib")
|
||||||
const { promisify } = require("util")
|
const { promisify } = require("util")
|
||||||
const streamPipeline = promisify(stream.pipeline)
|
const streamPipeline = promisify(stream.pipeline)
|
||||||
const { budibaseAppsDir } = require("./budibaseDir")
|
const { budibaseAppsDir } = require("./budibaseDir")
|
||||||
|
const env = require("../environment")
|
||||||
const CouchDB = require("../db")
|
const CouchDB = require("../db")
|
||||||
|
const { DocumentTypes } = require("../db/utils")
|
||||||
|
|
||||||
const DEFAULT_TEMPLATES_BUCKET =
|
const DEFAULT_TEMPLATES_BUCKET =
|
||||||
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
||||||
|
|
||||||
|
exports.getLocalTemplates = function() {
|
||||||
|
const templatesDir = join(os.homedir(), ".budibase", "templates", "app")
|
||||||
|
const templateObj = { app: {} }
|
||||||
|
fs.ensureDirSync(templatesDir)
|
||||||
|
const templateNames = fs.readdirSync(templatesDir)
|
||||||
|
for (let name of templateNames) {
|
||||||
|
templateObj.app[name] = {
|
||||||
|
name,
|
||||||
|
category: "local",
|
||||||
|
description: "local template",
|
||||||
|
type: "app",
|
||||||
|
key: `app/${name}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return templateObj
|
||||||
|
}
|
||||||
|
|
||||||
exports.downloadTemplate = async function(type, name) {
|
exports.downloadTemplate = async function(type, name) {
|
||||||
|
const dirName = join(budibaseAppsDir(), "templates", type, name)
|
||||||
|
if (env.LOCAL_TEMPLATES) {
|
||||||
|
return dirName
|
||||||
|
}
|
||||||
const templateUrl = `https://${DEFAULT_TEMPLATES_BUCKET}/templates/${type}/${name}.tar.gz`
|
const templateUrl = `https://${DEFAULT_TEMPLATES_BUCKET}/templates/${type}/${name}.tar.gz`
|
||||||
const response = await fetch(templateUrl)
|
const response = await fetch(templateUrl)
|
||||||
|
|
||||||
|
@ -30,26 +53,27 @@ exports.downloadTemplate = async function(type, name) {
|
||||||
tar.extract(join(budibaseAppsDir(), "templates", type))
|
tar.extract(join(budibaseAppsDir(), "templates", type))
|
||||||
)
|
)
|
||||||
|
|
||||||
return join(budibaseAppsDir(), "templates", type, name)
|
return dirName
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.exportTemplateFromApp = async function({ templateName, appId }) {
|
exports.exportTemplateFromApp = async function({ templateName, appId }) {
|
||||||
// Copy frontend files
|
// Copy frontend files
|
||||||
const appToExport = join(os.homedir(), ".budibase", appId, "pages")
|
const templatesDir = join(
|
||||||
const templatesDir = join(os.homedir(), ".budibase", "templates")
|
os.homedir(),
|
||||||
fs.ensureDirSync(templatesDir)
|
".budibase",
|
||||||
|
"templates",
|
||||||
const templateOutputPath = join(templatesDir, templateName)
|
"app",
|
||||||
fs.copySync(appToExport, join(templateOutputPath, "pages"))
|
templateName,
|
||||||
|
"db"
|
||||||
fs.ensureDirSync(join(templateOutputPath, "db"))
|
|
||||||
const writeStream = fs.createWriteStream(
|
|
||||||
join(templateOutputPath, "db", "dump.txt")
|
|
||||||
)
|
)
|
||||||
|
fs.ensureDirSync(templatesDir)
|
||||||
|
const writeStream = fs.createWriteStream(join(templatesDir, "dump.txt"))
|
||||||
// perform couch dump
|
// perform couch dump
|
||||||
const instanceDb = new CouchDB(appId)
|
const instanceDb = new CouchDB(appId)
|
||||||
|
await instanceDb.dump(writeStream, {
|
||||||
await instanceDb.dump(writeStream)
|
filter: doc => {
|
||||||
return templateOutputPath
|
return !doc._id.startsWith(DocumentTypes.USER)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return templatesDir
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue