@@ -66,6 +72,15 @@
>
Change organisation
+ {:else}
+ {
+ modal.show()
+ }}
+ >
+ Import from cloud
+
{/if}
diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte
index d84b327e90..096c4ed5b5 100644
--- a/packages/builder/src/pages/builder/portal/apps/index.svelte
+++ b/packages/builder/src/pages/builder/portal/apps/index.svelte
@@ -70,6 +70,15 @@
creatingApp = true
}
+ const initiateAppsExport = () => {
+ try {
+ download(`/api/cloud/export`)
+ notifications.success("Apps exported successfully")
+ } catch (err) {
+ notifications.error(`Error exporting apps: ${err}`)
+ }
+ }
+
const initiateAppImport = () => {
template = { fromFile: true }
creationModal.show()
@@ -190,6 +199,7 @@
Apps
+
diff --git a/packages/server/scripts/dev/manage.js b/packages/server/scripts/dev/manage.js
index 2557f88adf..e0801bc9df 100644
--- a/packages/server/scripts/dev/manage.js
+++ b/packages/server/scripts/dev/manage.js
@@ -37,7 +37,7 @@ async function init() {
const envFileJson = {
PORT: 4001,
MINIO_URL: "http://localhost:10000/",
- COUCH_DB_URL: "http://@localhost:10000/db/",
+ COUCH_DB_URL: "http://budibase:budibase@localhost:10000/db/",
REDIS_URL: "localhost:6379",
WORKER_URL: "http://localhost:4002",
INTERNAL_API_KEY: "budibase",
diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js
index a6e05ff002..3a0b0f8ed8 100644
--- a/packages/server/src/api/controllers/application.js
+++ b/packages/server/src/api/controllers/application.js
@@ -31,7 +31,7 @@ const {
getDeployedApps,
removeAppFromUserRoles,
} = require("../../utilities/workerRequests")
-const { clientLibraryPath } = require("../../utilities")
+const { clientLibraryPath, stringToReadStream } = require("../../utilities")
const { getAllLocks } = require("../../utilities/redis")
const {
updateClientLibrary,
@@ -115,7 +115,7 @@ async function createInstance(template) {
// replicate the template data to the instance DB
// this is currently very hard to test, downloading and importing template files
if (template && template.templateString) {
- const { ok } = await db.load(template.templateString)
+ const { ok } = await db.load(stringToReadStream(template.templateString))
if (!ok) {
throw "Error loading database dump from memory."
}
diff --git a/packages/server/src/api/controllers/cloud.js b/packages/server/src/api/controllers/cloud.js
index d08efbef94..1c2bdcc76a 100644
--- a/packages/server/src/api/controllers/cloud.js
+++ b/packages/server/src/api/controllers/cloud.js
@@ -6,6 +6,7 @@ const {
sendTempFile,
readFileSync,
} = require("../../utilities/fileSystem")
+const { stringToReadStream } = require("../../utilities")
const { getGlobalDBName, getGlobalDB } = require("@budibase/auth/tenancy")
const { create } = require("./application")
@@ -54,13 +55,15 @@ exports.importApps = async ctx => {
)
}
const importFile = ctx.request.files.importFile
- const importString = readFileSync(importFile.file.path)
+ const importString = readFileSync(importFile.path)
const dbs = JSON.parse(importString)
const globalDb = dbs.global
+ // remove from the list of apps
+ delete dbs.global
const db = getGlobalDB()
// load the global db first
- await db.load(globalDb)
- for (let [appName, appImport] of Object.values(dbs)) {
+ await db.load(stringToReadStream(globalDb))
+ for (let [appName, appImport] of Object.entries(dbs)) {
await createApp(appName, appImport)
}
ctx.body = {
diff --git a/packages/server/src/api/routes/index.js b/packages/server/src/api/routes/index.js
index 2e1353df98..29d0cd42b4 100644
--- a/packages/server/src/api/routes/index.js
+++ b/packages/server/src/api/routes/index.js
@@ -24,6 +24,7 @@ const hostingRoutes = require("./hosting")
const backupRoutes = require("./backup")
const metadataRoutes = require("./metadata")
const devRoutes = require("./dev")
+const cloudRoutes = require("./cloud")
exports.mainRoutes = [
authRoutes,
@@ -49,6 +50,7 @@ exports.mainRoutes = [
backupRoutes,
metadataRoutes,
devRoutes,
+ cloudRoutes,
// these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this
tableRoutes,
diff --git a/packages/server/src/utilities/fileSystem/index.js b/packages/server/src/utilities/fileSystem/index.js
index e3798192b7..6fee7b4283 100644
--- a/packages/server/src/utilities/fileSystem/index.js
+++ b/packages/server/src/utilities/fileSystem/index.js
@@ -176,6 +176,15 @@ exports.storeTempFile = fileContents => {
return path
}
+/**
+ * Utility function for getting a file read stream - a simple in memory buffered read
+ * stream doesn't work for pouchdb.
+ */
+exports.stringToFileStream = contents => {
+ const path = exports.storeTempFile(contents)
+ return fs.createReadStream(path)
+}
+
/**
* Creates a temp file and returns it from the API.
* @param {string} fileContents the contents to be returned in file.
diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js
index b16a687fe5..e568ba063c 100644
--- a/packages/server/src/utilities/index.js
+++ b/packages/server/src/utilities/index.js
@@ -3,6 +3,7 @@ const { OBJ_STORE_DIRECTORY } = require("../constants")
const { sanitizeKey } = require("@budibase/auth/src/objectStore")
const CouchDB = require("../db")
const { generateMetadataID } = require("../db/utils")
+const Readable = require("stream").Readable
const BB_CDN = "https://cdn.budi.live"
@@ -124,3 +125,12 @@ exports.escapeDangerousCharacters = string => {
.replace(/[\r]/g, "\\r")
.replace(/[\t]/g, "\\t")
}
+
+exports.stringToReadStream = string => {
+ return new Readable({
+ read() {
+ this.push(string)
+ this.push(null)
+ },
+ })
+}