Merge pull request #6059 from Budibase/feat/dont-export-app-rows

Allow export of app without rows
This commit is contained in:
Peter Clement 2022-06-06 16:31:21 +01:00 committed by GitHub
commit 5bd5d7df1b
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 excludeRows = false
const exportApp = () => {
const id = app.deployed ? app.prodId : app.devId
const appName = encodeURIComponent(app.name)
window.location = `/api/backups/export?appId=${id}&appname=${appName}&excludeRows=${excludeRows}`
}
</script>
<ModalContent title={"Export"} confirmText={"Export"} onConfirm={exportApp}>
<Toggle text="Exclude Rows" bind:value={excludeRows} />
</ModalContent>

View File

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

View File

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

View File

@ -74,6 +74,7 @@ exports.isDevAppID = isDevAppID
exports.isProdAppID = isProdAppID exports.isProdAppID = isProdAppID
exports.USER_METDATA_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}` exports.USER_METDATA_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
exports.LINK_USER_METADATA_PREFIX = `${DocumentTypes.LINK}${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.ViewNames = ViewNames
exports.InternalTables = InternalTables exports.InternalTables = InternalTables
exports.DocumentTypes = DocumentTypes exports.DocumentTypes = DocumentTypes

View File

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