Merge pull request #12060 from Budibase/fix/12046-nav-links-overwrite-app
App overwrite - take new apps navigation
This commit is contained in:
commit
64f4701b57
|
@ -54,6 +54,7 @@
|
||||||
label="App export"
|
label="App export"
|
||||||
on:change={e => {
|
on:change={e => {
|
||||||
file = e.detail?.[0]
|
file = e.detail?.[0]
|
||||||
|
encrypted = file?.name?.endsWith(".enc.tar.gz")
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Toggle text="Encrypted" bind:value={encrypted} />
|
<Toggle text="Encrypted" bind:value={encrypted} />
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
import ExportAppModal from "components/start/ExportAppModal.svelte"
|
||||||
import ImportAppModal from "components/start/ImportAppModal.svelte"
|
import ImportAppModal from "components/start/ImportAppModal.svelte"
|
||||||
|
|
||||||
$: filteredApps = $apps.filter(app => app.devId == $store.appId)
|
$: filteredApps = $apps.filter(app => app.devId === $store.appId)
|
||||||
$: app = filteredApps.length ? filteredApps[0] : {}
|
$: app = filteredApps.length ? filteredApps[0] : {}
|
||||||
$: appDeployed = app?.status === AppStatus.DEPLOYED
|
$: appDeployed = app?.status === AppStatus.DEPLOYED
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,10 @@ describe("/applications/:appId/import", () => {
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.message).toBe("app updated")
|
const appPackage = await config.api.application.get(appId!)
|
||||||
|
expect(appPackage.navigation?.links?.length).toBe(2)
|
||||||
|
expect(expect(appPackage.navigation?.links?.[0].url).toBe("/blank"))
|
||||||
|
expect(expect(appPackage.navigation?.links?.[1].url).toBe("/derp"))
|
||||||
const screens = await config.api.screen.list()
|
const screens = await config.api.screen.list()
|
||||||
expect(screens.length).toBe(2)
|
expect(screens.length).toBe(2)
|
||||||
expect(screens[0].routing.route).toBe("/derp")
|
expect(screens[0].routing.route).toBe("/derp")
|
||||||
|
|
|
@ -4,6 +4,8 @@ import {
|
||||||
Document,
|
Document,
|
||||||
Database,
|
Database,
|
||||||
RowValue,
|
RowValue,
|
||||||
|
DocumentType,
|
||||||
|
App,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import backups from "../backups"
|
import backups from "../backups"
|
||||||
|
|
||||||
|
@ -12,9 +14,39 @@ export type FileAttributes = {
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getNewAppMetadata(
|
||||||
|
tempDb: Database,
|
||||||
|
appDb: Database
|
||||||
|
): Promise<App> {
|
||||||
|
// static doc denoting app information
|
||||||
|
const docId = DocumentType.APP_METADATA
|
||||||
|
try {
|
||||||
|
const [tempMetadata, appMetadata] = await Promise.all([
|
||||||
|
tempDb.get<App>(docId),
|
||||||
|
appDb.get<App>(docId),
|
||||||
|
])
|
||||||
|
return {
|
||||||
|
...appMetadata,
|
||||||
|
automationErrors: undefined,
|
||||||
|
theme: tempMetadata.theme,
|
||||||
|
customTheme: tempMetadata.customTheme,
|
||||||
|
features: tempMetadata.features,
|
||||||
|
icon: tempMetadata.icon,
|
||||||
|
navigation: tempMetadata.navigation,
|
||||||
|
type: tempMetadata.type,
|
||||||
|
version: tempMetadata.version,
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to retrieve app metadata for import - ${err.message}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function mergeUpdateAndDeleteDocuments(
|
function mergeUpdateAndDeleteDocuments(
|
||||||
updateDocs: Document[],
|
updateDocs: Document[],
|
||||||
deleteDocs: Document[]
|
deleteDocs: Document[],
|
||||||
|
metadata: App
|
||||||
) {
|
) {
|
||||||
// compress the documents to create and to delete (if same ID, then just update the rev)
|
// compress the documents to create and to delete (if same ID, then just update the rev)
|
||||||
const finalToDelete = []
|
const finalToDelete = []
|
||||||
|
@ -26,7 +58,7 @@ function mergeUpdateAndDeleteDocuments(
|
||||||
finalToDelete.push(deleteDoc)
|
finalToDelete.push(deleteDoc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [...updateDocs, ...finalToDelete]
|
return [...updateDocs, ...finalToDelete, metadata]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeImportableDocuments(db: Database) {
|
async function removeImportableDocuments(db: Database) {
|
||||||
|
@ -90,12 +122,15 @@ export async function updateWithExport(
|
||||||
await backups.importApp(devId, tempDb, template, {
|
await backups.importApp(devId, tempDb, template, {
|
||||||
importObjStoreContents: false,
|
importObjStoreContents: false,
|
||||||
})
|
})
|
||||||
|
const newMetadata = await getNewAppMetadata(tempDb, appDb)
|
||||||
// get the documents to copy
|
// get the documents to copy
|
||||||
const toUpdate = await getImportableDocuments(tempDb)
|
const toUpdate = await getImportableDocuments(tempDb)
|
||||||
// clear out the old documents
|
// clear out the old documents
|
||||||
const toDelete = await removeImportableDocuments(appDb)
|
const toDelete = await removeImportableDocuments(appDb)
|
||||||
// now bulk update documents - add new ones, delete old ones and update common ones
|
// now bulk update documents - add new ones, delete old ones and update common ones
|
||||||
await appDb.bulkDocs(mergeUpdateAndDeleteDocuments(toUpdate, toDelete))
|
await appDb.bulkDocs(
|
||||||
|
mergeUpdateAndDeleteDocuments(toUpdate, toDelete, newMetadata)
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
await tempDb.destroy()
|
await tempDb.destroy()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { App } from "@budibase/types"
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import { TestAPI } from "./base"
|
||||||
|
|
||||||
|
export class ApplicationAPI extends TestAPI {
|
||||||
|
constructor(config: TestConfiguration) {
|
||||||
|
super(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
get = async (appId: string): Promise<App> => {
|
||||||
|
const result = await this.request
|
||||||
|
.get(`/api/applications/${appId}/appPackage`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
return result.body.application as App
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import { ViewV2API } from "./viewV2"
|
||||||
import { DatasourceAPI } from "./datasource"
|
import { DatasourceAPI } from "./datasource"
|
||||||
import { LegacyViewAPI } from "./legacyView"
|
import { LegacyViewAPI } from "./legacyView"
|
||||||
import { ScreenAPI } from "./screen"
|
import { ScreenAPI } from "./screen"
|
||||||
|
import { ApplicationAPI } from "./application"
|
||||||
|
|
||||||
export default class API {
|
export default class API {
|
||||||
table: TableAPI
|
table: TableAPI
|
||||||
|
@ -15,6 +16,7 @@ export default class API {
|
||||||
permission: PermissionAPI
|
permission: PermissionAPI
|
||||||
datasource: DatasourceAPI
|
datasource: DatasourceAPI
|
||||||
screen: ScreenAPI
|
screen: ScreenAPI
|
||||||
|
application: ApplicationAPI
|
||||||
|
|
||||||
constructor(config: TestConfiguration) {
|
constructor(config: TestConfiguration) {
|
||||||
this.table = new TableAPI(config)
|
this.table = new TableAPI(config)
|
||||||
|
@ -24,5 +26,6 @@ export default class API {
|
||||||
this.permission = new PermissionAPI(config)
|
this.permission = new PermissionAPI(config)
|
||||||
this.datasource = new DatasourceAPI(config)
|
this.datasource = new DatasourceAPI(config)
|
||||||
this.screen = new ScreenAPI(config)
|
this.screen = new ScreenAPI(config)
|
||||||
|
this.application = new ApplicationAPI(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue