Some fixes after testing and adding some basic work to the frontend.

This commit is contained in:
mike12345567 2021-09-28 18:05:52 +01:00
parent a83b9835b2
commit d282cd030f
9 changed files with 106 additions and 6 deletions

View File

@ -0,0 +1,51 @@
<script>
import { notifications, ModalContent, Dropzone, Body } from "@budibase/bbui"
import { post } from "builderStore/api"
import { goto } from "@roxi/routify"
let submitting = false
$: value = { file: null }
async function importApps() {
submitting = true
try {
// Create form data to create app
let data = new FormData()
data.append("importFile", value.file)
// Create App
const importResp = await post("/api/cloud/import", data, {})
const importJson = await importResp.json()
if (!importResp.ok) {
throw new Error(importJson.message)
}
// now login
$goto("../auth")
} catch (error) {
notifications.error(error)
submitting = false
}
}
</script>
<ModalContent
title="Import apps"
confirmText="Import apps"
onConfirm={importApps}
disabled={!value.file}
>
<Body
>Please upload the file that was exported from your Cloud environment to get
started</Body
>
<Dropzone
gallery={false}
label="File to import"
value={[value.file]}
on:change={e => {
value.file = e.detail?.[0]
}}
/>
</ModalContent>

View File

@ -7,15 +7,18 @@
Input, Input,
Body, Body,
ActionButton, ActionButton,
Modal,
} from "@budibase/bbui" } from "@budibase/bbui"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import api from "builderStore/api" import api from "builderStore/api"
import { admin, auth } from "stores/portal" import { admin, auth } from "stores/portal"
import PasswordRepeatInput from "components/common/users/PasswordRepeatInput.svelte" import PasswordRepeatInput from "components/common/users/PasswordRepeatInput.svelte"
import ImportAppsModal from "./_components/ImportAppsModal.svelte"
import Logo from "assets/bb-emblem.svg" import Logo from "assets/bb-emblem.svg"
let adminUser = {} let adminUser = {}
let error let error
let modal
$: tenantId = $auth.tenantId $: tenantId = $auth.tenantId
$: multiTenancyEnabled = $admin.multiTenancy $: multiTenancyEnabled = $admin.multiTenancy
@ -38,6 +41,9 @@
} }
</script> </script>
<Modal bind:this={modal} padding={false} width="600px">
<ImportAppsModal />
</Modal>
<section> <section>
<div class="container"> <div class="container">
<Layout> <Layout>
@ -66,6 +72,15 @@
> >
Change organisation Change organisation
</ActionButton> </ActionButton>
{:else}
<ActionButton
quiet
on:click={() => {
modal.show()
}}
>
Import from cloud
</ActionButton>
{/if} {/if}
</Layout> </Layout>
</Layout> </Layout>

View File

@ -70,6 +70,15 @@
creatingApp = true creatingApp = true
} }
const initiateAppsExport = () => {
try {
download(`/api/cloud/export`)
notifications.success("Apps exported successfully")
} catch (err) {
notifications.error(`Error exporting apps: ${err}`)
}
}
const initiateAppImport = () => { const initiateAppImport = () => {
template = { fromFile: true } template = { fromFile: true }
creationModal.show() creationModal.show()
@ -190,6 +199,7 @@
<div class="title"> <div class="title">
<Heading>Apps</Heading> <Heading>Apps</Heading>
<ButtonGroup> <ButtonGroup>
<Button secondary on:click={initiateAppsExport}>Export apps</Button>
<Button secondary on:click={initiateAppImport}>Import app</Button> <Button secondary on:click={initiateAppImport}>Import app</Button>
<Button cta on:click={initiateAppCreation}>Create app</Button> <Button cta on:click={initiateAppCreation}>Create app</Button>
</ButtonGroup> </ButtonGroup>

View File

@ -37,7 +37,7 @@ async function init() {
const envFileJson = { const envFileJson = {
PORT: 4001, PORT: 4001,
MINIO_URL: "http://localhost:10000/", 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", REDIS_URL: "localhost:6379",
WORKER_URL: "http://localhost:4002", WORKER_URL: "http://localhost:4002",
INTERNAL_API_KEY: "budibase", INTERNAL_API_KEY: "budibase",

View File

@ -31,7 +31,7 @@ const {
getDeployedApps, getDeployedApps,
removeAppFromUserRoles, removeAppFromUserRoles,
} = require("../../utilities/workerRequests") } = require("../../utilities/workerRequests")
const { clientLibraryPath } = require("../../utilities") const { clientLibraryPath, stringToReadStream } = require("../../utilities")
const { getAllLocks } = require("../../utilities/redis") const { getAllLocks } = require("../../utilities/redis")
const { const {
updateClientLibrary, updateClientLibrary,
@ -115,7 +115,7 @@ async function createInstance(template) {
// replicate the template data to the instance DB // replicate the template data to the instance DB
// this is currently very hard to test, downloading and importing template files // this is currently very hard to test, downloading and importing template files
if (template && template.templateString) { if (template && template.templateString) {
const { ok } = await db.load(template.templateString) const { ok } = await db.load(stringToReadStream(template.templateString))
if (!ok) { if (!ok) {
throw "Error loading database dump from memory." throw "Error loading database dump from memory."
} }

View File

@ -6,6 +6,7 @@ const {
sendTempFile, sendTempFile,
readFileSync, readFileSync,
} = require("../../utilities/fileSystem") } = require("../../utilities/fileSystem")
const { stringToReadStream } = require("../../utilities")
const { getGlobalDBName, getGlobalDB } = require("@budibase/auth/tenancy") const { getGlobalDBName, getGlobalDB } = require("@budibase/auth/tenancy")
const { create } = require("./application") const { create } = require("./application")
@ -54,13 +55,15 @@ exports.importApps = async ctx => {
) )
} }
const importFile = ctx.request.files.importFile const importFile = ctx.request.files.importFile
const importString = readFileSync(importFile.file.path) const importString = readFileSync(importFile.path)
const dbs = JSON.parse(importString) const dbs = JSON.parse(importString)
const globalDb = dbs.global const globalDb = dbs.global
// remove from the list of apps
delete dbs.global
const db = getGlobalDB() const db = getGlobalDB()
// load the global db first // load the global db first
await db.load(globalDb) await db.load(stringToReadStream(globalDb))
for (let [appName, appImport] of Object.values(dbs)) { for (let [appName, appImport] of Object.entries(dbs)) {
await createApp(appName, appImport) await createApp(appName, appImport)
} }
ctx.body = { ctx.body = {

View File

@ -24,6 +24,7 @@ const hostingRoutes = require("./hosting")
const backupRoutes = require("./backup") const backupRoutes = require("./backup")
const metadataRoutes = require("./metadata") const metadataRoutes = require("./metadata")
const devRoutes = require("./dev") const devRoutes = require("./dev")
const cloudRoutes = require("./cloud")
exports.mainRoutes = [ exports.mainRoutes = [
authRoutes, authRoutes,
@ -49,6 +50,7 @@ exports.mainRoutes = [
backupRoutes, backupRoutes,
metadataRoutes, metadataRoutes,
devRoutes, devRoutes,
cloudRoutes,
// these need to be handled last as they still use /api/:tableId // these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this // this could be breaking as koa may recognise other routes as this
tableRoutes, tableRoutes,

View File

@ -176,6 +176,15 @@ exports.storeTempFile = fileContents => {
return path 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. * Creates a temp file and returns it from the API.
* @param {string} fileContents the contents to be returned in file. * @param {string} fileContents the contents to be returned in file.

View File

@ -3,6 +3,7 @@ const { OBJ_STORE_DIRECTORY } = require("../constants")
const { sanitizeKey } = require("@budibase/auth/src/objectStore") const { sanitizeKey } = require("@budibase/auth/src/objectStore")
const CouchDB = require("../db") const CouchDB = require("../db")
const { generateMetadataID } = require("../db/utils") const { generateMetadataID } = require("../db/utils")
const Readable = require("stream").Readable
const BB_CDN = "https://cdn.budi.live" const BB_CDN = "https://cdn.budi.live"
@ -124,3 +125,12 @@ exports.escapeDangerousCharacters = string => {
.replace(/[\r]/g, "\\r") .replace(/[\r]/g, "\\r")
.replace(/[\t]/g, "\\t") .replace(/[\t]/g, "\\t")
} }
exports.stringToReadStream = string => {
return new Readable({
read() {
this.push(string)
this.push(null)
},
})
}