Export app without rows

This commit is contained in:
Peter Clement 2022-05-25 09:26:10 +01:00
parent d08e5ad95b
commit a0735efbb7
5 changed files with 51 additions and 13 deletions

View File

@ -0,0 +1,16 @@
<script>
import { ModalContent, Toggle } from "@budibase/bbui"
export let app
let includeRows = true
const exportApp = () => {
const id = app.deployed ? app.prodId : app.devId
const appName = encodeURIComponent(app.name)
window.location = `/api/backups/export?appId=${id}&appname=${appName}&includeRows=${includeRows}`
}
</script>
<ModalContent title={"Export"} confirmText={"Export"} onConfirm={exportApp}>
<Toggle text="Include Data" bind:value={includeRows} />
</ModalContent>

View File

@ -18,6 +18,7 @@
import CreateAppModal from "components/start/CreateAppModal.svelte"
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
import ChooseIconModal from "components/start/ChooseIconModal.svelte"
import ExportAppModal from "components/start/ExportAppModal.svelte"
import { store, automationStore } from "builderStore"
import { API } from "api"
@ -38,6 +39,7 @@
let updatingModal
let deletionModal
let unpublishModal
let exportModal
let iconModal
let creatingApp = false
let loaded = $apps?.length || $templates?.length
@ -198,9 +200,8 @@
}
const exportApp = app => {
const id = app.deployed ? app.prodId : app.devId
const appName = encodeURIComponent(app.name)
window.location = `/api/backups/export?appId=${id}&appname=${appName}`
exportModal.show()
selectedApp = app
}
const unpublishApp = app => {
@ -434,6 +435,10 @@
<UpdateAppModal app={selectedApp} />
</Modal>
<Modal bind:this={exportModal} padding={false} width="600px">
<ExportAppModal app={selectedApp} />
</Modal>
<ConfirmDialog
bind:this={deletionModal}
title="Confirm deletion"

View File

@ -1,9 +1,11 @@
const { streamBackup } = require("../../utilities/fileSystem")
exports.exportAppDump = async function (ctx) {
const { appId } = ctx.query
let { appId, includeRows } = ctx.query
const appName = decodeURI(ctx.query.appname)
includeRows = includeRows === "true"
const backupIdentifier = `${appName}-export-${new Date().getTime()}.txt`
ctx.attachment(backupIdentifier)
ctx.body = await streamBackup(appId)
ctx.body = await streamBackup(appId, includeRows)
}

View File

@ -72,6 +72,7 @@ exports.isDevAppID = isDevAppID
exports.isProdAppID = isProdAppID
exports.USER_METDATA_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
exports.LINK_USER_METADATA_PREFIX = `${DocumentTypes.LINK}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
exports.TABLE_ROW_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${DocumentTypes.TABLE}`
exports.ViewNames = ViewNames
exports.InternalTables = InternalTables
exports.DocumentTypes = DocumentTypes

View File

@ -21,6 +21,7 @@ const env = require("../../environment")
const {
USER_METDATA_PREFIX,
LINK_USER_METADATA_PREFIX,
TABLE_ROW_PREFIX,
} = require("../../db/utils")
const MemoryStream = require("memorystream")
const { getAppId } = require("@budibase/backend-core/context")
@ -109,6 +110,23 @@ exports.apiFileReturn = contents => {
return fs.createReadStream(path)
}
exports.defineFilter = includeRows => {
if (includeRows) {
return doc =>
!(
doc._id.includes(USER_METDATA_PREFIX) ||
doc._id.includes(LINK_USER_METADATA_PREFIX)
)
} else if (!includeRows) {
return doc =>
!(
doc._id.includes(USER_METDATA_PREFIX) ||
doc._id.includes(LINK_USER_METADATA_PREFIX) ||
doc._id.includes(TABLE_ROW_PREFIX)
)
}
}
/**
* Local utility to back up the database state for an app, excluding global user
* data or user relationships.
@ -116,14 +134,10 @@ exports.apiFileReturn = contents => {
* @param {object} config Config to send to export DB
* @returns {*} either a string or a stream of the backup
*/
const backupAppData = async (appId, config) => {
const backupAppData = async (appId, config, noRows) => {
return await exports.exportDB(appId, {
...config,
filter: doc =>
!(
doc._id.includes(USER_METDATA_PREFIX) ||
doc._id.includes(LINK_USER_METADATA_PREFIX)
),
filter: exports.defineFilter(noRows),
})
}
@ -142,8 +156,8 @@ exports.performBackup = async (appId, backupName) => {
* @param {string} appId The ID of the app which is to be backed up.
* @returns {*} a readable stream of the backup which is written in real time
*/
exports.streamBackup = async appId => {
return await backupAppData(appId, { stream: true })
exports.streamBackup = async (appId, includeRows) => {
return await backupAppData(appId, { stream: true }, includeRows)
}
/**