forked from tsai/budibase
5 changed files with 433 additions and 0 deletions
@ -0,0 +1,134 @@ |
|||
const { |
|||
appPackageFolder |
|||
} = require("../createAppPackage"); |
|||
const { componentLibraryInfo } = require("./componentLibraryInfo"); |
|||
const { |
|||
stat, ensureDir, pathExists, |
|||
constants, copyFile, writeFile, |
|||
readFile |
|||
} = require("fs-extra"); |
|||
const { join, resolve, dirname } = require("path"); |
|||
const sqrl = require('squirrelly'); |
|||
|
|||
module.exports = async (config, appname, pages, appdefinition) => { |
|||
|
|||
const appPath = appPackageFolder(config, appname); |
|||
|
|||
await buildClientAppDefinition( |
|||
config, appname, |
|||
appdefinition, |
|||
appPath, pages, "main"); |
|||
|
|||
await buildClientAppDefinition( |
|||
config, appname, |
|||
appdefinition, |
|||
appPath, pages, "unauthenticated") |
|||
|
|||
await buildIndexHtml( |
|||
config, appname, appPath, |
|||
pages, "main"); |
|||
|
|||
await buildIndexHtml( |
|||
config, appname, appPath, |
|||
pages, "unauthenticated"); |
|||
|
|||
await copyClientLib(appPath, "main"); |
|||
await copyClientLib(appPath, "unauthenticated"); |
|||
|
|||
} |
|||
|
|||
const publicPath = (appPath, pageName) => join(appPath, "public", pageName); |
|||
const rootPath = (config, appname) => config.useAppRootPath ? `/${appname}` : ""; |
|||
|
|||
const copyClientLib = async (appPath, pageName) => { |
|||
var sourcepath = require.resolve("@budibase/client"); |
|||
var destPath = join(publicPath(appPath, pageName), "budibase-client.js"); |
|||
|
|||
await copyFile(sourcepath, destPath, constants.COPYFILE_FICLONE); |
|||
await copyFile(sourcepath + ".map", destPath + ".map", constants.COPYFILE_FICLONE); |
|||
|
|||
} |
|||
|
|||
const buildIndexHtml = async (config, appname, appPath, pages, pageName) => { |
|||
|
|||
|
|||
const appPublicPath = publicPath(appPath, pageName); |
|||
const appRootPath = rootPath(config, appname); |
|||
|
|||
const stylesheetUrl = s => |
|||
s.indexOf('http://') === 0 || s.indexOf('https://') === 0 |
|||
? s |
|||
: `/${rootPath(config, appname)}/${s}`; |
|||
|
|||
const templateObj = { |
|||
title: pages[pageName].index.title || "Budibase App", |
|||
favicon: `${appRootPath}/${pages[pageName].index.favicon || "/_shared/favicon.png"}`, |
|||
stylesheets: (pages.stylesheets || []).map(stylesheetUrl), |
|||
appRootPath |
|||
} |
|||
|
|||
const indexHtmlTemplate = await readFile( |
|||
resolve(__dirname, "index.template.html"), "utf8"); |
|||
|
|||
const indexHtmlPath = join(appPublicPath, "index.html"); |
|||
|
|||
const indexHtml = sqrl.Render(indexHtmlTemplate, templateObj) |
|||
|
|||
await writeFile( |
|||
indexHtmlPath, |
|||
indexHtml, |
|||
{flag:"w+"}); |
|||
|
|||
} |
|||
|
|||
|
|||
const buildClientAppDefinition = async (config, appname, appdefinition, appPath, pages, pageName) => { |
|||
|
|||
|
|||
const appPublicPath = publicPath(appPath, pageName); |
|||
const appRootPath = rootPath(config, appname); |
|||
|
|||
|
|||
const componentLibraries = []; |
|||
|
|||
for(let lib of pages.componentLibraries) { |
|||
const info = await componentLibraryInfo(appPath, lib); |
|||
const libFile = info.components._lib || "index.js"; |
|||
const source = join(info.libDir, libFile); |
|||
const moduleDir = join(appPublicPath, "lib", info.libDir.replace(appPath, "")); |
|||
const destPath = join(moduleDir, libFile); |
|||
|
|||
await ensureDir(dirname(destPath)); |
|||
|
|||
componentLibraries.push({ |
|||
importPath: destPath.replace(appPublicPath, "") |
|||
.replace(/\\/g, "/"), |
|||
libName: lib |
|||
}); |
|||
|
|||
let shouldCopy = !(await pathExists(destPath)); |
|||
if(!shouldCopy) { |
|||
const destStat = await stat(destPath); |
|||
const sourceStat = await stat(source); |
|||
shouldCopy = destStat.ctimeMs !== sourceStat.ctimeMs; |
|||
} |
|||
|
|||
if(shouldCopy) { |
|||
await copyFile(source, destPath, constants.COPYFILE_FICLONE); |
|||
} |
|||
|
|||
} |
|||
|
|||
const filename = join(appPublicPath, "clientAppDefinition.js"); |
|||
|
|||
const clientAppDefObj = { |
|||
hierarchy: appdefinition.hierarchy, |
|||
componentLibraries: componentLibraries, |
|||
appRootPath: appRootPath, |
|||
props: appdefinition.props[pageName] |
|||
} |
|||
|
|||
await writeFile(filename, |
|||
`window['##BUDIBASE_APPDEFINITION##'] = ${JSON.stringify(clientAppDefObj)}`); |
|||
|
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
const { |
|||
readJSON, exists |
|||
} = require("fs-extra"); |
|||
const { |
|||
resolve, join , dirname |
|||
} = require("path"); |
|||
|
|||
const getLibDir = (appPath, libname) => { |
|||
try { |
|||
const componentsFile = require.resolve( |
|||
join(libname, "components.json"), |
|||
{ paths: [appPath]}); |
|||
return dirname(componentsFile); |
|||
} catch(e) { |
|||
console.log(e); |
|||
} |
|||
} |
|||
|
|||
const getComponentsFilepath = libPath => |
|||
resolve(libPath, "components.json"); |
|||
|
|||
module.exports.componentsFilepath = (appPath, libname) => |
|||
getComponentsFilepath(getLibDir(appPath, libname)); |
|||
|
|||
module.exports.componentLibraryInfo = async (appPath, libname) => { |
|||
|
|||
const libDir = getLibDir(appPath, libname); |
|||
const componentsPath = getComponentsFilepath(libDir); |
|||
|
|||
if(!await exists(componentsPath)) { |
|||
const e = new Error(`could not find components definition file at ${componentsPath}`); |
|||
e.statusCode = 404; |
|||
throw e; |
|||
} |
|||
|
|||
try { |
|||
const components = await readJSON(componentsPath); |
|||
const namespacedComponents = {_lib:components._lib}; |
|||
for(let cname in components) { |
|||
if(cname === "_lib" || cname == "_generators") continue; |
|||
const namespacedName = `${libname}/${cname}`; |
|||
components[cname].name = namespacedName; |
|||
namespacedComponents[namespacedName] = components[cname]; |
|||
} |
|||
|
|||
const namespacedGenerators = {} |
|||
if(components._generators) { |
|||
namespacedGenerators._lib=components._generators._lib || "generators.js"; |
|||
for(let gname in components._generators) { |
|||
if(gname === "_lib") continue; |
|||
const namespacedName = `${libname}/${gname}`; |
|||
components._generators[gname].name = namespacedName; |
|||
namespacedGenerators[namespacedName] = components._generators[gname]; |
|||
} |
|||
} |
|||
|
|||
return ({ |
|||
components: namespacedComponents, |
|||
generators: namespacedGenerators, |
|||
libDir, |
|||
componentsPath |
|||
}); |
|||
} catch(e) { |
|||
const err = `could not parse JSON - ${componentsPath} : ${e.message}`; |
|||
throw new Error(err); |
|||
} |
|||
} |
|||
@ -0,0 +1,175 @@ |
|||
const { |
|||
appPackageFolder, |
|||
appsFolder |
|||
} = require("../createAppPackage"); |
|||
const { |
|||
readJSON, writeJSON, readdir, |
|||
stat, ensureDir, rename, |
|||
unlink, rmdir |
|||
} = require("fs-extra"); |
|||
const { |
|||
join,dirname |
|||
} = require("path"); |
|||
const { $ } = require("@budibase/core").common; |
|||
const { |
|||
keyBy, intersection, map |
|||
} = require("lodash/fp"); |
|||
const {merge} = require("lodash"); |
|||
|
|||
const { componentLibraryInfo } = require("./componentLibraryInfo"); |
|||
const savePackage = require("./savePackage"); |
|||
const buildApp = require("./buildApp"); |
|||
|
|||
module.exports.savePackage = savePackage; |
|||
|
|||
const getPages = async (appPath) => await readJSON(`${appPath}/pages.json`); |
|||
const getAppDefinition = async (appPath) => await readJSON(`${appPath}/appDefinition.json`); |
|||
|
|||
module.exports.getPackageForBuilder = async (config, appname) => { |
|||
const appPath = appPackageFolder(config, appname); |
|||
|
|||
const pages = await getPages(appPath); |
|||
|
|||
return ({ |
|||
appDefinition: await getAppDefinition(appPath), |
|||
|
|||
accessLevels: await readJSON(`${appPath}/access_levels.json`), |
|||
|
|||
pages, |
|||
|
|||
components: await getComponents(appPath, pages), |
|||
|
|||
screens: keyBy("name")( |
|||
await fetchscreens(appPath)) |
|||
}); |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
module.exports.getApps = async (config, master) => { |
|||
const dirs = await readdir(appsFolder(config)); |
|||
|
|||
return $(master.listApplications(), [ |
|||
map(a => a.name), |
|||
intersection(dirs) |
|||
]); |
|||
} |
|||
|
|||
|
|||
const componentPath = (appPath, name) => |
|||
join(appPath, "components", name + ".json"); |
|||
|
|||
module.exports.saveScreen = async (config, appname, component) => { |
|||
const appPath = appPackageFolder(config, appname); |
|||
const compPath = componentPath(appPath, component.name); |
|||
await ensureDir(dirname(compPath)); |
|||
await writeJSON( |
|||
compPath, |
|||
component, |
|||
{encoding:"utf8", flag:"w", spaces:2}); |
|||
} |
|||
|
|||
module.exports.renameScreen = async (config, appname, oldName, newName) => { |
|||
const appPath = appPackageFolder(config, appname); |
|||
|
|||
const oldComponentPath = componentPath( |
|||
appPath, oldName); |
|||
|
|||
const newComponentPath = componentPath( |
|||
appPath, newName); |
|||
|
|||
await ensureDir(dirname(newComponentPath)); |
|||
await rename( |
|||
oldComponentPath, |
|||
newComponentPath); |
|||
} |
|||
|
|||
module.exports.deleteScreen = async (config, appname, name) => { |
|||
const appPath = appPackageFolder(config, appname); |
|||
const componentFile = componentPath(appPath, name); |
|||
await unlink(componentFile); |
|||
|
|||
const dir = dirname(componentFile); |
|||
if((await readdir(dir)).length === 0) { |
|||
await rmdir(dir); |
|||
} |
|||
} |
|||
|
|||
module.exports.componentLibraryInfo = async (config, appname, lib) => { |
|||
const appPath = appPackageFolder(config, appname); |
|||
return await componentLibraryInfo(appPath, lib); |
|||
}; |
|||
|
|||
|
|||
const getComponents = async (appPath, pages ,lib) => { |
|||
|
|||
let libs; |
|||
if(!lib) { |
|||
pages = pages || await readJSON( |
|||
`${appPath}/pages.json`); |
|||
|
|||
if(!pages.componentLibraries) return []; |
|||
|
|||
libs = pages.componentLibraries; |
|||
} else { |
|||
libs = [lib]; |
|||
} |
|||
|
|||
const components = {}; |
|||
const generators = {}; |
|||
|
|||
for(let l of libs) { |
|||
const info = await componentLibraryInfo(appPath, l); |
|||
merge(components, info.components); |
|||
merge(generators, info.generators); |
|||
} |
|||
|
|||
if(components._lib) delete components._lib; |
|||
if(components._generators) delete components._generators; |
|||
|
|||
return {components, generators}; |
|||
} |
|||
|
|||
const fetchscreens = async (appPath, relativePath = "") => { |
|||
|
|||
const currentDir = join(appPath, "components", relativePath); |
|||
|
|||
const contents = await readdir(currentDir); |
|||
|
|||
const components = []; |
|||
|
|||
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 || {}; |
|||
|
|||
components.push(component); |
|||
} else { |
|||
const childComponents = await fetchscreens( |
|||
appPath, join(relativePath, item) |
|||
); |
|||
|
|||
for(let c of childComponents) { |
|||
components.push(c); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return components; |
|||
} |
|||
|
|||
module.exports.getComponents = getComponents; |
|||
@ -0,0 +1,32 @@ |
|||
<!doctype html> |
|||
<html> |
|||
<head> |
|||
<meta charset='utf8'> |
|||
<meta name='viewport' content='width=device-width'> |
|||
|
|||
<title>{{ title }}</title> |
|||
<link rel='icon' type='image/png' href='{{ favicon }}'> |
|||
|
|||
<style> |
|||
html, body { |
|||
height: 100%; |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
|
|||
{{ each(options.stylesheets) }} |
|||
<link rel='stylesheet' href='{{ @this }}'> |
|||
{{ /each }} |
|||
|
|||
<script src='{{ appRootPath }}/clientAppDefinition.js'></script> |
|||
<script src='{{ appRootPath }}/budibase-client.js'></script> |
|||
<script> |
|||
loadBudibase(); |
|||
</script> |
|||
|
|||
</head> |
|||
|
|||
<body id="app"> |
|||
|
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,25 @@ |
|||
const { appPackageFolder } = require("../createAppPackage"); |
|||
const { writeJSON } = require("fs-extra"); |
|||
const buildApp = require("./buildApp"); |
|||
|
|||
module.exports = async (config, appname, pkg) => { |
|||
const appPath = appPackageFolder(config, appname); |
|||
await writeJSON( |
|||
`${appPath}/appDefinition.json`, |
|||
pkg.appDefinition, |
|||
{spaces:2}); |
|||
|
|||
await writeJSON( |
|||
`${appPath}/access_levels.json`, |
|||
pkg.accessLevels, |
|||
{spaces:2}); |
|||
|
|||
await writeJSON( |
|||
`${appPath}/pages.json`, |
|||
pkg.pages, |
|||
{spaces:2}); |
|||
|
|||
await buildApp( |
|||
config, appname, |
|||
pkg.pages, pkg.appDefinition); |
|||
} |
|||
Loading…
Reference in new issue