adding in routes for components and pages
This commit is contained in:
parent
70082147c7
commit
4891c6de80
|
@ -1,10 +1,14 @@
|
|||
import {hierarchy as hierarchyFunctions,
|
||||
common, getTemplateApi } from "budibase-core";
|
||||
import {filter, cloneDeep, sortBy, map, last,
|
||||
import {filter, cloneDeep, sortBy, map, last, keys,
|
||||
cloneDeep, keyBy,
|
||||
find, isEmpty, groupBy, reduce} from "lodash/fp";
|
||||
import {chain, getNode, validate,
|
||||
constructHierarchy, templateApi} from "../common/core";
|
||||
import {writable} from "svelte/store";
|
||||
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
|
||||
|
||||
const pipe = common.$;
|
||||
|
||||
export const getStore = () => {
|
||||
|
||||
|
@ -14,6 +18,11 @@ export const getStore = () => {
|
|||
hierarchy: {},
|
||||
actions: [],
|
||||
triggers: [],
|
||||
pages:defaultPagesObject(),
|
||||
mainUi:{},
|
||||
unauthenticatedUi:{},
|
||||
derivedComponents:[],
|
||||
rootComponents:[],
|
||||
currentNodeIsNew: false,
|
||||
errors: [],
|
||||
activeNav: "database",
|
||||
|
@ -41,6 +50,9 @@ export const getStore = () => {
|
|||
store.saveLevel = saveLevel(store);
|
||||
store.deleteLevel = deleteLevel(store);
|
||||
store.setActiveNav = setActiveNav(store);
|
||||
store.saveDerivedComponent = saveDerivedComponent(store);
|
||||
store.refreshComponents = refreshComponents(store);
|
||||
store.addComponentLibrary = addComponentLibrary(store);
|
||||
return store;
|
||||
}
|
||||
|
||||
|
@ -312,30 +324,107 @@ const deleteLevel = store => level => {
|
|||
});
|
||||
}
|
||||
|
||||
const setActiveNav = databaseStore => navName => {
|
||||
databaseStore.update(db => {
|
||||
db.activeNav = navName;
|
||||
return db;
|
||||
const setActiveNav = store => navName => {
|
||||
store.update(s => {
|
||||
s.activeNav = navName;
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
const createShadowHierarchy = hierarchy =>
|
||||
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)));
|
||||
|
||||
const savePackage = (store, db) => {
|
||||
const saveDerivedComponent = store => (derivedComponent) => {
|
||||
|
||||
store.update(s => {
|
||||
|
||||
const derivedComponents = pipe(s.derivedComponents, [
|
||||
filter(c => c._name !== derivedComponent._name)
|
||||
]);
|
||||
|
||||
s.derivedComponents = derivedComponents;
|
||||
|
||||
const forSave = pipe(derivedComponents, [
|
||||
cloneDeep,
|
||||
keyBy("_name")
|
||||
]);
|
||||
|
||||
for(let c of forSave) {
|
||||
delete c._name;
|
||||
}
|
||||
|
||||
s.pages.derivedComponents = forSave;
|
||||
savePackage(store, s);
|
||||
|
||||
return s;
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
const addComponentLibrary = store => async lib => {
|
||||
|
||||
const response =
|
||||
await fetch(`/_builder/api/${db.appname}/components?${encodeURI(lib)}`);
|
||||
|
||||
const success = response.status === 200;
|
||||
|
||||
const error = response.status === 404
|
||||
? `Could not find library ${lib}`
|
||||
: success
|
||||
? ""
|
||||
: response.statusText;
|
||||
|
||||
const components = success
|
||||
? await response.json()
|
||||
: [];
|
||||
|
||||
store.update(s => {
|
||||
s.componentsErrors.addComponent = error;
|
||||
if(success) {
|
||||
s.pages.componentLibraries.push(lib);
|
||||
s.rootComponents = [...s.rootComponents, components];
|
||||
}
|
||||
|
||||
return s;
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
const refreshComponents = store => async () => {
|
||||
|
||||
const components =
|
||||
await fetch(`/_builder/api/${db.appname}/components`)
|
||||
.then(r => jQuery.json());
|
||||
|
||||
const rootComponents = pipe(components, [
|
||||
keys,
|
||||
map(k => ({...components[k], _name:k}))
|
||||
]);
|
||||
|
||||
store.update(s => {
|
||||
s.rootComponents = rootComponents;
|
||||
return s;
|
||||
});
|
||||
};
|
||||
|
||||
const savePackage = (store, s) => {
|
||||
|
||||
const appDefinition = {
|
||||
hierarchy:db.hierarchy,
|
||||
triggers:db.triggers,
|
||||
actions: groupBy("name")(db.actions)
|
||||
hierarchy:s.hierarchy,
|
||||
triggers:s.triggers,
|
||||
actions: groupBy("name")(s.actions),
|
||||
pages:s.pages,
|
||||
mainUi: s.mainUi,
|
||||
unauthenticatedUi: s.unauthenticatedUi
|
||||
};
|
||||
|
||||
const data = {
|
||||
appDefinition,
|
||||
accessLevels:db.accessLevels
|
||||
accessLevels:s.accessLevels
|
||||
}
|
||||
|
||||
fetch(`/_builder/api/${db.appname}/appPackage`, {
|
||||
fetch(`/_builder/api/${s.appname}/appPackage`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
export const defaultPagesObject = () => ({
|
||||
main: {
|
||||
index: {
|
||||
_component : "./components/indexHtml"
|
||||
},
|
||||
appBody: "bbapp.main.json"
|
||||
},
|
||||
unauthenticated: {
|
||||
index: {
|
||||
_component : "./components/indexHtml"
|
||||
},
|
||||
appBody: "bbapp.unauthenticated.json"
|
||||
},
|
||||
componentLibraries: ["./components"],
|
||||
derivedComponents:[]
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import {
|
||||
validatePages,
|
||||
validatePage
|
||||
} from "../src/userInterface/propsDefinitionParsing/validatePages";
|
||||
} from "../src/userInterface/pagesParsing/validatePages";
|
||||
|
||||
const validPages = () => ({
|
||||
"main" : {
|
||||
|
@ -85,8 +85,37 @@ describe("validate pages", () => {
|
|||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
it("should return error when index is not set, or set incorrectly", () => {
|
||||
it("should return error when component libraries not set", () => {
|
||||
const pages = validPages();
|
||||
|
||||
delete pages.componentLibraries;
|
||||
let errors = validatePages(pages, getComponent);
|
||||
expect(errors.length).toBe(1);
|
||||
|
||||
pages.componentLibraries = [];
|
||||
errors = validatePages(pages, getComponent);
|
||||
expect(errors.length).toBe(1);
|
||||
|
||||
});
|
||||
|
||||
it("should return error when no main or unauthenticated page", () => {
|
||||
|
||||
let pages = validPages();
|
||||
delete pages.main;
|
||||
let errors = validatePages(pages, getComponent);
|
||||
expect(errors.length).toBe(1);
|
||||
|
||||
pages = validPages();
|
||||
delete pages.unauthenticated;
|
||||
errors = validatePages(pages, getComponent);
|
||||
expect(errors.length).toBe(1);
|
||||
|
||||
});
|
||||
|
||||
it("should return error when page is invalid", () => {
|
||||
const pages = validPages();
|
||||
delete pages.main.index;
|
||||
const errors = validatePages(pages, getComponent);
|
||||
expect(errors.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"textbox" : {
|
||||
"path": "./textbox",
|
||||
"name": "Textbox",
|
||||
"description": "A text input, with a label",
|
||||
"props": {
|
||||
"label": "string"
|
||||
},
|
||||
"tags": ["textboxt", "input", "text"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"main" : {
|
||||
"index" : {
|
||||
|
||||
},
|
||||
"appBody" : "./main.app.json"
|
||||
},
|
||||
"unauthenticated" : {
|
||||
"index" : {
|
||||
"_component": "budibase-components/indexHtml",
|
||||
"title": "Test App 1 - Login",
|
||||
"customScripts": [
|
||||
"MyCustomComponents.js"
|
||||
]
|
||||
},
|
||||
"appBody" : "./unauthenticated.app.json"
|
||||
},
|
||||
"componentLibraries": ["./myComponents"]
|
||||
}
|
|
@ -4,7 +4,7 @@ const StatusCodes = require("../utilities/statusCodes");
|
|||
const fs = require("fs");
|
||||
const { resolve } = require("path");
|
||||
const send = require('koa-send');
|
||||
const { getPackageForBuilder,
|
||||
const { getPackageForBuilder, getComponents,
|
||||
savePackage, getApps } = require("../utilities/builder");
|
||||
|
||||
const builderPath = resolve(__dirname, "../builder");
|
||||
|
@ -152,6 +152,27 @@ module.exports = (config, app) => {
|
|||
ctx.request.body);
|
||||
ctx.response.status = StatusCodes.OK;
|
||||
})
|
||||
.get("/_builder/api/:appname/components", async (ctx) => {
|
||||
if(!config.dev) {
|
||||
ctx.request.status = StatusCodes.FORBIDDEN;
|
||||
ctx.body = "run in dev mode to access builder";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ctx.body = getComponents(
|
||||
config,
|
||||
ctx.params.appname,
|
||||
ctx.query.lib);
|
||||
ctx.response.status = StatusCodes.OK;
|
||||
} catch(e) {
|
||||
if(e.status) {
|
||||
ctx.response.status = e.status;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
})
|
||||
.get("/:appname", async (ctx) => {
|
||||
await send(ctx, "/index.html", { root: ctx.publicPath });
|
||||
})
|
||||
|
|
|
@ -7,7 +7,7 @@ module.exports = (app) => {
|
|||
const response = await app.get("/testApp")
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
const expectedIndexHtml = await readFile("appPackages/testApp/ui/unauthenticated/public/index.html", "utf8");
|
||||
const expectedIndexHtml = await readFile("appPackages/testApp/public/unauthenticated/index.html", "utf8");
|
||||
|
||||
expect(response.text).toBe(expectedIndexHtml);
|
||||
|
||||
|
@ -17,7 +17,7 @@ module.exports = (app) => {
|
|||
const response = await app.get("/testApp/app.js")
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
const expectedFile = await readFile("appPackages/testApp/ui/unauthenticated/public/app.js", "utf8");
|
||||
const expectedFile = await readFile("appPackages/testApp/public/unauthenticated/app.js", "utf8");
|
||||
|
||||
expect(response.text).toBe(expectedFile);
|
||||
|
||||
|
@ -28,7 +28,7 @@ module.exports = (app) => {
|
|||
.set("cookie", app.credentials.testAppUser1.cookie)
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
const expectedIndexHtml = await readFile("appPackages/testApp/ui/main/public/index.html", "utf8");
|
||||
const expectedIndexHtml = await readFile("appPackages/testApp/public/main/index.html", "utf8");
|
||||
|
||||
expect(response.text).toBe(expectedIndexHtml);
|
||||
|
||||
|
@ -39,7 +39,7 @@ module.exports = (app) => {
|
|||
.set("cookie", app.credentials.testAppUser1.cookie)
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
const expectedFile = await readFile("appPackages/testApp/ui/main/public/app.js", "utf8");
|
||||
const expectedFile = await readFile("appPackages/testApp/public/main/app.js", "utf8");
|
||||
|
||||
expect(response.text).toBe(expectedFile);
|
||||
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
const { appPackageFolder, appsFolder } = require("./createAppPackage");
|
||||
const { writeFile, readFile, readdir } = require("./fsawait");
|
||||
const { pipe : $ } = require("budibase-core").common;
|
||||
const {
|
||||
appPackageFolder,
|
||||
appsFolder
|
||||
} = require("./createAppPackage");
|
||||
const {
|
||||
writeFile,
|
||||
readFile,
|
||||
readdir,
|
||||
exists
|
||||
} = require("./fsawait");
|
||||
const { resolve } = require("path");
|
||||
const { $ } = require("budibase-core").common;
|
||||
const {
|
||||
keys,
|
||||
reduce,
|
||||
map,
|
||||
flatten,
|
||||
some
|
||||
} = require("lodash/fp");
|
||||
|
||||
module.exports.getPackageForBuilder = async (config, appname) => {
|
||||
const appPath = appPackageFolder(config, appname);
|
||||
|
@ -11,12 +27,15 @@ module.exports.getPackageForBuilder = async (config, appname) => {
|
|||
|
||||
accessLevels: JSON.parse(await readFile(
|
||||
`${appPath}/access_levels.json`,
|
||||
"utf8")),
|
||||
|
||||
pages: JSON.parse(await readFile(
|
||||
`${appPath}/pages.json`,
|
||||
"utf8"))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
module.exports.savePackage = async (config, appname, pkg) => {
|
||||
const appPath = appPackageFolder(config, appname);
|
||||
await writeFile(
|
||||
|
@ -29,10 +48,68 @@ module.exports.savePackage = async (config, appname, pkg) => {
|
|||
JSON.stringify(pkg.accessLevels),
|
||||
"utf8");
|
||||
|
||||
await writeFile(
|
||||
`${appPath}/pages.json`,
|
||||
JSON.stringify(pkg.accessLevels),
|
||||
"utf8");
|
||||
}
|
||||
|
||||
module.exports.getApps = async (config) =>
|
||||
await readdir(appsFolder(config));
|
||||
|
||||
|
||||
module.exports.getComponents = async (config, appname, lib) => {
|
||||
|
||||
const componentsInLibrary = (libname) => {
|
||||
const isRelative = some(c => c === libname.substring(0,1))
|
||||
("./~\\".split(""));
|
||||
|
||||
const componentsPath = isRelative
|
||||
? resolve(appPath, libname, "components.json")
|
||||
: resolve(libname, "components.json");
|
||||
|
||||
if(!await exists(componentsPath)) {
|
||||
const e = new Error(`could not find components definition file at ${componentsPath}`);
|
||||
e.statusCode = 404;
|
||||
throw e;
|
||||
}
|
||||
|
||||
let components;
|
||||
try {
|
||||
components = JSON.parse(
|
||||
readFile(componentsPath, "utf8"));
|
||||
} catch(e) {
|
||||
const e = new Error(`could not parse JSON - ${componentsPath} `);
|
||||
throw e;
|
||||
}
|
||||
|
||||
return $(components, [
|
||||
keys,
|
||||
reduce((obj, k) => {
|
||||
obj[`${libname}/${k}`] = components[k]
|
||||
return obj;
|
||||
}, {})
|
||||
])
|
||||
}
|
||||
|
||||
let libs;
|
||||
if(!lib) {
|
||||
const appPath = appPackageFolder(config, appname);
|
||||
|
||||
const pages = JSON.parse(await readFile(
|
||||
`${appPath}/pages.json`,
|
||||
"utf8"));
|
||||
|
||||
if(!pages.componentLibraries) return [];
|
||||
|
||||
libs = pages.componentLibraries;
|
||||
} else {
|
||||
libs = [lib];
|
||||
}
|
||||
|
||||
return $(libs, [
|
||||
map(componentsInLibrary),
|
||||
flatten
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,9 +65,9 @@ const applictionVersionPath = (appname, versionId) =>
|
|||
|
||||
const publicPaths = (appPath) => ({
|
||||
mainUiPath: resolve(join(
|
||||
__dirname, appPath, "ui", "main", "public")),
|
||||
__dirname, appPath, "public", "main")),
|
||||
unauthenticatedUiPath: resolve(join(
|
||||
__dirname, appPath, "ui", "unauthenticated", "public"))
|
||||
__dirname, appPath, "public", "unauthenticated"))
|
||||
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue