Merge pull request #7450 from Budibase/cheeks-fixes
App navigation and screen migration for imports and templates
This commit is contained in:
commit
512d225389
|
@ -19,7 +19,6 @@ import {
|
|||
makeComponentUnique,
|
||||
} from "../componentUtils"
|
||||
import { Helpers } from "@budibase/bbui"
|
||||
import { DefaultAppTheme, LAYOUT_NAMES } from "../../constants"
|
||||
import { Utils } from "@budibase/frontend-core"
|
||||
|
||||
const INITIAL_FRONTEND_STATE = {
|
||||
|
@ -125,35 +124,6 @@ export const getFrontendStore = () => {
|
|||
await integrations.init()
|
||||
await queries.init()
|
||||
await tables.init()
|
||||
|
||||
// Add navigation settings to old apps
|
||||
if (!application.navigation) {
|
||||
const layout = layouts.find(x => x._id === LAYOUT_NAMES.MASTER.PRIVATE)
|
||||
const customTheme = application.customTheme
|
||||
let navigationSettings = {
|
||||
navigation: "Top",
|
||||
title: application.name,
|
||||
navWidth: "Large",
|
||||
navBackground:
|
||||
customTheme?.navBackground || DefaultAppTheme.navBackground,
|
||||
navTextColor:
|
||||
customTheme?.navTextColor || DefaultAppTheme.navTextColor,
|
||||
}
|
||||
if (layout) {
|
||||
navigationSettings.hideLogo = layout.props.hideLogo
|
||||
navigationSettings.hideTitle = layout.props.hideTitle
|
||||
navigationSettings.title = layout.props.title || application.name
|
||||
navigationSettings.logoUrl = layout.props.logoUrl
|
||||
navigationSettings.links = layout.props.links
|
||||
navigationSettings.navigation = layout.props.navigation || "Top"
|
||||
navigationSettings.sticky = layout.props.sticky
|
||||
navigationSettings.navWidth = layout.props.width || "Large"
|
||||
if (navigationSettings.navigation === "None") {
|
||||
navigationSettings.navigation = "Top"
|
||||
}
|
||||
}
|
||||
await store.actions.navigation.save(navigationSettings)
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
save: async theme => {
|
||||
|
|
|
@ -47,7 +47,14 @@ import { checkAppMetadata } from "../../automations/logging"
|
|||
import { getUniqueRows } from "../../utilities/usageQuota/rows"
|
||||
import { quotas } from "@budibase/pro"
|
||||
import { errors, events, migrations } from "@budibase/backend-core"
|
||||
import { App, MigrationType } from "@budibase/types"
|
||||
import {
|
||||
App,
|
||||
Layout,
|
||||
Screen,
|
||||
MigrationType,
|
||||
AppNavigation,
|
||||
} from "@budibase/types"
|
||||
import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts"
|
||||
|
||||
const URL_REGEX_SLASH = /\/|\\/g
|
||||
|
||||
|
@ -243,27 +250,19 @@ const performAppCreate = async (ctx: any) => {
|
|||
}
|
||||
const instance = await createInstance(instanceConfig)
|
||||
const appId = instance._id
|
||||
|
||||
const db = context.getAppDB()
|
||||
let _rev
|
||||
try {
|
||||
// if template there will be an existing doc
|
||||
const existing = await db.get(DocumentType.APP_METADATA)
|
||||
_rev = existing._rev
|
||||
} catch (err) {
|
||||
// nothing to do
|
||||
}
|
||||
const newApplication: App = {
|
||||
|
||||
let newApplication: App = {
|
||||
_id: DocumentType.APP_METADATA,
|
||||
_rev,
|
||||
appId: instance._id,
|
||||
_rev: undefined,
|
||||
appId,
|
||||
type: "app",
|
||||
version: packageJson.version,
|
||||
componentLibraries: ["@budibase/standard-components"],
|
||||
name: name,
|
||||
url: url,
|
||||
template: ctx.request.body.template,
|
||||
instance: instance,
|
||||
template: templateKey,
|
||||
instance,
|
||||
tenantId: getTenantId(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
createdAt: new Date().toISOString(),
|
||||
|
@ -285,6 +284,36 @@ const performAppCreate = async (ctx: any) => {
|
|||
buttonBorderRadius: "16px",
|
||||
},
|
||||
}
|
||||
|
||||
// If we used a template or imported an app there will be an existing doc.
|
||||
// Fetch and migrate some metadata from the existing app.
|
||||
try {
|
||||
const existing: App = await db.get(DocumentType.APP_METADATA)
|
||||
const keys: (keyof App)[] = [
|
||||
"_rev",
|
||||
"navigation",
|
||||
"theme",
|
||||
"customTheme",
|
||||
"icon",
|
||||
]
|
||||
keys.forEach(key => {
|
||||
if (existing[key]) {
|
||||
// @ts-ignore
|
||||
newApplication[key] = existing[key]
|
||||
}
|
||||
})
|
||||
|
||||
// Migrate navigation settings and screens if required
|
||||
if (existing && !existing.navigation) {
|
||||
const navigation = await migrateAppNavigation()
|
||||
if (navigation) {
|
||||
newApplication.navigation = navigation
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
const response = await db.put(newApplication, { force: true })
|
||||
newApplication._rev = response.rev
|
||||
|
||||
|
@ -567,3 +596,55 @@ const updateAppPackage = async (appPackage: any, appId: any) => {
|
|||
return newAppPackage
|
||||
})
|
||||
}
|
||||
|
||||
const migrateAppNavigation = async () => {
|
||||
const db = context.getAppDB()
|
||||
const existing: App = await db.get(DocumentType.APP_METADATA)
|
||||
const layouts: Layout[] = await getLayouts()
|
||||
const screens: Screen[] = await getScreens()
|
||||
|
||||
// Migrate all screens, removing custom layouts
|
||||
for (let screen of screens) {
|
||||
if (!screen.layoutId) {
|
||||
return
|
||||
}
|
||||
const layout = layouts.find(layout => layout._id === screen.layoutId)
|
||||
screen.layoutId = undefined
|
||||
screen.showNavigation = layout?.props.navigation !== "None"
|
||||
screen.width = layout?.props.width || "Large"
|
||||
await db.put(screen)
|
||||
}
|
||||
|
||||
// Migrate layout navigation settings
|
||||
const { name, customTheme } = existing
|
||||
const layout = layouts?.find(
|
||||
(layout: Layout) => layout._id === BASE_LAYOUT_PROP_IDS.PRIVATE
|
||||
)
|
||||
if (layout) {
|
||||
let navigationSettings: any = {
|
||||
navigation: "Top",
|
||||
title: name,
|
||||
navWidth: "Large",
|
||||
navBackground:
|
||||
customTheme?.navBackground || "var(--spectrum-global-color-gray-50)",
|
||||
navTextColor:
|
||||
customTheme?.navTextColor || "var(--spectrum-global-color-gray-800)",
|
||||
}
|
||||
if (layout) {
|
||||
navigationSettings.hideLogo = layout.props.hideLogo
|
||||
navigationSettings.hideTitle = layout.props.hideTitle
|
||||
navigationSettings.title = layout.props.title || name
|
||||
navigationSettings.logoUrl = layout.props.logoUrl
|
||||
navigationSettings.links = layout.props.links
|
||||
navigationSettings.navigation = layout.props.navigation || "Top"
|
||||
navigationSettings.sticky = layout.props.sticky
|
||||
navigationSettings.navWidth = layout.props.width || "Large"
|
||||
if (navigationSettings.navigation === "None") {
|
||||
navigationSettings.navigation = "Top"
|
||||
}
|
||||
}
|
||||
return navigationSettings
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ const {
|
|||
checkBuilderEndpoint,
|
||||
} = require("./utilities/TestFunctions")
|
||||
const setup = require("./utilities")
|
||||
const { basicScreen, basicLayout } = setup.structures
|
||||
const { AppStatus } = require("../../../db/utils")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
|
||||
|
@ -81,6 +82,31 @@ describe("/applications", () => {
|
|||
body: { name: "My App" },
|
||||
})
|
||||
})
|
||||
|
||||
it("migrates navigation settings from old apps", async () => {
|
||||
const res = await request
|
||||
.post("/api/applications")
|
||||
.field("name", "Old App")
|
||||
.field("useTemplate", "true")
|
||||
.set(config.defaultHeaders())
|
||||
.attach("templateFile", "src/api/routes/tests/data/old-app.txt")
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200)
|
||||
expect(res.body._id).toBeDefined()
|
||||
expect(res.body.navigation).toBeDefined()
|
||||
expect(res.body.navigation.hideLogo).toBe(true)
|
||||
expect(res.body.navigation.title).toBe("Custom Title")
|
||||
expect(res.body.navigation.hideLogo).toBe(true)
|
||||
expect(res.body.navigation.navigation).toBe("Left")
|
||||
expect(res.body.navigation.navBackground).toBe(
|
||||
"var(--spectrum-global-color-blue-600)"
|
||||
)
|
||||
expect(res.body.navigation.navTextColor).toBe(
|
||||
"var(--spectrum-global-color-gray-50)"
|
||||
)
|
||||
expect(events.app.created).toBeCalledTimes(1)
|
||||
expect(events.app.fileImported).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe("fetch", () => {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -14,14 +14,11 @@ export interface App extends Document {
|
|||
tenantId: string
|
||||
status: string
|
||||
theme?: string
|
||||
customTheme?: {
|
||||
buttonBorderRadius?: string
|
||||
primaryColor?: string
|
||||
primaryColorHover?: string
|
||||
}
|
||||
customTheme?: AppCustomTheme
|
||||
revertableVersion?: string
|
||||
navigation?: AppNavigation
|
||||
automationErrors?: AppMetadataErrors
|
||||
icon?: AppIcon
|
||||
}
|
||||
|
||||
export interface AppInstance {
|
||||
|
@ -47,3 +44,18 @@ export interface AppNavigationLink {
|
|||
id?: string
|
||||
roleId?: string
|
||||
}
|
||||
|
||||
export interface AppCustomTheme {
|
||||
buttonBorderRadius?: string
|
||||
primaryColor?: string
|
||||
primaryColorHover?: string
|
||||
|
||||
// Used to exist before new design UI
|
||||
navTextColor?: string
|
||||
navBackground?: string
|
||||
}
|
||||
|
||||
export interface AppIcon {
|
||||
name: string
|
||||
color: string
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { Document } from "../document"
|
||||
|
||||
export interface Layout extends Document {}
|
||||
export interface Layout extends Document {
|
||||
props: any
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Document } from "../document"
|
||||
|
||||
export interface Screen extends Document {
|
||||
layoutId: string
|
||||
layoutId?: string
|
||||
showNavigation?: boolean
|
||||
width?: string
|
||||
routing: {
|
||||
|
|
|
@ -2,12 +2,12 @@ import { BaseEvent } from "./event"
|
|||
|
||||
export interface ScreenCreatedEvent extends BaseEvent {
|
||||
screenId: string
|
||||
layoutId: string
|
||||
layoutId?: string
|
||||
roleId: string
|
||||
}
|
||||
|
||||
export interface ScreenDeletedEvent extends BaseEvent {
|
||||
screenId: string
|
||||
layoutId: string
|
||||
layoutId?: string
|
||||
roleId: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue