development setup, adding data components
|
@ -20,7 +20,7 @@
|
|||
"publishdev": "lerna run publishdev",
|
||||
"publishnpm": "yarn build && lerna publish",
|
||||
"clean": "lerna clean",
|
||||
"dev": "lerna run --parallel --stream dev:builder",
|
||||
"dev": "./scripts/symlinkDev.js && lerna run --parallel --stream dev:builder",
|
||||
"test": "lerna run test",
|
||||
"lint": "eslint packages",
|
||||
"lint:fix": "eslint --fix packages",
|
||||
|
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
@ -151,7 +151,7 @@ export default {
|
|||
targets: [
|
||||
{ src: "src/index.html", dest: outputpath },
|
||||
{ src: "src/favicon.png", dest: outputpath },
|
||||
{ src: "src/assets", dest: outputpath },
|
||||
{ src: "assets", dest: outputpath },
|
||||
{
|
||||
src: "node_modules/@budibase/client/dist/budibase-client.esm.mjs",
|
||||
dest: outputpath,
|
||||
|
|
|
@ -161,10 +161,6 @@
|
|||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.select {
|
||||
background: white;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #ccc;
|
||||
background: #fff;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import api from "builderStore/api"
|
||||
|
||||
export async function createUser(user, instanceId) {
|
||||
const CREATE_USER_URL = `/api/${instanceId}/users`
|
||||
export async function createUser(user, appId, instanceId) {
|
||||
const CREATE_USER_URL = `/api/${appId}/${instanceId}/users`
|
||||
const response = await api.post(CREATE_USER_URL, user)
|
||||
const json = await response.json()
|
||||
return json.user;
|
||||
|
@ -21,11 +21,11 @@ export async function deleteRecord(record, instanceId) {
|
|||
return response
|
||||
}
|
||||
|
||||
export async function loadRecord(key, { appname, instanceId }) {
|
||||
const LOAD_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record${key}`
|
||||
const response = await api.get(LOAD_RECORDS_URL)
|
||||
return await response.json()
|
||||
}
|
||||
// export async function loadRecord(key, { appname, instanceId }) {
|
||||
// const LOAD_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record${key}`
|
||||
// const response = await api.get(LOAD_RECORDS_URL)
|
||||
// return await response.json()
|
||||
// }
|
||||
|
||||
export async function saveRecord(record, instanceId) {
|
||||
const SAVE_RECORDS_URL = `/api/${instanceId}/records`
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
$: valid = username && password
|
||||
$: instanceId = $backendUiStore.selectedDatabase.id
|
||||
$: appId = $store.appId
|
||||
|
||||
async function createUser() {
|
||||
const user = { name: username, username, password }
|
||||
const response = await api.createUser(user, instanceId);
|
||||
const response = await api.createUser(user, appId, instanceId);
|
||||
backendUiStore.actions.users.create(response)
|
||||
onClosed()
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
import iframeTemplate from "./iframeTemplate";
|
||||
import { pipe } from "components/common/core"
|
||||
|
||||
|
||||
let iframe
|
||||
let styles = ""
|
||||
|
||||
function transform_component(comp) {
|
||||
const props = comp.props || comp
|
||||
|
@ -24,7 +24,15 @@
|
|||
)
|
||||
)
|
||||
$: hasComponent = !!$store.currentPreviewItem
|
||||
$: styles = hasComponent ? $store.currentPreviewItem._css : ""
|
||||
$: {
|
||||
// Apply the CSS from the currently selected page and its screens
|
||||
const currentPage = $store.pages[$store.currentPageName];
|
||||
styles += currentPage._css;
|
||||
for (let screen of currentPage._screens) {
|
||||
styles += screen._css;
|
||||
}
|
||||
styles = styles
|
||||
}
|
||||
|
||||
$: stylesheetLinks = pipe(
|
||||
$store.pages.stylesheets,
|
||||
|
@ -67,7 +75,7 @@
|
|||
]
|
||||
}
|
||||
}],
|
||||
appRootPath: `/_builder/instance/${$store.appname}/${$backendUiStore.selectedDatabase.id}/`,
|
||||
appRootPath: `/`,
|
||||
}
|
||||
|
||||
$: selectedComponentId = $store.currentComponentInfo ? $store.currentComponentInfo._id : ""
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
const onStyleChanged = store.setComponentStyle
|
||||
|
||||
function getProps(obj, keys) {
|
||||
return keys.map((k, i) => [k, obj[k], obj.props._id + i])
|
||||
return keys.map((key, i) => [key, obj[key], obj.props._id + i])
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -24,17 +24,18 @@
|
|||
<form on:submit|preventDefault class="uk-form-stacked form-root">
|
||||
{#if componentDef}
|
||||
{#each Object.entries(componentDef.props) as [prop_name, prop_def], index}
|
||||
<div class="prop-container">
|
||||
{#if prop_def !== "event"}
|
||||
<div class="prop-container">
|
||||
<PropControl
|
||||
{setProp}
|
||||
{prop_name}
|
||||
prop_value={component[prop_name]}
|
||||
prop_definition={prop_def}
|
||||
{index}
|
||||
disabled={false} />
|
||||
|
||||
<PropControl
|
||||
{setProp}
|
||||
{prop_name}
|
||||
prop_value={component[prop_name]}
|
||||
prop_definition={prop_def}
|
||||
{index}
|
||||
disabled={false} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</form>
|
||||
|
|
|
@ -166,7 +166,23 @@ export default {
|
|||
name: "@budibase/materialdesign-components/recordForm",
|
||||
},
|
||||
children: []
|
||||
}
|
||||
},
|
||||
{
|
||||
_component: "@budibase/standard-components/datatable",
|
||||
name: 'DataTable',
|
||||
description: 'A table for displaying data from the backend.',
|
||||
icon: 'ri-archive-drawer-fill',
|
||||
commonProps: {},
|
||||
children: []
|
||||
},
|
||||
{
|
||||
_component: "@budibase/standard-components/dataform",
|
||||
name: 'DataForm',
|
||||
description: 'Form stuff',
|
||||
icon: 'ri-file-edit-fill',
|
||||
commonProps: {},
|
||||
children: []
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"test": "jest",
|
||||
"publishdev": "yarn build && node ./scripts/publishDev.js"
|
||||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"jest": {
|
||||
"globals": {
|
||||
|
|
|
@ -102,7 +102,6 @@ export default {
|
|||
}),
|
||||
builtins(),
|
||||
nodeglobals(),
|
||||
//terser()
|
||||
],
|
||||
watch: {
|
||||
clearScreen: false,
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
const { readdir, stat, copyFile, ensureDir } = require("fs-extra")
|
||||
const { constants } = require("fs")
|
||||
const { join, basename } = require("path")
|
||||
|
||||
const packagesFolder = ".."
|
||||
|
||||
const jsFile = dir => join(dir, "budibase-client.js")
|
||||
const jsMapFile = dir => join(dir, "budibase-client.js.map")
|
||||
const sourceJs = jsFile("dist")
|
||||
const sourceJsMap = jsMapFile("dist")
|
||||
|
||||
const appPackages = join(
|
||||
packagesFolder,
|
||||
"server",
|
||||
serverConfig.latestPackagesFolder
|
||||
)
|
||||
|
||||
const publicMain = appName => join(appPackages, appName, "public", "main")
|
||||
const publicUnauth = appName =>
|
||||
join(appPackages, appName, "public", "unauthenticated")
|
||||
|
||||
;(async () => {
|
||||
const apps = await readdir(appPackages)
|
||||
|
||||
const copySource = file => async toDir => {
|
||||
await ensureDir(toDir)
|
||||
const dest = join(toDir, basename(file))
|
||||
try {
|
||||
await copyFile(file, dest, constants.COPYFILE_FICLONE)
|
||||
console.log(`COPIED ${file} to ${dest}`)
|
||||
} catch (e) {
|
||||
console.log(`COPY FAILED ${file} to ${dest}: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
const copySourceJs = copySource(sourceJs)
|
||||
const copySourceJsMap = copySource(sourceJsMap)
|
||||
|
||||
for (let app of apps) {
|
||||
if (app === ".data") continue
|
||||
if (!(await stat(join(appPackages, app))).isDirectory()) continue
|
||||
|
||||
//await copySourceJs(nodeModules(app))
|
||||
//await copySourceJsMap(nodeModules(app))
|
||||
|
||||
await copySourceJs(publicMain(app))
|
||||
await copySourceJsMap(publicMain(app))
|
||||
|
||||
await copySourceJs(publicUnauth(app))
|
||||
await copySourceJsMap(publicUnauth(app))
|
||||
|
||||
await copySource(join("dist", "budibase-client.esm.mjs"))(
|
||||
join(packagesFolder, "server", "builder")
|
||||
)
|
||||
}
|
||||
})()
|
|
@ -1,8 +1,8 @@
|
|||
import { createApp } from "./createApp"
|
||||
import { trimSlash } from "./common/trimSlash"
|
||||
import { builtins, builtinLibName } from "./render/builtinComponents"
|
||||
import * as standardComponents from "@budibase/standard-components";
|
||||
import * as materialDesignComponents from "@budibase/materialdesign-components";
|
||||
import * as standardComponents from "../../standard-components/dist";
|
||||
import * as materialDesignComponents from "../../materialdesign-components/dist";
|
||||
|
||||
/**
|
||||
* create a web application from static budibase definition files.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"testbuild": "rollup -w -c rollup.testconfig.js",
|
||||
"dev": "run-p start:dev testbuild",
|
||||
"start:dev": "sirv public --single --dev",
|
||||
"publishdev": "yarn build && node ./scripts/publishDev.js"
|
||||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@budibase/client": "^0.0.32",
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
const { readdir, stat, copyFile, ensureDir } = require("fs-extra")
|
||||
const { constants } = require("fs")
|
||||
const { join, basename } = require("path")
|
||||
const serverConfig = require("../../server/config")()
|
||||
|
||||
const packagesFolder = ".."
|
||||
|
||||
const jsFile = dir => join(dir, "index.js")
|
||||
const jsMapFile = dir => join(dir, "index.js.map")
|
||||
const sourceJs = jsFile("dist")
|
||||
const sourceJsMap = jsMapFile("dist")
|
||||
const componentsFile = "components.json"
|
||||
|
||||
const appPackages = join(
|
||||
packagesFolder,
|
||||
"server",
|
||||
serverConfig.latestPackagesFolder
|
||||
)
|
||||
|
||||
const publicMain = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"public",
|
||||
"main",
|
||||
"lib",
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"materialdesign-components"
|
||||
)
|
||||
const publicUnauth = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"public",
|
||||
"unauthenticated",
|
||||
"lib",
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"materialdesign-components"
|
||||
)
|
||||
const nodeModulesDist = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"materialdesign-components",
|
||||
"dist"
|
||||
)
|
||||
|
||||
const nodeModules = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"materialdesign-components"
|
||||
)
|
||||
|
||||
;(async () => {
|
||||
const apps = await readdir(appPackages)
|
||||
|
||||
const copySource = file => async toDir => {
|
||||
await ensureDir(toDir)
|
||||
const dest = join(toDir, basename(file))
|
||||
try {
|
||||
await copyFile(file, dest, constants.COPYFILE_FICLONE)
|
||||
console.log(`COPIED ${file} to ${dest}`)
|
||||
} catch (e) {
|
||||
console.log(`COPY FAILED ${file} to ${dest}: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
const copySourceJs = copySource(sourceJs)
|
||||
const copySourceJsMap = copySource(sourceJsMap)
|
||||
const copyComponentsJson = copySource(componentsFile)
|
||||
|
||||
for (let app of apps) {
|
||||
if (app === ".data") continue
|
||||
if (!(await stat(join(appPackages, app))).isDirectory()) continue
|
||||
|
||||
await copySourceJs(nodeModulesDist(app))
|
||||
await copySourceJsMap(nodeModulesDist(app))
|
||||
|
||||
await copyComponentsJson(nodeModules(app))
|
||||
|
||||
await copySourceJs(join(publicMain(app), "dist"))
|
||||
await copySourceJsMap(join(publicMain(app), "dist"))
|
||||
|
||||
await copySourceJs(join(publicUnauth(app), "dist"))
|
||||
await copySourceJsMap(join(publicUnauth(app), "dist"))
|
||||
}
|
||||
})()
|
|
@ -8,24 +8,43 @@ exports.authenticate = async ctx => {
|
|||
if (!username) ctx.throw(400, "Username Required.");
|
||||
if (!password) ctx.throw(400, "Password Required");
|
||||
|
||||
// query couch for their username
|
||||
const db = new CouchDB(ctx.params.clientId);
|
||||
const dbUser = await db.query("by_username", {
|
||||
// TODO: Don't use this. It can't be relied on
|
||||
const referer = ctx.request.headers.referer.split("/");
|
||||
const appId = referer[3];
|
||||
|
||||
// find the instance that the user is associated with
|
||||
const db = new CouchDB(`client-${process.env.CLIENT_ID}`);
|
||||
const app = await db.get(appId);
|
||||
const instanceId = app.userInstanceMap[username];
|
||||
|
||||
if (!instanceId) ctx.throw(500, "User is not associated with an instance of app", appId)
|
||||
|
||||
// Check the user exists in the instance DB by username
|
||||
const instanceDb = new CouchDB(instanceId);
|
||||
const { rows } = await instanceDb.query("database/by_username", {
|
||||
include_docs: true,
|
||||
key: username
|
||||
username
|
||||
});
|
||||
|
||||
|
||||
if (rows.length === 0) ctx.throw(500, `User does not exist.`);
|
||||
|
||||
const dbUser = rows[0].doc;
|
||||
|
||||
// authenticate
|
||||
if (await bcrypt.compare(password, dbUser.password)) {
|
||||
const payload = {
|
||||
userId: dbUser._id,
|
||||
accessLevel: "",
|
||||
instanceId: ctx.params.instanceId
|
||||
instanceId: instanceId
|
||||
};
|
||||
const token = jwt.sign(payload, ctx.config.secret, {
|
||||
expiresIn: "1 day"
|
||||
});
|
||||
|
||||
ctx.body = token;
|
||||
ctx.body = {
|
||||
token,
|
||||
...dbUser
|
||||
};
|
||||
} else {
|
||||
ctx.throw(401, "Invalid credentials.");
|
||||
}
|
||||
|
|
|
@ -2,12 +2,20 @@ const CouchDB = require("../../db");
|
|||
const { homedir } = require("os");
|
||||
const { resolve, join } = require("path");
|
||||
|
||||
const isDev = process.env.NODE_ENV !== "production";
|
||||
|
||||
exports.fetchAppComponentDefinitions = async function(ctx) {
|
||||
const db = new CouchDB(`client-${ctx.params.clientId}`);
|
||||
const app = await db.get(ctx.params.appId)
|
||||
|
||||
const componentDefinitions = app.componentLibraries.reduce((acc, componentLibrary) => {
|
||||
const appDirectory = resolve(homedir(), ".budibase", ctx.params.appId, "node_modules");
|
||||
|
||||
let appDirectory = resolve(homedir(), ".budibase", ctx.params.appId, "node_modules");
|
||||
|
||||
if (isDev) {
|
||||
appDirectory = "/tmp/.budibase";
|
||||
}
|
||||
|
||||
const componentJson = require(join(appDirectory, componentLibrary, "components.json"));
|
||||
|
||||
const result = {};
|
||||
|
|
|
@ -2,7 +2,6 @@ const CouchDB = require("../../db");
|
|||
|
||||
exports.create = async function(ctx) {
|
||||
const instanceName = ctx.request.body.name;
|
||||
// await couchdb.db.create(instanceName);
|
||||
|
||||
const { clientId, applicationId } = ctx.params;
|
||||
const db = new CouchDB(instanceName);
|
||||
|
@ -13,6 +12,13 @@ exports.create = async function(ctx) {
|
|||
applicationId
|
||||
},
|
||||
views: {
|
||||
by_username: {
|
||||
map: function(doc) {
|
||||
if (doc.type === "user") {
|
||||
emit([doc.username], doc._id);
|
||||
}
|
||||
}.toString()
|
||||
},
|
||||
by_type: {
|
||||
map: function(doc) {
|
||||
emit([doc.type], doc._id);
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
const send = require("koa-send");
|
||||
const { resolve } = require("path")
|
||||
const { resolve, join } = require("path")
|
||||
const { homedir } = require("os");
|
||||
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
|
||||
exports.serveBuilder = async function(ctx) {
|
||||
const builderPath = resolve(process.cwd(), "builder")
|
||||
await send(ctx, ctx.file, { root: builderPath })
|
||||
}
|
||||
|
||||
exports.serveApp = async function(ctx) {
|
||||
|
||||
// ONLY RELEVANT FOR THE CLIENT LIB
|
||||
// const devPath = join("/tmp", ".budibase", ctx.params.appId);
|
||||
|
||||
// TODO: update homedir stuff to wherever budi is run
|
||||
// default to homedir
|
||||
const appPath = resolve(
|
||||
|
@ -18,38 +24,30 @@ exports.serveApp = async function(ctx) {
|
|||
ctx.isAuthenticated ? "main" : "unauthenticated"
|
||||
);
|
||||
|
||||
// TODO: Hook up to JWT auth in real app
|
||||
// TODO: serve CSS and other assets
|
||||
// resolve main page if user authenticated
|
||||
await send(ctx, ctx.file, { root: appPath })
|
||||
}
|
||||
|
||||
exports.serveComponentLibrary = async function(ctx) {
|
||||
// TODO: update homedir stuff to wherever budi is run
|
||||
// default to homedir
|
||||
const componentLibraryPath = resolve(
|
||||
homedir(),
|
||||
".budibase",
|
||||
ctx.params.appId,
|
||||
"node_modules",
|
||||
|
||||
let componentLibraryPath = join(
|
||||
"/tmp",
|
||||
".budibase",
|
||||
decodeURI(ctx.query.library),
|
||||
"dist"
|
||||
);
|
||||
|
||||
if (isProduction) {
|
||||
// TODO: update homedir stuff to wherever budi is run
|
||||
// default to homedir
|
||||
componentLibraryPath = resolve(
|
||||
homedir(),
|
||||
".budibase",
|
||||
ctx.params.appId,
|
||||
"node_modules",
|
||||
decodeURI(ctx.query.library),
|
||||
"dist"
|
||||
);
|
||||
}
|
||||
|
||||
await send(ctx, "/index.js", { root: componentLibraryPath })
|
||||
}
|
||||
|
||||
exports.serveComponentDefinitions = async function(ctx) {
|
||||
// TODO: update homedir stuff to wherever budi is run
|
||||
// default to homedir
|
||||
const componentLibraryPath = resolve(
|
||||
homedir(),
|
||||
".budibase",
|
||||
ctx.params.appId,
|
||||
"node_modules",
|
||||
decodeURI(ctx.query.library),
|
||||
"dist"
|
||||
);
|
||||
|
||||
await send(ctx, "/index.js", { root: componentLibraryPath })
|
||||
}
|
|
@ -25,12 +25,12 @@ exports.create = async function(ctx) {
|
|||
});
|
||||
|
||||
// the clientDB needs to store a map of users against the app
|
||||
const clientDB = new CouchDB(process.env.CLIENT_ID);
|
||||
const app = await clientDB.get(ctx.params.appId);
|
||||
const clientDb = new CouchDB(`client-${process.env.CLIENT_ID}`);
|
||||
const app = await clientDb.get(ctx.params.appId);
|
||||
|
||||
app.userInstanceMap = {
|
||||
...app.userInstanceMap,
|
||||
[response._id]: ctx.params.instanceId
|
||||
[username]: ctx.params.instanceId
|
||||
}
|
||||
await clientDb.put(app);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ const controller = {
|
|||
const response = [];
|
||||
|
||||
for (let name in designDoc.views) {
|
||||
if (!name.startsWith("all") && name !== "by_type") {
|
||||
if (!name.startsWith("all") && name !== "by_type" && name !== "by_username") {
|
||||
response.push({
|
||||
name,
|
||||
...designDoc.views[name]
|
||||
|
|
|
@ -36,7 +36,10 @@ module.exports = app => {
|
|||
// TODO: temp dev middleware
|
||||
// ctx.sessionId = ctx.session._sessCtx.externalKey
|
||||
// ctx.session.accessed = true
|
||||
ctx.config = { latestPackagesFolder: resolve(homedir(), ".budibase") }
|
||||
ctx.config = {
|
||||
latestPackagesFolder: resolve(homedir(), ".budibase"),
|
||||
secret: "foo"
|
||||
}
|
||||
await next();
|
||||
});
|
||||
|
||||
|
|
|
@ -11,30 +11,30 @@ const {
|
|||
|
||||
const router = Router()
|
||||
|
||||
router.post("/_builder/api/:appname/pages/:pageName", async ctx => {
|
||||
router.post("/_builder/api/:appId/pages/:pageName", async ctx => {
|
||||
await buildPage(
|
||||
ctx.config,
|
||||
ctx.params.appname,
|
||||
ctx.params.appId,
|
||||
ctx.params.pageName,
|
||||
ctx.request.body
|
||||
)
|
||||
ctx.response.status = StatusCodes.OK
|
||||
})
|
||||
|
||||
router.get("/_builder/api/:appname/pages/:pagename/screens", async ctx => {
|
||||
router.get("/_builder/api/:appId/pages/:pagename/screens", async ctx => {
|
||||
ctx.body = await listScreens(
|
||||
ctx.config,
|
||||
ctx.params.appname,
|
||||
ctx.params.appId,
|
||||
ctx.params.pagename
|
||||
)
|
||||
ctx.response.status = StatusCodes.OK
|
||||
})
|
||||
|
||||
router
|
||||
.post("/_builder/api/:appname/pages/:pagename/screen", async ctx => {
|
||||
.post("/_builder/api/:appId/pages/:pagename/screen", async ctx => {
|
||||
ctx.body = await saveScreen(
|
||||
ctx.config,
|
||||
ctx.params.appname,
|
||||
ctx.params.appId,
|
||||
ctx.params.pagename,
|
||||
ctx.request.body
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ const {
|
|||
readFile,
|
||||
writeJSON,
|
||||
} = require("fs-extra")
|
||||
const { join, resolve, dirname } = require("path")
|
||||
const { join, resolve } = require("path")
|
||||
const sqrl = require("squirrelly")
|
||||
const { convertCssToFiles } = require("./convertCssToFiles")
|
||||
const publicPath = require("./publicPath")
|
||||
|
|
|
@ -4977,9 +4977,9 @@ supports-color@^7.1.0:
|
|||
has-flag "^4.0.0"
|
||||
|
||||
svelte@^3.9.2:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.21.0.tgz#e326591cb92267e90b4fb5b961d80d9763792551"
|
||||
integrity sha512-smh3LZKPCGJ+UXa0iZvUmuDctPYCwPY1opmClTWTm+l6e4y9FHLoCZMiue8YIeyc9JvlGT/EK0xry0diXjFDZQ==
|
||||
version "3.22.2"
|
||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.22.2.tgz#06585244191bf7a112af2a0025610f33d77c3715"
|
||||
integrity sha512-DxumO0+vvHA6NSc2jtVty08I8lFI43q8P2zX6JxZL8J1kqK5NVjad6TRM/twhnWXC+QScnwkZ15O6X1aTsEKTA==
|
||||
|
||||
symbol-tree@^3.2.2:
|
||||
version "3.2.4"
|
||||
|
|
|
@ -262,6 +262,29 @@
|
|||
"color": "colour"
|
||||
}
|
||||
},
|
||||
"datatable": {
|
||||
"description": "Other thingwy",
|
||||
"props": {
|
||||
"_viewName": "string",
|
||||
"_instanceId": "string",
|
||||
"model": {
|
||||
"store": true,
|
||||
"type": "options",
|
||||
"default": "",
|
||||
"options": [
|
||||
"something",
|
||||
"something"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dataform": {
|
||||
"description": "an HTML table that fetches data from a model or view and displays it.",
|
||||
"props": {
|
||||
"_viewName": "string",
|
||||
"_instanceId": "string"
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"description": "an HTML anchor <a> tag",
|
||||
"props": {
|
||||
|
@ -402,4 +425,4 @@
|
|||
"className": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"testbuild": "rollup -w -c rollup.testconfig.js",
|
||||
"dev": "run-p start:dev testbuild",
|
||||
"start:dev": "sirv public --single --dev",
|
||||
"publishdev": "yarn build && node ./scripts/publishDev.js"
|
||||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@budibase/client": "^0.0.32",
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
const { readdir, stat, copyFile, ensureDir } = require("fs-extra")
|
||||
const { constants } = require("fs")
|
||||
const { join, basename } = require("path")
|
||||
const serverConfig = require("../../server/config")()
|
||||
|
||||
const packagesFolder = ".."
|
||||
|
||||
const jsFile = dir => join(dir, "index.js")
|
||||
const jsMapFile = dir => join(dir, "index.js.map")
|
||||
const sourceJs = jsFile("dist")
|
||||
const sourceJsMap = jsMapFile("dist")
|
||||
const componentsFile = "components.json"
|
||||
|
||||
const appPackages = join(
|
||||
packagesFolder,
|
||||
"server",
|
||||
resolve(homedir(), ".budibase")
|
||||
)
|
||||
|
||||
const publicMain = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"public",
|
||||
"main",
|
||||
"lib",
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"standard-components"
|
||||
)
|
||||
const publicUnauth = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"public",
|
||||
"unauthenticated",
|
||||
"lib",
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"standard-components"
|
||||
)
|
||||
const nodeModulesDist = appName =>
|
||||
join(
|
||||
appPackages,
|
||||
appName,
|
||||
"node_modules",
|
||||
"@budibase",
|
||||
"standard-components",
|
||||
"dist"
|
||||
)
|
||||
|
||||
const nodeModules = appName =>
|
||||
join(appPackages, appName, "node_modules", "@budibase", "standard-components")
|
||||
|
||||
;(async () => {
|
||||
const apps = await readdir(appPackages)
|
||||
|
||||
const copySource = file => async toDir => {
|
||||
await ensureDir(toDir)
|
||||
const dest = join(toDir, basename(file))
|
||||
try {
|
||||
await copyFile(file, dest, constants.COPYFILE_FICLONE)
|
||||
console.log(`COPIED ${file} to ${dest}`)
|
||||
} catch (e) {
|
||||
console.log(`COPY FAILED ${file} to ${dest}: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
const copySourceJs = copySource(sourceJs)
|
||||
const copySourceJsMap = copySource(sourceJsMap)
|
||||
const copyComponentsJson = copySource(componentsFile)
|
||||
|
||||
for (let app of apps) {
|
||||
if (app === ".data") continue
|
||||
if (!(await stat(join(appPackages, app))).isDirectory()) continue
|
||||
|
||||
await copySourceJs(nodeModulesDist(app))
|
||||
await copySourceJsMap(nodeModulesDist(app))
|
||||
|
||||
await copyComponentsJson(nodeModules(app))
|
||||
|
||||
await copySourceJs(join(publicMain(app), "dist"))
|
||||
await copySourceJsMap(join(publicMain(app), "dist"))
|
||||
|
||||
await copySourceJs(join(publicUnauth(app), "dist"))
|
||||
await copySourceJsMap(join(publicUnauth(app), "dist"))
|
||||
}
|
||||
})()
|
|
@ -0,0 +1,27 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
|
||||
export let _bb
|
||||
export let _viewName
|
||||
export let _instanceId
|
||||
|
||||
let username
|
||||
let password
|
||||
|
||||
</script>
|
||||
|
||||
<form class="uk-form">
|
||||
<div>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="form-stacked-text">Username</label>
|
||||
<input class="uk-input" type="text" bind:value={username} />
|
||||
</div>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="form-stacked-text">Password</label>
|
||||
<input class="uk-input" type="password" bind:value={password} />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -0,0 +1,110 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
// import { cssVars, createClasses } from "./cssVars"
|
||||
// import { buildStyle } from "./buildStyle"
|
||||
|
||||
export let _bb
|
||||
export let onLoad
|
||||
export let _viewName
|
||||
export let _instanceId
|
||||
|
||||
let cssVariables
|
||||
let headers = []
|
||||
let data = []
|
||||
|
||||
async function fetchData() {
|
||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/${_viewName}/records`;
|
||||
const response = await _bb.api.get(FETCH_RECORDS_URL);
|
||||
if (response.status === 200) {
|
||||
const json = await response.json();
|
||||
|
||||
if (json.length > 0) {
|
||||
data = json;
|
||||
headers = Object.keys(data[0]);
|
||||
} else {
|
||||
console.log("NO DATA");
|
||||
}
|
||||
} else {
|
||||
throw new Error("Failed to fetch records..");
|
||||
console.log("FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await fetchData();
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- This prop was in the old one -->
|
||||
<!-- use:cssVars={cssVariables} -->
|
||||
|
||||
<table class="uk-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{#each headers as header}
|
||||
<th>{header}</th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each data as row}
|
||||
<tr>
|
||||
{#each headers as header}
|
||||
{#if row[header]}
|
||||
<td>
|
||||
{row[header]}
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<!-- <button
|
||||
bind:this={theButton}
|
||||
use:cssVars={cssVariables}
|
||||
class="{className}
|
||||
{customClasses}"
|
||||
disabled={disabled || false}
|
||||
on:click={clickHandler}
|
||||
style={buttonStyles}>
|
||||
{#if !_bb.props._children || _bb.props._children.length === 0}
|
||||
{contentText}
|
||||
{/if}
|
||||
</button> -->
|
||||
|
||||
<style>
|
||||
table {
|
||||
border: 1px solid #ccc;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
thead {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
thead th {
|
||||
color: var(--button-text);
|
||||
text-transform: capitalize;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
text-rendering: optimizeLegibility;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
border-bottom: 1px solid #ccc;
|
||||
transition: 0.3s background-color;
|
||||
color: var(--secondary100);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
|
@ -4,7 +4,6 @@
|
|||
export let usernameLabel = "Username"
|
||||
export let passwordLabel = "Password"
|
||||
export let loginButtonLabel = "Login"
|
||||
export let loginRedirect = ""
|
||||
export let logo = ""
|
||||
export let buttonClass = ""
|
||||
export let inputClass = ""
|
||||
|
@ -13,8 +12,8 @@
|
|||
|
||||
let username = ""
|
||||
let password = ""
|
||||
let busy = false
|
||||
let incorrect = false
|
||||
let loading = false
|
||||
let error = false
|
||||
let _logo = ""
|
||||
let _buttonClass = ""
|
||||
let _inputClass = ""
|
||||
|
@ -25,32 +24,25 @@
|
|||
_inputClass = inputClass || "default-input"
|
||||
}
|
||||
|
||||
const login = () => {
|
||||
busy = true
|
||||
_bb.api
|
||||
.post("/api/authenticate", { username, password })
|
||||
.then(r => {
|
||||
busy = false
|
||||
if (r.status === 200) {
|
||||
return r.json()
|
||||
} else {
|
||||
incorrect = true
|
||||
return
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
localStorage.setItem("budibase:user", JSON.stringify(user))
|
||||
location.reload()
|
||||
}
|
||||
})
|
||||
const login = async () => {
|
||||
loading = true
|
||||
const response = _bb.api.post("/api/authenticate", { username, password });
|
||||
|
||||
if (response.status === 200) {
|
||||
const json = await response.json();
|
||||
localStorage.setItem("budibase:token", json.token);
|
||||
// TODO: possibly do something with the user information in the response?
|
||||
location.reload()
|
||||
} else {
|
||||
loading = false
|
||||
error = true
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
||||
<div class="content">
|
||||
|
||||
{#if _logo}
|
||||
<div class="logo-container">
|
||||
<img src={_logo} alt="logo" />
|
||||
|
@ -69,17 +61,15 @@
|
|||
</div>
|
||||
|
||||
<div class="login-button-container">
|
||||
<button disabled={busy} on:click={login} class={_buttonClass}>
|
||||
<button disabled={loading} on:click={login} class={_buttonClass}>
|
||||
{loginButtonLabel}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if incorrect}
|
||||
{#if error}
|
||||
<div class="incorrect-details-panel">Incorrect username or password</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -14,3 +14,5 @@ export { default as link } from "./Link.svelte"
|
|||
export { default as image } from "./Image.svelte"
|
||||
export { default as icon } from "./Icon.svelte"
|
||||
export { default as Navigation } from "./Navigation.svelte"
|
||||
export { default as datatable } from "./DataTable.svelte"
|
||||
export { default as dataform } from "./DataForm.svelte"
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
This script symlinks the budibase component and client paths to the
|
||||
ones that exist in your local development directories. This means you
|
||||
can work your budibase apps but also change code for the components
|
||||
and client library in real time.
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const { resolve } = require("path")
|
||||
|
||||
const devDir = "/tmp/.budibase/@budibase";
|
||||
|
||||
// create the dev directory if it doesn't exist
|
||||
if (!fs.existsSync(devDir)) {
|
||||
fs.mkdirSync(devDir, { recursive: true });
|
||||
}
|
||||
|
||||
const SYMLINK_PATHS = [
|
||||
{
|
||||
symlink: "/tmp/.budibase/@budibase/materialdesign-components",
|
||||
destination: resolve("packages/materialdesign-components"),
|
||||
},
|
||||
{
|
||||
symlink: "/tmp/.budibase/@budibase/standard-components",
|
||||
destination: resolve("packages/standard-components")
|
||||
},
|
||||
{
|
||||
symlink: "/tmp/.budibase/budibase-client.esm.mjs",
|
||||
destination: resolve("packages/client/dist/budibase-client.esm.mjs")
|
||||
},
|
||||
{
|
||||
symlink: "/tmp/.budibase/budibase-client.js",
|
||||
destination: resolve("packages/client/dist/budibase-client.js"),
|
||||
}
|
||||
]
|
||||
|
||||
SYMLINK_PATHS.forEach(sym => {
|
||||
fs.symlinkSync(sym.destination, sym.symlink);
|
||||
});
|
||||
|
||||
console.log("Dev Symlinks Created Successfully.")
|