Browse Source

development setup, adding data components

gh-pages
Martin McKeaveney 6 years ago
parent
commit
392de2efcc
  1. 7563
      package-lock.json
  2. 2
      package.json
  3. 0
      packages/builder/assets/budibase-emblem-white.svg
  4. 0
      packages/builder/assets/budibase-logo-only.png
  5. 0
      packages/builder/assets/budibase-logo-white.png
  6. 0
      packages/builder/assets/budibase-logo.png
  7. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-300.woff
  8. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-300.woff2
  9. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-500.woff
  10. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-500.woff2
  11. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-700.woff
  12. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-700.woff2
  13. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-900.woff
  14. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-900.woff2
  15. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-regular.woff
  16. 0
      packages/builder/assets/roboto-v20-latin-ext_latin-regular.woff2
  17. 2
      packages/builder/rollup.config.js
  18. 4
      packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte
  19. 14
      packages/builder/src/components/database/ModelDataTable/api.js
  20. 3
      packages/builder/src/components/database/ModelDataTable/modals/CreateUser.svelte
  21. 14
      packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte
  22. 2
      packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte
  23. 23
      packages/builder/src/components/userInterface/PropsView.svelte
  24. 18
      packages/builder/src/components/userInterface/temporaryPanelStructure.js
  25. 2
      packages/client/package.json
  26. 1
      packages/client/rollup.config.js
  27. 56
      packages/client/scripts/publishDev.js
  28. 4
      packages/client/src/index.js
  29. 2
      packages/materialdesign-components/package.json
  30. 94
      packages/materialdesign-components/scripts/publishDev.js
  31. 33
      packages/server/api/controllers/auth.js
  32. 10
      packages/server/api/controllers/component.js
  33. 8
      packages/server/api/controllers/instance.js
  34. 50
      packages/server/api/controllers/static.js
  35. 6
      packages/server/api/controllers/user.js
  36. 2
      packages/server/api/controllers/view.js
  37. 5
      packages/server/api/index.js
  38. 12
      packages/server/api/routes/pages.js
  39. 2
      packages/server/utilities/builder/buildPage.js
  40. 6
      packages/server/yarn.lock
  41. 25
      packages/standard-components/components.json
  42. 2
      packages/standard-components/package.json
  43. 88
      packages/standard-components/scripts/publishDev.js
  44. 27
      packages/standard-components/src/DataForm.svelte
  45. 110
      packages/standard-components/src/DataTable.svelte
  46. 46
      packages/standard-components/src/Login.svelte
  47. 2
      packages/standard-components/src/index.js
  48. 43
      scripts/symlinkDev.js

7563
package-lock.json

File diff suppressed because it is too large

2
package.json

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

0
packages/builder/src/assets/budibase-emblem-white.svg → packages/builder/assets/budibase-emblem-white.svg

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
packages/builder/src/assets/budibase-logo-only.png → packages/builder/assets/budibase-logo-only.png

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

0
packages/builder/src/assets/budibase-logo-white.png → packages/builder/assets/budibase-logo-white.png

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

0
packages/builder/src/assets/budibase-logo.png → packages/builder/assets/budibase-logo.png

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-300.woff → packages/builder/assets/roboto-v20-latin-ext_latin-300.woff

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-300.woff2 → packages/builder/assets/roboto-v20-latin-ext_latin-300.woff2

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-500.woff → packages/builder/assets/roboto-v20-latin-ext_latin-500.woff

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-500.woff2 → packages/builder/assets/roboto-v20-latin-ext_latin-500.woff2

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-700.woff → packages/builder/assets/roboto-v20-latin-ext_latin-700.woff

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-700.woff2 → packages/builder/assets/roboto-v20-latin-ext_latin-700.woff2

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-900.woff → packages/builder/assets/roboto-v20-latin-ext_latin-900.woff

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-900.woff2 → packages/builder/assets/roboto-v20-latin-ext_latin-900.woff2

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-regular.woff → packages/builder/assets/roboto-v20-latin-ext_latin-regular.woff

0
packages/builder/src/assets/roboto-v20-latin-ext_latin-regular.woff2 → packages/builder/assets/roboto-v20-latin-ext_latin-regular.woff2

2
packages/builder/rollup.config.js

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

4
packages/builder/src/components/database/ModelDataTable/ModelDataTable.svelte

@ -161,10 +161,6 @@
text-transform: capitalize;
}
.select {
background: white;
}
table {
border: 1px solid #ccc;
background: #fff;

14
packages/builder/src/components/database/ModelDataTable/api.js

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

3
packages/builder/src/components/database/ModelDataTable/modals/CreateUser.svelte

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

14
packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte

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

2
packages/builder/src/components/userInterface/ComponentPropertiesPanel.svelte

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

23
packages/builder/src/components/userInterface/PropsView.svelte

@ -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">
<PropControl
{setProp}
{prop_name}
prop_value={component[prop_name]}
prop_definition={prop_def}
{index}
disabled={false} />
</div>
{#if prop_def !== "event"}
<div class="prop-container">
<PropControl
{setProp}
{prop_name}
prop_value={component[prop_name]}
prop_definition={prop_def}
{index}
disabled={false} />
</div>
{/if}
{/each}
{/if}
</form>

18
packages/builder/src/components/userInterface/temporaryPanelStructure.js

@ -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: []
},
]
},
]

2
packages/client/package.json

@ -7,7 +7,7 @@
"scripts": {
"build": "rollup -c",
"test": "jest",
"publishdev": "yarn build && node ./scripts/publishDev.js"
"dev:builder": "rollup -cw"
},
"jest": {
"globals": {

1
packages/client/rollup.config.js

@ -102,7 +102,6 @@ export default {
}),
builtins(),
nodeglobals(),
//terser()
],
watch: {
clearScreen: false,

56
packages/client/scripts/publishDev.js

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

4
packages/client/src/index.js

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

2
packages/materialdesign-components/package.json

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

94
packages/materialdesign-components/scripts/publishDev.js

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

33
packages/server/api/controllers/auth.js

@ -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.");
}

10
packages/server/api/controllers/component.js

@ -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 = {};

8
packages/server/api/controllers/instance.js

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

50
packages/server/api/controllers/static.js

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

6
packages/server/api/controllers/user.js

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

2
packages/server/api/controllers/view.js

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

5
packages/server/api/index.js

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

12
packages/server/api/routes/pages.js

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

2
packages/server/utilities/builder/buildPage.js

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

6
packages/server/yarn.lock

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

25
packages/standard-components/components.json

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

2
packages/standard-components/package.json

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

88
packages/standard-components/scripts/publishDev.js

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

27
packages/standard-components/src/DataForm.svelte

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

110
packages/standard-components/src/DataTable.svelte

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

46
packages/standard-components/src/Login.svelte

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

2
packages/standard-components/src/index.js

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

43
scripts/symlinkDev.js

@ -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.")
Loading…
Cancel
Save