Fixing an issue with deleting large apps with a lot of internal table data and adding back the export modal which allows picking whether an export includes internal table rows - #7583.
This commit is contained in:
parent
2686d50523
commit
3d66e71d7d
|
@ -1,16 +1,24 @@
|
|||
<script>
|
||||
import { ModalContent, Toggle } from "@budibase/bbui"
|
||||
import { ModalContent, Toggle, Body } from "@budibase/bbui"
|
||||
|
||||
export let app
|
||||
export let published
|
||||
let excludeRows = false
|
||||
|
||||
$: title = published ? "Export published app" : "Export latest app"
|
||||
$: confirmText = published ? "Export published" : "Export latest"
|
||||
|
||||
const exportApp = () => {
|
||||
const id = app.deployed ? app.prodId : app.devId
|
||||
const id = published ? 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}>
|
||||
<ModalContent {title} {confirmText} onConfirm={exportApp}>
|
||||
<Body
|
||||
>Apps can be exported with or without data that is within internal tables -
|
||||
select this below.</Body
|
||||
>
|
||||
<Toggle text="Exclude Rows" bind:value={excludeRows} />
|
||||
</ModalContent>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import Spinner from "components/common/Spinner.svelte"
|
||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
||||
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
||||
|
||||
import { store, automationStore } from "builderStore"
|
||||
import { API } from "api"
|
||||
|
@ -33,7 +32,6 @@
|
|||
let selectedApp
|
||||
let creationModal
|
||||
let updatingModal
|
||||
let exportModal
|
||||
let creatingApp = false
|
||||
let loaded = $apps?.length || $templates?.length
|
||||
let searchTerm = ""
|
||||
|
@ -41,6 +39,9 @@
|
|||
let creatingFromTemplate = false
|
||||
let automationErrors
|
||||
let accessFilterList = null
|
||||
let welcomeHeader, welcomeBody
|
||||
let createAppButtonText
|
||||
let enrichedApps, filteredApps, lockedApps, unlocked
|
||||
|
||||
const resolveWelcomeMessage = (auth, apps) => {
|
||||
const userWelcome = auth?.user?.firstName
|
||||
|
@ -407,10 +408,6 @@
|
|||
<UpdateAppModal app={selectedApp} />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={exportModal} padding={false} width="600px">
|
||||
<ExportAppModal app={selectedApp} />
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.appTable {
|
||||
border-top: var(--border-light);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
MenuItem,
|
||||
Icon,
|
||||
Helpers,
|
||||
Modal,
|
||||
} from "@budibase/bbui"
|
||||
import OverviewTab from "../_components/OverviewTab.svelte"
|
||||
import SettingsTab from "../_components/SettingsTab.svelte"
|
||||
|
@ -29,6 +30,7 @@
|
|||
import EditableIcon from "components/common/EditableIcon.svelte"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import HistoryTab from "components/portal/overview/automation/HistoryTab.svelte"
|
||||
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
||||
import { checkIncomingDeploymentStatus } from "components/deploy/utils"
|
||||
import { onDestroy, onMount } from "svelte"
|
||||
|
||||
|
@ -38,7 +40,9 @@
|
|||
let loaded = false
|
||||
let deletionModal
|
||||
let unpublishModal
|
||||
let exportModal
|
||||
let appName = ""
|
||||
let published
|
||||
|
||||
// App
|
||||
$: filteredApps = $apps.filter(app => app.devId === application)
|
||||
|
@ -140,11 +144,9 @@
|
|||
notifications.success("App ID copied to clipboard.")
|
||||
}
|
||||
|
||||
const exportApp = (app, opts = { published: false }) => {
|
||||
const appName = encodeURIComponent(app.name)
|
||||
const id = opts?.published ? app.prodId : app.devId
|
||||
// always export the development version
|
||||
window.location = `/api/backups/export?appId=${id}&appname=${appName}`
|
||||
const exportApp = opts => {
|
||||
published = opts.published
|
||||
exportModal.show()
|
||||
}
|
||||
|
||||
const unpublishApp = app => {
|
||||
|
@ -206,6 +208,10 @@
|
|||
})
|
||||
</script>
|
||||
|
||||
<Modal bind:this={exportModal} padding={false} width="600px">
|
||||
<ExportAppModal app={selectedApp} {published} />
|
||||
</Modal>
|
||||
|
||||
<span class="overview-wrap">
|
||||
<Page wide noPadding>
|
||||
{#await promise}
|
||||
|
@ -269,14 +275,14 @@
|
|||
<Icon hoverable name="More" />
|
||||
</span>
|
||||
<MenuItem
|
||||
on:click={() => exportApp(selectedApp, { published: false })}
|
||||
on:click={() => exportApp({ published: false })}
|
||||
icon="DownloadFromCloud"
|
||||
>
|
||||
Export latest
|
||||
</MenuItem>
|
||||
{#if isPublished}
|
||||
<MenuItem
|
||||
on:click={() => exportApp(selectedApp, { published: true })}
|
||||
on:click={() => exportApp({ published: true })}
|
||||
icon="DownloadFromCloudOutline"
|
||||
>
|
||||
Export published
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
const { streamBackup } = require("../../utilities/fileSystem")
|
||||
const { events, context } = require("@budibase/backend-core")
|
||||
const { DocumentType } = require("../../db/utils")
|
||||
const { isQsTrue } = require("../../utilities")
|
||||
|
||||
exports.exportAppDump = async function (ctx) {
|
||||
let { appId, excludeRows } = ctx.query
|
||||
const appName = decodeURI(ctx.query.appname)
|
||||
excludeRows = excludeRows === "true"
|
||||
excludeRows = isQsTrue(excludeRows)
|
||||
const backupIdentifier = `${appName}-export-${new Date().getTime()}.txt`
|
||||
ctx.attachment(backupIdentifier)
|
||||
ctx.body = await streamBackup(appId, excludeRows)
|
||||
|
|
|
@ -125,13 +125,13 @@ exports.defineFilter = excludeRows => {
|
|||
* data or user relationships.
|
||||
* @param {string} appId The app to backup
|
||||
* @param {object} config Config to send to export DB
|
||||
* @param {boolean} includeRows Flag to state whether the export should include data.
|
||||
* @param {boolean} excludeRows Flag to state whether the export should include data.
|
||||
* @returns {*} either a string or a stream of the backup
|
||||
*/
|
||||
const backupAppData = async (appId, config, includeRows) => {
|
||||
const backupAppData = async (appId, config, excludeRows) => {
|
||||
return await exports.exportDB(appId, {
|
||||
...config,
|
||||
filter: exports.defineFilter(includeRows),
|
||||
filter: exports.defineFilter(excludeRows),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -148,11 +148,11 @@ exports.performBackup = async (appId, backupName) => {
|
|||
/**
|
||||
* Streams a backup of the database state for an app
|
||||
* @param {string} appId The ID of the app which is to be backed up.
|
||||
* @param {boolean} includeRows Flag to state whether the export should include data.
|
||||
* @param {boolean} excludeRows Flag to state whether the export should include data.
|
||||
* @returns {*} a readable stream of the backup which is written in real time
|
||||
*/
|
||||
exports.streamBackup = async (appId, includeRows) => {
|
||||
return await backupAppData(appId, { stream: true }, includeRows)
|
||||
exports.streamBackup = async (appId, excludeRows) => {
|
||||
return await backupAppData(appId, { stream: true }, excludeRows)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -162,3 +162,11 @@ exports.convertBookmark = bookmark => {
|
|||
}
|
||||
return bookmark
|
||||
}
|
||||
|
||||
exports.isQsTrue = param => {
|
||||
if (typeof param === "string") {
|
||||
return param.toLowerCase() === "true"
|
||||
} else {
|
||||
return param === true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,8 @@ exports.getUniqueRows = async appIds => {
|
|||
// ensure uniqueness on a per app pair basis
|
||||
// this can't be done on all rows because app import results in
|
||||
// duplicate row ids across apps
|
||||
uniqueRows = uniqueRows.concat(...new Set(appRows))
|
||||
// the array pre-concat is important to avoid stack overflow
|
||||
uniqueRows = uniqueRows.concat([...new Set(appRows)])
|
||||
}
|
||||
|
||||
return uniqueRows
|
||||
|
|
Loading…
Reference in New Issue