From 6ca49403dfc86de52864d9bd35240cd32087f7e9 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 17:28:33 +0200 Subject: [PATCH 01/28] adds tab to settings modal on front-end to display API Keys --- .../src/components/settings/Modal.svelte | 7 ++- .../src/components/settings/tabs/API.svelte | 55 +++++++++++++++++++ .../src/components/settings/tabs/index.js | 1 + 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 packages/builder/src/components/settings/tabs/API.svelte diff --git a/packages/builder/src/components/settings/Modal.svelte b/packages/builder/src/components/settings/Modal.svelte index 2d832481c3..dc6809f488 100644 --- a/packages/builder/src/components/settings/Modal.svelte +++ b/packages/builder/src/components/settings/Modal.svelte @@ -1,5 +1,5 @@ + +API Keys +
+
+ +
+
+ +
+
+ + diff --git a/packages/builder/src/components/settings/tabs/index.js b/packages/builder/src/components/settings/tabs/index.js index a1d1df38e4..67f79b536c 100644 --- a/packages/builder/src/components/settings/tabs/index.js +++ b/packages/builder/src/components/settings/tabs/index.js @@ -2,4 +2,5 @@ export { default as General } from "./General.svelte" export { default as Integrations } from "./Integrations.svelte" export { default as Permissions } from "./Permissions.svelte" export { default as Users } from "./Users.svelte" +export { default as APIKeys } from "./Api.svelte" export { default as DangerZone } from "./DangerZone.svelte" From d8e6bd0ab9e34cdae5482ad64bafac46f8ff703f Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 17:53:09 +0200 Subject: [PATCH 02/28] sets up dummy back-end --- .../tabs/{API.svelte => APIKeys.svelte} | 5 ++- .../src/components/settings/tabs/index.js | 2 +- .../server/src/api/controllers/apikeys.js | 45 +++++++++++++++++++ packages/server/src/api/index.js | 4 ++ packages/server/src/api/routes/apikeys.js | 12 +++++ packages/server/src/api/routes/index.js | 2 + 6 files changed, 68 insertions(+), 2 deletions(-) rename packages/builder/src/components/settings/tabs/{API.svelte => APIKeys.svelte} (85%) create mode 100644 packages/server/src/api/controllers/apikeys.js create mode 100644 packages/server/src/api/routes/apikeys.js diff --git a/packages/builder/src/components/settings/tabs/API.svelte b/packages/builder/src/components/settings/tabs/APIKeys.svelte similarity index 85% rename from packages/builder/src/components/settings/tabs/API.svelte rename to packages/builder/src/components/settings/tabs/APIKeys.svelte index fe3fe142ce..03aa2c86fc 100644 --- a/packages/builder/src/components/settings/tabs/API.svelte +++ b/packages/builder/src/components/settings/tabs/APIKeys.svelte @@ -9,12 +9,15 @@ async function updateKey(e) { console.log("Event Key: ", e.detail) // Send to endpoint when it exists - // const response = await api.put(`/api/${$store.appId}`, data) + const response = await api.put(`/api/${$store.appId}`, data) // const res = await response.json() } // Get Keys async function fetchKeys() { + const response = await api.get(`/api/keys/`) + const res = await response.json() + console.log("Res: ", res) // fetch keys from endpoint // return keys } diff --git a/packages/builder/src/components/settings/tabs/index.js b/packages/builder/src/components/settings/tabs/index.js index 67f79b536c..6e34141d09 100644 --- a/packages/builder/src/components/settings/tabs/index.js +++ b/packages/builder/src/components/settings/tabs/index.js @@ -2,5 +2,5 @@ export { default as General } from "./General.svelte" export { default as Integrations } from "./Integrations.svelte" export { default as Permissions } from "./Permissions.svelte" export { default as Users } from "./Users.svelte" -export { default as APIKeys } from "./Api.svelte" +export { default as APIKeys } from "./APIKeys.svelte" export { default as DangerZone } from "./DangerZone.svelte" diff --git a/packages/server/src/api/controllers/apikeys.js b/packages/server/src/api/controllers/apikeys.js new file mode 100644 index 0000000000..11dd0ac787 --- /dev/null +++ b/packages/server/src/api/controllers/apikeys.js @@ -0,0 +1,45 @@ +const CouchDB = require("../../db") +const clientDb = require("../../db/clientDb") +const bcrypt = require("../../utilities/bcrypt") +const getUserId = userName => `user_${userName}` +const { + POWERUSER_LEVEL_ID, + ADMIN_LEVEL_ID, +} = require("../../utilities/accessLevels") + +exports.fetch = async function (ctx) { + // Temporary while "real" infrastructure to store keys is created + ctx.status = 200 + ctx.message = "API Keys" + ctx.body = { + budibase: 'testFromBackEnd', + sendgrid: 'testFromBackEnd' + } +} + +exports.update = async function (ctx) { + ctx.status = 200 + ctx.message = `Updated ${ctx.params.key} succesfully.` + ctx.body = { + [ctx.params.key]: "somethingsomethingsomething" + } + + ctx.status = 200 + ctx.message = `User ${ctx.request.body.username} updated successfully.` + ctx.body = response +} + +const checkAccessLevel = async (db, accessLevelId) => { + if (!accessLevelId) return + if ( + accessLevelId === POWERUSER_LEVEL_ID || + accessLevelId === ADMIN_LEVEL_ID + ) { + return { + _id: accessLevelId, + name: accessLevelId, + permissions: [], + } + } + return await db.get(accessLevelId) +} diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index e6143d6725..09849422da 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -17,6 +17,7 @@ const { componentRoutes, workflowRoutes, accesslevelRoutes, + apiKeysRoutes } = require("./routes") const router = new Router() @@ -98,6 +99,9 @@ router.use(clientRoutes.allowedMethods()) router.use(accesslevelRoutes.routes()) router.use(accesslevelRoutes.allowedMethods()) +router.use(apiKeysRoutes.routes()) +router.use(apiKeysRoutes.allowedMethods()) + router.use(staticRoutes.routes()) router.use(staticRoutes.allowedMethods()) diff --git a/packages/server/src/api/routes/apikeys.js b/packages/server/src/api/routes/apikeys.js new file mode 100644 index 0000000000..66e1cd2d68 --- /dev/null +++ b/packages/server/src/api/routes/apikeys.js @@ -0,0 +1,12 @@ +const Router = require("@koa/router") +const controller = require("../controllers/apikeys") +const authorized = require("../../middleware/authorized") +const { BUILDER } = require("../../utilities/accessLevels") + +const router = Router() + +router + .get("/api/keys", authorized(BUILDER), controller.fetch) + .put("/api/keys/:key", authorized(BUILDER), controller.update) + +module.exports = router diff --git a/packages/server/src/api/routes/index.js b/packages/server/src/api/routes/index.js index b50fee788a..2e8662242f 100644 --- a/packages/server/src/api/routes/index.js +++ b/packages/server/src/api/routes/index.js @@ -11,6 +11,7 @@ const staticRoutes = require("./static") const componentRoutes = require("./component") const workflowRoutes = require("./workflow") const accesslevelRoutes = require("./accesslevel") +const apiKeysRoutes = require("./apikeys") module.exports = { authRoutes, @@ -26,4 +27,5 @@ module.exports = { componentRoutes, workflowRoutes, accesslevelRoutes, + apiKeysRoutes } From b6f3a1e32de7f21fd315bb82e61a29c78da888d2 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 17:55:36 +0200 Subject: [PATCH 03/28] fetches keys correctly on the front-end --- .../builder/src/components/settings/tabs/APIKeys.svelte | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/components/settings/tabs/APIKeys.svelte b/packages/builder/src/components/settings/tabs/APIKeys.svelte index 03aa2c86fc..db07755d56 100644 --- a/packages/builder/src/components/settings/tabs/APIKeys.svelte +++ b/packages/builder/src/components/settings/tabs/APIKeys.svelte @@ -17,12 +17,10 @@ async function fetchKeys() { const response = await api.get(`/api/keys/`) const res = await response.json() - console.log("Res: ", res) - // fetch keys from endpoint - // return keys + keys = res } - let fetchKeysPromise = fetchKeys() + fetchKeys() API Keys From a5d33854da1098d278ad62d9603f35eebbc76c37 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 18:38:00 +0200 Subject: [PATCH 04/28] dummy methods wired up to return values to the front-end --- .../src/components/settings/tabs/APIKeys.svelte | 13 ++++++------- packages/server/src/api/controllers/apikeys.js | 11 +++-------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/builder/src/components/settings/tabs/APIKeys.svelte b/packages/builder/src/components/settings/tabs/APIKeys.svelte index db07755d56..4545cf9b85 100644 --- a/packages/builder/src/components/settings/tabs/APIKeys.svelte +++ b/packages/builder/src/components/settings/tabs/APIKeys.svelte @@ -6,11 +6,10 @@ let keys = { budibase: "", sendGrid: "" } - async function updateKey(e) { - console.log("Event Key: ", e.detail) - // Send to endpoint when it exists - const response = await api.put(`/api/${$store.appId}`, data) - // const res = await response.json() + async function updateKey([key, value]) { + const response = await api.put(`/api/keys/${key}`, { value }) + const res = await response.json() + keys = { ...keys, ...res } } // Get Keys @@ -27,7 +26,7 @@
updateKey(['budibase', e.detail])} thin edit value={keys.budibase} @@ -35,7 +34,7 @@
updateKey(['sendgrid', e.detail])} thin edit value={keys.sendgrid} diff --git a/packages/server/src/api/controllers/apikeys.js b/packages/server/src/api/controllers/apikeys.js index 11dd0ac787..88758cb4c3 100644 --- a/packages/server/src/api/controllers/apikeys.js +++ b/packages/server/src/api/controllers/apikeys.js @@ -18,15 +18,10 @@ exports.fetch = async function (ctx) { } exports.update = async function (ctx) { + // Do something with ctx.request.body: <{ value: value }> ctx.status = 200 - ctx.message = `Updated ${ctx.params.key} succesfully.` - ctx.body = { - [ctx.params.key]: "somethingsomethingsomething" - } - - ctx.status = 200 - ctx.message = `User ${ctx.request.body.username} updated successfully.` - ctx.body = response + ctx.message = `Updated ${ctx.params.key} API key succesfully.` + ctx.body = { [ctx.params.key]: ctx.request.body.value } } const checkAccessLevel = async (db, accessLevelId) => { From e3e5caaf9769cb05d14e151fb26a2c4889d38b5c Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 20:31:26 +0200 Subject: [PATCH 05/28] adds getEnvironmentVariables function --- .../server/src/api/controllers/apikeys.js | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/server/src/api/controllers/apikeys.js b/packages/server/src/api/controllers/apikeys.js index 88758cb4c3..2c31449d0a 100644 --- a/packages/server/src/api/controllers/apikeys.js +++ b/packages/server/src/api/controllers/apikeys.js @@ -1,13 +1,15 @@ -const CouchDB = require("../../db") -const clientDb = require("../../db/clientDb") -const bcrypt = require("../../utilities/bcrypt") -const getUserId = userName => `user_${userName}` -const { - POWERUSER_LEVEL_ID, - ADMIN_LEVEL_ID, -} = require("../../utilities/accessLevels") +const fs = require("fs") + +const ENV_FILE_PATH = ".budibase/.env" exports.fetch = async function (ctx) { + // Check if structure of call makes sense, if not, return error + + + // Read File + const fileContent = await getEnvironmentVariables() + const keys = await extractKeys(fileContent) + // Temporary while "real" infrastructure to store keys is created ctx.status = 200 ctx.message = "API Keys" @@ -24,17 +26,14 @@ exports.update = async function (ctx) { ctx.body = { [ctx.params.key]: ctx.request.body.value } } -const checkAccessLevel = async (db, accessLevelId) => { - if (!accessLevelId) return - if ( - accessLevelId === POWERUSER_LEVEL_ID || - accessLevelId === ADMIN_LEVEL_ID - ) { - return { - _id: accessLevelId, - name: accessLevelId, - permissions: [], - } - } - return await db.get(accessLevelId) +async function getEnvironmentVariables() { + const home = require('os').homedir(); + const filePath = `${home}/${ENV_FILE_PATH}` + + return data = fs.readFileSync(filePath, 'utf8'); } + +async function extractKeys() { + // Extract keys here + return [] +} \ No newline at end of file From 160c3ef7c4fabaa4bff8b8138f628ee525e1ec86 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 21:01:34 +0200 Subject: [PATCH 06/28] update process.env with new value --- packages/server/src/api/controllers/apikeys.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/apikeys.js b/packages/server/src/api/controllers/apikeys.js index 2c31449d0a..8fc0260617 100644 --- a/packages/server/src/api/controllers/apikeys.js +++ b/packages/server/src/api/controllers/apikeys.js @@ -20,7 +20,13 @@ exports.fetch = async function (ctx) { } exports.update = async function (ctx) { - // Do something with ctx.request.body: <{ value: value }> + // Set process.env + const envKeyName = `${ctx.params.key.toUpperCase()}_API_KEY` + process.env[envKeyName] = ctx.request.body.value + + // Write to file + // TODO + ctx.status = 200 ctx.message = `Updated ${ctx.params.key} API key succesfully.` ctx.body = { [ctx.params.key]: ctx.request.body.value } @@ -33,7 +39,8 @@ async function getEnvironmentVariables() { return data = fs.readFileSync(filePath, 'utf8'); } -async function extractKeys() { +async function extractKeys(content) { + const lines = content.split(/\r?\n/) // Extract keys here return [] } \ No newline at end of file From 0ae8c425ee8543f0b106a49d90d8acec9d389616 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Thu, 2 Jul 2020 21:25:25 +0200 Subject: [PATCH 07/28] fetching keys now done correctly --- packages/server/src/api/controllers/apikeys.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/server/src/api/controllers/apikeys.js b/packages/server/src/api/controllers/apikeys.js index 8fc0260617..3a993f53ae 100644 --- a/packages/server/src/api/controllers/apikeys.js +++ b/packages/server/src/api/controllers/apikeys.js @@ -1,21 +1,11 @@ const fs = require("fs") - const ENV_FILE_PATH = ".budibase/.env" exports.fetch = async function (ctx) { - // Check if structure of call makes sense, if not, return error - - - // Read File - const fileContent = await getEnvironmentVariables() - const keys = await extractKeys(fileContent) - - // Temporary while "real" infrastructure to store keys is created ctx.status = 200 - ctx.message = "API Keys" ctx.body = { - budibase: 'testFromBackEnd', - sendgrid: 'testFromBackEnd' + budibase: process.env.BUDIBASE_API_KEY, + sendgrid: process.env.SENDGRID_API_KEY } } @@ -41,6 +31,7 @@ async function getEnvironmentVariables() { async function extractKeys(content) { const lines = content.split(/\r?\n/) + console.log(lines) // Extract keys here - return [] + return lines } \ No newline at end of file From 2a7926a677e2a36987f0e668ba3c50d3c1ce3008 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Thu, 2 Jul 2020 21:22:21 +0100 Subject: [PATCH 08/28] DataTable should not display type & modelId --- packages/standard-components/src/DataTable.svelte | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/standard-components/src/DataTable.svelte b/packages/standard-components/src/DataTable.svelte index e6f097314c..6782a9925c 100644 --- a/packages/standard-components/src/DataTable.svelte +++ b/packages/standard-components/src/DataTable.svelte @@ -8,6 +8,16 @@ let headers = [] let store = _bb.store + const shouldDisplayField = name => { + if (name.startsWith("_")) return false + // always 'record' + if (name === "type") return false + // tables are always tied to a single modelId, this is irrelevant + if (name === "modelId") return false + + return true + } + async function fetchData() { const FETCH_RECORDS_URL = `/api/views/all_${model}` @@ -20,7 +30,7 @@ return state }) - headers = Object.keys(json[0]).filter(key => !key.startsWith("_")) + headers = Object.keys(json[0]).filter(shouldDisplayField) } else { throw new Error("Failed to fetch records.", response) } From 69b05d6f931c9603c2f4018c6bef1ee49cc68045 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 3 Jul 2020 13:03:50 +0100 Subject: [PATCH 09/28] #416 auto init of budibase when electron starts --- packages/cli/src/commands/init/initHandler.js | 87 +--------------- packages/server/package.json | 2 +- packages/server/src/electron.js | 98 +++++++++++-------- .../src/utilities/initialiseBudibase.js | 66 +++++++++++++ 4 files changed, 128 insertions(+), 125 deletions(-) create mode 100644 packages/server/src/utilities/initialiseBudibase.js diff --git a/packages/cli/src/commands/init/initHandler.js b/packages/cli/src/commands/init/initHandler.js index 3fe4134447..eadc74f815 100644 --- a/packages/cli/src/commands/init/initHandler.js +++ b/packages/cli/src/commands/init/initHandler.js @@ -1,88 +1,7 @@ -const inquirer = require("inquirer") -const { exists, readFile, writeFile, ensureDir } = require("fs-extra") -const chalk = require("chalk") -const { serverFileName, xPlatHomeDir } = require("../../common") -const { join } = require("path") -const Sqrl = require("squirrelly") -const uuid = require("uuid") +const { xPlatHomeDir } = require("../../common") +const initialiseBudibase = require("@budibase/server/src/utilities/initialiseBudibase") module.exports = opts => { - return run(opts) -} - -const run = async opts => { - try { - await ensureAppDir(opts) - await setEnvironmentVariables(opts) - await createClientDatabase(opts) - await createDevEnvFile(opts) - console.log(chalk.green("Budibase successfully initialised.")) - } catch (error) { - console.error(`Error initialising Budibase: ${error.message}`) - } -} - -const setEnvironmentVariables = async opts => { - if (opts.couchDbUrl) { - process.env.COUCH_DB_URL = opts.couchDbUrl - } else { - const dataDir = join(opts.dir, ".data") - await ensureDir(dataDir) - process.env.COUCH_DB_URL = - dataDir + (dataDir.endsWith("/") || dataDir.endsWith("\\") ? "" : "/") - } -} - -const ensureAppDir = async opts => { opts.dir = xPlatHomeDir(opts.dir) - await ensureDir(opts.dir) -} - -const createClientDatabase = async opts => { - // cannot be a top level require as it - // will cause environment module to be loaded prematurely - const clientDb = require("@budibase/server/src/db/clientDb") - - if (opts.clientId === "new") { - // cannot be a top level require as it - // will cause environment module to be loaded prematurely - const CouchDB = require("@budibase/server/src/db/client") - const existing = await CouchDB.allDbs() - - let i = 0 - let isExisting = true - while (isExisting) { - i += 1 - opts.clientId = i.toString() - isExisting = existing.includes(clientDb.name(opts.clientId)) - } - } - - await clientDb.create(opts.clientId) -} - -const createDevEnvFile = async opts => { - const destConfigFile = join(opts.dir, "./.env") - let createConfig = !(await exists(destConfigFile)) || opts.quiet - if (!createConfig) { - const answers = await inquirer.prompt([ - { - type: "input", - name: "overwrite", - message: ".env already exists - overwrite? (N/y)", - }, - ]) - createConfig = ["Y", "y", "yes"].includes(answers.overwrite) - } - - if (createConfig) { - const template = await readFile(serverFileName(".env.template"), { - encoding: "utf8", - }) - opts.adminSecret = uuid.v4() - opts.cookieKey1 = uuid.v4() - opts.cookieKey2 = uuid.v4() - const config = Sqrl.Render(template, opts) - await writeFile(destConfigFile, config, { flag: "w+" }) - } + return initialiseBudibase(opts) } diff --git a/packages/server/package.json b/packages/server/package.json index f725f65abf..e57691209e 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -26,7 +26,7 @@ "test": "jest routes --runInBand", "test:integration": "jest workflow --runInBand", "test:watch": "jest --watch", - "initialise": "node ../cli/bin/budi init -b local -q", + "initialise": "node ../cli/bin/budi init -q", "run:docker": "node src/index", "budi": "node ../cli/bin/budi", "dev:builder": "nodemon ../cli/bin/budi run", diff --git a/packages/server/src/electron.js b/packages/server/src/electron.js index d496c276cc..1d6687a145 100644 --- a/packages/server/src/electron.js +++ b/packages/server/src/electron.js @@ -1,55 +1,73 @@ const { app, BrowserWindow, shell } = require("electron") const { join } = require("path") -const { homedir } = require("os") const isDev = require("electron-is-dev") const { autoUpdater } = require("electron-updater") const unhandled = require("electron-unhandled") +const { existsSync } = require("fs-extra") +const initialiseBudibase = require("./utilities/initialiseBudibase") +const { budibaseAppsDir } = require("./utilities/budibaseDir") -require("dotenv").config({ path: join(homedir(), ".budibase", ".env") }) +const budibaseDir = budibaseAppsDir() +const envFile = join(budibaseDir, ".env") -if (isDev) { - unhandled({ - showDialog: true, +if (!existsSync(envFile)) { + // assume not initialised + initialiseBudibase({ dir: budibaseDir }).then(() => { + startApp() }) +} else { + startApp() } -const APP_URL = "http://localhost:4001/_builder" -const APP_TITLE = "Budibase Builder" +function startApp() { + // evict environment from cache, so it reloads when next asked + delete require.cache[require.resolve("./environment")] + require("dotenv").config({ path: envFile }) -let win - -function handleRedirect(e, url) { - e.preventDefault() - shell.openExternal(url) -} - -async function createWindow() { - app.server = await require("./app")() - win = new BrowserWindow({ width: 1920, height: 1080 }) - win.setTitle(APP_TITLE) - win.loadURL(APP_URL) if (isDev) { - win.webContents.openDevTools() - } else { - autoUpdater.checkForUpdatesAndNotify() + unhandled({ + showDialog: true, + }) } - // open _blank in default browser - win.webContents.on("new-window", handleRedirect) - win.webContents.on("will-navigate", handleRedirect) + const APP_URL = "http://localhost:4001/_builder" + const APP_TITLE = "Budibase Builder" + + let win + + function handleRedirect(e, url) { + e.preventDefault() + shell.openExternal(url) + } + + async function createWindow() { + app.server = await require("./app")() + win = new BrowserWindow({ width: 1920, height: 1080 }) + win.setTitle(APP_TITLE) + win.loadURL(APP_URL) + if (isDev) { + win.webContents.openDevTools() + } else { + autoUpdater.checkForUpdatesAndNotify() + } + + // open _blank in default browser + win.webContents.on("new-window", handleRedirect) + win.webContents.on("will-navigate", handleRedirect) + } + + app.whenReady().then(createWindow) + + // Quit when all windows are closed. + app.on("window-all-closed", () => { + // On macOS it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== "darwin") app.quit() + }) + + app.on("activate", () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (win === null) createWindow() + }) } - -app.whenReady().then(createWindow) - -// Quit when all windows are closed. -app.on("window-all-closed", () => { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== "darwin") app.quit() -}) - -app.on("activate", () => { - // On macOS it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (win === null) createWindow() -}) diff --git a/packages/server/src/utilities/initialiseBudibase.js b/packages/server/src/utilities/initialiseBudibase.js new file mode 100644 index 0000000000..87fedb434f --- /dev/null +++ b/packages/server/src/utilities/initialiseBudibase.js @@ -0,0 +1,66 @@ +const { exists, readFile, writeFile, ensureDir } = require("fs-extra") +const { join, resolve } = require("path") +const Sqrl = require("squirrelly") +const uuid = require("uuid") + +module.exports = async opts => { + await ensureDir(opts.dir) + await setCouchDbUrl(opts) + + // need an env file to create the client database + await createDevEnvFile(opts) + await createClientDatabase(opts) + + // need to recreate the env file, as we only now have a client id + // quiet flag will force overwrite of config + opts.quiet = true + await createDevEnvFile(opts) +} + +const setCouchDbUrl = async opts => { + if (!opts.couchDbUrl) { + const dataDir = join(opts.dir, ".data") + await ensureDir(dataDir) + opts.couchDbUrl = + dataDir + (dataDir.endsWith("/") || dataDir.endsWith("\\") ? "" : "/") + } +} + +const createDevEnvFile = async opts => { + const destConfigFile = join(opts.dir, "./.env") + let createConfig = !(await exists(destConfigFile)) || opts.quiet + if (createConfig) { + const template = await readFile( + resolve(__dirname, "..", "..", ".env.template"), + { + encoding: "utf8", + } + ) + opts.cookieKey1 = opts.cookieKey1 || uuid.v4() + const config = Sqrl.Render(template, opts) + await writeFile(destConfigFile, config, { flag: "w+" }) + } +} + +const createClientDatabase = async opts => { + // cannot be a top level require as it + // will cause environment module to be loaded prematurely + const clientDb = require("../db/clientDb") + + if (!opts.clientId || opts.clientId === "new") { + // cannot be a top level require as it + // will cause environment module to be loaded prematurely + const CouchDB = require("../db/client") + const existing = await CouchDB.allDbs() + + let i = 0 + let isExisting = true + while (isExisting) { + i += 1 + opts.clientId = i.toString() + isExisting = existing.includes(clientDb.name(opts.clientId)) + } + } + + await clientDb.create(opts.clientId) +} From 03dabc58100e25c1668f4fa29d759e3790a72a18 Mon Sep 17 00:00:00 2001 From: cmack Date: Fri, 3 Jul 2020 13:38:51 +0100 Subject: [PATCH 10/28] Moz Prefixes and X Positional Awareness --- .../components/CheckedBackground.svelte | 4 +- .../Colorpicker/components/Colorpicker.svelte | 322 +++++++++--------- .../components/Colorpreview.svelte | 198 ++++++----- 3 files changed, 268 insertions(+), 256 deletions(-) diff --git a/packages/builder/src/components/userInterface/Colorpicker/components/CheckedBackground.svelte b/packages/builder/src/components/userInterface/Colorpicker/components/CheckedBackground.svelte index 2baa6b466e..c1a3c2f6fc 100644 --- a/packages/builder/src/components/userInterface/Colorpicker/components/CheckedBackground.svelte +++ b/packages/builder/src/components/userInterface/Colorpicker/components/CheckedBackground.svelte @@ -1,5 +1,5 @@ - -
- -
- -
- -
-
-
- -
- -
-
- setHue(hue.detail)} - on:dragend={dispatchValue} /> - - - setAlpha(alpha.detail, isDrag)} - on:dragend={dispatchValue} /> - - -
-
- - {#if !disableSwatches} -
- {#if hasSwatches} - {#each swatches as color, idx} - {#if idx < 12} - applySwatch(color)} - on:removeswatch={() => removeSwatch(idx)} /> - {/if} - {/each} - {/if} - {#if swatches.length < 12} -
- + -
- {/if} -
- {/if} - -
- - handleColorInput(event.target.value)} - on:change={dispatchInputChange} /> -
-
- -
- - + + +
+ +
+ +
+ +
+
+
+ +
+ +
+
+ setHue(hue.detail)} + on:dragend={dispatchValue} /> + + + setAlpha(alpha.detail, isDrag)} + on:dragend={dispatchValue} /> + + +
+
+ + {#if !disableSwatches} +
+ {#if hasSwatches} + {#each swatches as color, idx} + {#if idx < 12} + applySwatch(color)} + on:removeswatch={() => removeSwatch(idx)} /> + {/if} + {/each} + {/if} + {#if swatches.length < 12} +
+ + +
+ {/if} +
+ {/if} + +
+ + handleColorInput(event.target.value)} + on:change={dispatchInputChange} /> +
+
+ +
+ diff --git a/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte b/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte index a28c8d2560..f3ab6f6f22 100644 --- a/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte +++ b/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte @@ -1,93 +1,141 @@ + +
@@ -127,41 +175,3 @@
{/if}
- - From cb0492886b1b06192635e2b6854cf027eb3c1255 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 3 Jul 2020 14:44:25 +0100 Subject: [PATCH 11/28] hiding the `` for now --- .../[application]/backend/model/[selectedModel]/index.svelte | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte b/packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte index 3b2c43a178..6da373bcca 100644 --- a/packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte +++ b/packages/builder/src/pages/[application]/backend/model/[selectedModel]/index.svelte @@ -23,9 +23,7 @@ } -{#if selectedModel.schema && Object.keys(selectedModel.schema).length === 0} - -{:else if $backendUiStore.selectedDatabase._id && selectedModel.name} +{#if $backendUiStore.selectedDatabase._id && selectedModel.name} {:else} create your first table to start building From 6bf394fde57d51a31263f221900bf2ca9de9522e Mon Sep 17 00:00:00 2001 From: cmack Date: Fri, 3 Jul 2020 16:16:38 +0100 Subject: [PATCH 12/28] Minor bug fixes --- .../Colorpicker/components/Colorpicker.svelte | 2 +- .../components/Colorpreview.svelte | 2 - .../Colorpicker/components/Swatch.svelte | 81 ++++++++++--------- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/packages/builder/src/components/userInterface/Colorpicker/components/Colorpicker.svelte b/packages/builder/src/components/userInterface/Colorpicker/components/Colorpicker.svelte index 254dc1f288..7fa536a474 100644 --- a/packages/builder/src/components/userInterface/Colorpicker/components/Colorpicker.svelte +++ b/packages/builder/src/components/userInterface/Colorpicker/components/Colorpicker.svelte @@ -154,7 +154,7 @@ } function removeSwatch(idx) { - let removedSwatch = swatches.splice(idx, 1); + let [removedSwatch] = swatches.splice(idx, 1); swatches = swatches; dispatch("removeswatch", removedSwatch); if (swatchesSetFromLocalStore) { diff --git a/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte b/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte index f3ab6f6f22..2d9426fbae 100644 --- a/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte +++ b/packages/builder/src/components/userInterface/Colorpicker/components/Colorpreview.svelte @@ -114,8 +114,6 @@ cursor: pointer; border-radius: 3px; border: 1px solid #dedada; - position: absolute; - left: 110px; } .preview-error { diff --git a/packages/builder/src/components/userInterface/Colorpicker/components/Swatch.svelte b/packages/builder/src/components/userInterface/Colorpicker/components/Swatch.svelte index 11bd4d3821..e56e6d0b6f 100644 --- a/packages/builder/src/components/userInterface/Colorpicker/components/Swatch.svelte +++ b/packages/builder/src/components/userInterface/Colorpicker/components/Swatch.svelte @@ -1,39 +1,15 @@ -
- -
dispatch('click') }} - in:fade - title={color} - class="swatch" - style={`background: ${color};`} - on:click|self - on:mouseover={() => (hovered = true)} - on:mouseleave={() => (hovered = false)}> - {#if hovered} -
dispatch('removeswatch')}> - dispatch('removeswatch')}>× -
- {/if} -
-
-
- + +
+ +
dispatch('click') }} + in:fade + title={color} + class="swatch" + style={`background: ${color};`} + on:mouseover={() => (hovered = true)} + on:mouseleave={() => (hovered = false)} + on:click|self> + {#if hovered} + dispatch('removeswatch')} /> + {/if} +
+
+
From 1d85ce5acb2988bd46caf0db55faa8e28d9a4b86 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 3 Jul 2020 21:48:34 +0100 Subject: [PATCH 13/28] more understandable screenslot & default header on master screen --- .../AppPreview/CurrentItemPreview.svelte | 128 +++++++++++------- .../AppPreview/iframeTemplate.js | 10 ++ .../appDirectoryTemplate/pages/main/page.json | 75 ++++++++-- 3 files changed, 155 insertions(+), 58 deletions(-) diff --git a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte index abf226048b..239cebdd0a 100644 --- a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte @@ -25,16 +25,10 @@ name: "Screen Placeholder", route: "*", props: { - "_id": "49c3d0a2-7028-46f0-b004-7eddf62ad01c", + "_id": "screenslot-placeholder", "_component": "@budibase/standard-components/container", "_styles": { - "normal": { - "padding": "0px", - "font-family": "Roboto", - "border-width": "0", - "border-style": "None", - "text-align": "center" - }, + "normal": {}, "hover": {}, "active": {}, "selected": {} @@ -45,47 +39,87 @@ "type": "div", "_children": [ { - "_id": "335428f7-f9ca-4acd-9e76-71bc8ad27324", - "_component": "@budibase/standard-components/container", - "_styles": { - "normal": { - "padding": "16px", - "border-style": "Dashed", - "border-width": "2px", - "border-color": "#8a8989fa" - }, - "hover": {}, - "active": {}, - "selected": {} + "_id": "51a1b494-0fa4-49c3-90cc-c2a6c7a3f888", + "_component": "@budibase/standard-components/container", + "_styles": { + "normal": { + "display": "flex", + "flex-direction": "column", + "align-items": "center" }, - "_code": "", - "className": "", - "onLoad": [], - "type": "div", - "_instanceId": "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3", - "_instanceName": "Container", - "_children": [ - { - "_id": "ddb6a225-33ba-4ba8-91da-bc6a2697ebf9", - "_component": "@budibase/standard-components/heading", - "_styles": { - "normal": { - "font-family": "Roboto" - }, - "hover": {}, - "active": {}, - "selected": {} + "hover": {}, + "active": {}, + "selected": {} + }, + "_code": "", + "className": "", + "onLoad": [], + "type": "div", + "_instanceId": "inst_40d9036_4c81114e2bf145ab8721978c66e09a10", + "_instanceName": "Container", + "_children": [ + { + "_id": "90a52cd0-f215-46c1-b29b-e28f9e7edf72", + "_component": "@budibase/standard-components/heading", + "_styles": { + "normal": { + "width": "500px", + "padding": "8px" }, - "_code": "", - "className": "", - "text": "Your screens go here", - "type": "h1", - "_instanceId": "inst_b3b4e95_ab0df02dda3f4d8eb4b35eea2968bad3", - "_instanceName": "Heading", - "_children": [] - } - ] - } + "hover": {}, + "active": {}, + "selected": {} + }, + "_code": "", + "className": "", + "text": "Screenslot", + "type": "h1", + "_instanceId": "inst_40d9036_4c81114e2bf145ab8721978c66e09a10", + "_instanceName": "Heading", + "_children": [] + }, + { + "_id": "71a3da65-72c6-4c43-8c6a-49871c07b77d", + "_component": "@budibase/standard-components/text", + "_styles": { + "normal": { + "max-width": "", + "text-align": "left", + "width": "500px", + "padding": "8px" + }, + "hover": {}, + "active": {}, + "selected": {} + }, + "_code": "", + "text": "The screens that you create will be displayed inside this box.", + "type": "none", + "_instanceId": "inst_40d9036_4c81114e2bf145ab8721978c66e09a10", + "_instanceName": "Text" + }, + { + "_id": "8af80374-460d-497b-a5d8-7dd2ec4a7bbc", + "_component": "@budibase/standard-components/text", + "_styles": { + "normal": { + "max-width": "", + "text-align": "left", + "width": "500px", + "padding": "8px" + }, + "hover": {}, + "active": {}, + "selected": {} + }, + "_code": "", + "text": "This box is just a placeholder, to show you the position of screens.", + "type": "none", + "_instanceId": "inst_40d9036_4c81114e2bf145ab8721978c66e09a10", + "_instanceName": "Text" + } + ] + } ], "_instanceName": "Content Placeholder" }, diff --git a/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js b/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js index b78f882fe1..e269e3166e 100644 --- a/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js +++ b/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js @@ -24,6 +24,16 @@ export default ` text-transform: uppercase; font-weight: bold; } + + .container-screenslot-placeholder { + padding: 20px; + text-align: center; + border-style: dashed !important; + border-width: 1px; + color: #806fde; + background: #e9e6ff44; + height: 100%; + }
-

{modelDef.name} Form

+ {#if title} +

{title}

+ {/if}
{#each fields as field} diff --git a/packages/standard-components/src/DataFormWide.svelte b/packages/standard-components/src/DataFormWide.svelte index f712c787de..332e5d1672 100644 --- a/packages/standard-components/src/DataFormWide.svelte +++ b/packages/standard-components/src/DataFormWide.svelte @@ -2,6 +2,7 @@ import { onMount } from "svelte" export let _bb export let model + export let title const TYPE_MAP = { string: "text", @@ -9,8 +10,6 @@ number: "number", } - let username - let password let newModel = { modelId: model, } @@ -54,7 +53,9 @@ -

{modelDef.name} Form

+ {#if title} +

{title}

+ {/if}
{#each fields as field} From fee6985f3316697ffea259638d25880c783f9b8c Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Mon, 6 Jul 2020 11:17:54 +0100 Subject: [PATCH 17/28] bugfix: delete component sometimes breaks navigation --- .../frontend/[page]/[screen]/_layout.svelte | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/pages/[application]/frontend/[page]/[screen]/_layout.svelte b/packages/builder/src/pages/[application]/frontend/[page]/[screen]/_layout.svelte index b9bed2866a..b601251b16 100644 --- a/packages/builder/src/pages/[application]/frontend/[page]/[screen]/_layout.svelte +++ b/packages/builder/src/pages/[application]/frontend/[page]/[screen]/_layout.svelte @@ -38,15 +38,21 @@ // Loop through each ID ids.forEach(id => { - // Find ID and select it - componentToSelect = currentChildren.find(child => child._id === id) + // Find ID + const component = currentChildren.find(child => child._id === id) + + // If it does not exist, ignore (use last valid route) + if (!component) return + + componentToSelect = component // Update childrens array to selected components children currentChildren = componentToSelect._children }) // Select Component! - store.selectComponent(componentToSelect) + if (componentToSelect) + store.selectComponent(componentToSelect) } From cc1659f807fcc9c01e54d79e21c9881717140113 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Mon, 6 Jul 2020 11:30:36 +0100 Subject: [PATCH 18/28] Login: allow edit of title & button text --- .../userInterface/temporaryPanelStructure.js | 10 ++++++++++ .../pages/unauthenticated/page.json | 3 ++- packages/standard-components/components.json | 5 +++-- packages/standard-components/src/Login.svelte | 10 ++++++---- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index e3eb0b67f4..69f0005659 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -303,6 +303,16 @@ export default { key: "logo", control: Input, }, + { + label: "Title", + key: "title", + control: Input, + }, + { + label: "Button Text", + key: "buttonText", + control: Input, + }, ], }, }, diff --git a/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json b/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json index bfe0590912..fb010023b9 100644 --- a/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json +++ b/packages/server/src/utilities/appDirectoryTemplate/pages/unauthenticated/page.json @@ -28,7 +28,8 @@ "_instanceName": "Login", "inputClass": "", "_children": [], - "name": "{{ name }}", + "title": "Login to {{ name }}", + "buttonText": "Login", "logo": "" } ], diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index cbe2d7ff69..a46a44b06a 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -66,7 +66,7 @@ "props": { "logo": "asset", "loginRedirect": "string", - "name": "string", + "title": "string", "usernameLabel": { "type": "string", "default": "Username" @@ -80,7 +80,8 @@ "default": "Login" }, "buttonClass": "string", - "inputClass": "string" + "inputClass": "string", + "buttonText": "string" }, "tags": [ "login", diff --git a/packages/standard-components/src/Login.svelte b/packages/standard-components/src/Login.svelte index d09cd0ff2b..2b94d9e425 100644 --- a/packages/standard-components/src/Login.svelte +++ b/packages/standard-components/src/Login.svelte @@ -1,9 +1,9 @@ diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 890e573817..526c36d423 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -10,6 +10,7 @@ const { budibaseAppsDir } = require("../../utilities/budibaseDir") const { exec } = require("child_process") const sqrl = require("squirrelly") const setBuilderToken = require("../../utilities/builder/setBuilderToken") +const fs = require("fs-extra") exports.fetch = async function(ctx) { const db = new CouchDB(ClientDb.name(getClientId(ctx))) @@ -106,6 +107,21 @@ exports.update = async function(ctx) { ctx.body = response } +exports.delete = async function(ctx) { + const db = new CouchDB(ClientDb.name(getClientId(ctx))) + const app = await db.get(ctx.params.applicationId) + const result = await db.remove(app) + await fs.rmdir(`${budibaseAppsDir()}/${ctx.params.applicationId}`, { + recursive: true, + }) + + console.log + + ctx.status = 200 + ctx.message = `Application ${app.name} deleted successfully.` + ctx.body = result +} + const createEmptyAppPackage = async (ctx, app) => { const templateFolder = resolve( __dirname, diff --git a/packages/server/src/api/routes/application.js b/packages/server/src/api/routes/application.js index 2843770b46..65e73e95f5 100644 --- a/packages/server/src/api/routes/application.js +++ b/packages/server/src/api/routes/application.js @@ -14,5 +14,6 @@ router ) .put("/api/:applicationId", authorized(BUILDER), controller.update) .post("/api/applications", authorized(BUILDER), controller.create) + .delete("/api/:applicationId", authorized(BUILDER), controller.delete) module.exports = router From 246d4beb802847e9bf59c55ad463d8238b679a75 Mon Sep 17 00:00:00 2001 From: kevmodrome Date: Tue, 7 Jul 2020 14:47:27 +0200 Subject: [PATCH 26/28] remove som console.logs --- packages/builder/src/components/settings/tabs/DangerZone.svelte | 1 - packages/server/src/api/controllers/application.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/builder/src/components/settings/tabs/DangerZone.svelte b/packages/builder/src/components/settings/tabs/DangerZone.svelte index 40286a902d..524fee3351 100644 --- a/packages/builder/src/components/settings/tabs/DangerZone.svelte +++ b/packages/builder/src/components/settings/tabs/DangerZone.svelte @@ -11,7 +11,6 @@ loading = true const id = $params.application const res = await del(`/api/${id}`) - console.log(res) const json = await res.json() loading = false diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 526c36d423..e1b850a31f 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -115,8 +115,6 @@ exports.delete = async function(ctx) { recursive: true, }) - console.log - ctx.status = 200 ctx.message = `Application ${app.name} deleted successfully.` ctx.body = result From 671170d5647e223b4d29db44e4501e42345d21c4 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Tue, 7 Jul 2020 13:51:12 +0100 Subject: [PATCH 27/28] remove import csv button --- .../src/components/nav/ModelSetupNav/ModelSetupNav.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte b/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte index e1f4d3601b..0855d04b2e 100644 --- a/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte +++ b/packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte @@ -103,10 +103,12 @@ class="budibase__input" bind:value={$backendUiStore.draftModel.name} />
+ {/if}
{/if} - +