diff --git a/packages/client/package.json b/packages/client/package.json index 39ddb4bd49..227c7b25d4 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -37,7 +37,6 @@ "downloadjs": "1.4.7", "html5-qrcode": "^2.2.1", "leaflet": "^1.7.1", - "regexparam": "^1.3.0", "sanitize-html": "^2.7.0", "screenfull": "^6.0.1", "shortid": "^2.2.15", diff --git a/packages/client/src/api/api.js b/packages/client/src/api/api.js index 8488b702b6..d4c8faa4d2 100644 --- a/packages/client/src/api/api.js +++ b/packages/client/src/api/api.js @@ -77,4 +77,10 @@ export const API = createAPIClient({ // Log all errors to console console.warn(`[Client] HTTP ${status} on ${method}:${url}\n\t${message}`) }, + onMigrationDetected: _appId => { + if (!window.MIGRATING_APP) { + // We will force a reload, that will display the updating screen until the migration is running + window.location.reload() + } + }, }) diff --git a/packages/client/src/components/UpdatingApp.svelte b/packages/client/src/components/UpdatingApp.svelte new file mode 100644 index 0000000000..74e5500715 --- /dev/null +++ b/packages/client/src/components/UpdatingApp.svelte @@ -0,0 +1,23 @@ + + +
+ +
+ + diff --git a/packages/client/src/index.js b/packages/client/src/index.js index a3cb4206c3..f6ed23b2a9 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -1,4 +1,5 @@ import ClientApp from "./components/ClientApp.svelte" +import UpdatingApp from "./components/UpdatingApp.svelte" import { builderStore, appStore, @@ -52,6 +53,13 @@ const loadBudibase = async () => { window["##BUDIBASE_APP_EMBEDDED##"] === "true" ) + if (window.MIGRATING_APP) { + new UpdatingApp({ + target: window.document.body, + }) + return + } + // Fetch environment info if (!get(environmentStore)?.loaded) { await environmentStore.actions.fetchEnvironment() diff --git a/packages/server/nodemon.json b/packages/server/nodemon.json index 33d277dd64..5535e0772e 100644 --- a/packages/server/nodemon.json +++ b/packages/server/nodemon.json @@ -7,7 +7,7 @@ "../shared-core", "../string-templates" ], - "ext": "js,ts,json", + "ext": "js,ts,json,svelte", "ignore": ["src/**/*.spec.ts", "src/**/*.spec.js", "../*/dist/**/*"], "exec": "yarn build && node ./dist/index.js" } diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 2963546e7f..5f383e837d 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -25,8 +25,12 @@ import fs from "fs" import sdk from "../../../sdk" import * as pro from "@budibase/pro" import { App, Ctx, ProcessAttachmentResponse } from "@budibase/types" +import { + getAppMigrationVersion, + getLatestMigrationId, +} from "../../../appMigrations" -const send = require("koa-send") +import send from "koa-send" export const toggleBetaUiFeature = async function (ctx: Ctx) { const cookieName = `beta:${ctx.params.feature}` @@ -125,7 +129,26 @@ export const deleteObjects = async function (ctx: Ctx) { ) } +const requiresMigration = async (ctx: Ctx) => { + const appId = context.getAppId() + if (!appId) { + ctx.throw("AppId could not be found") + } + + const latestMigration = getLatestMigrationId() + if (!latestMigration) { + return false + } + + const latestMigrationApplied = await getAppMigrationVersion(appId) + + const requiresMigrations = latestMigrationApplied !== latestMigration + return requiresMigrations +} + export const serveApp = async function (ctx: Ctx) { + const needMigrations = await requiresMigration(ctx) + const bbHeaderEmbed = ctx.request.get("x-budibase-embed")?.toLowerCase() === "true" @@ -145,8 +168,8 @@ export const serveApp = async function (ctx: Ctx) { let appId = context.getAppId() if (!env.isJest()) { - const App = require("./templates/BudibaseApp.svelte").default const plugins = objectStore.enrichPluginURLs(appInfo.usedPlugins) + const App = require("./templates/BudibaseApp.svelte").default const { head, html, css } = App.render({ metaImage: branding?.metaImageUrl || @@ -167,6 +190,7 @@ export const serveApp = async function (ctx: Ctx) { config?.logoUrl !== "" ? objectStore.getGlobalFileUrl("settings", "logoUrl") : "", + appMigrating: needMigrations, }) const appHbs = loadHandlebarsFile(appHbsPath) ctx.body = await processString(appHbs, { @@ -273,7 +297,6 @@ export const getSignedUploadURL = async function (ctx: Ctx) { const { bucket, key } = ctx.request.body || {} if (!bucket || !key) { ctx.throw(400, "bucket and key values are required") - return } try { const s3 = new AWS.S3({ diff --git a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte index 32edb6dc7b..7819368fc0 100644 --- a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte +++ b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte @@ -8,6 +8,7 @@ export let clientLibPath export let usedPlugins + export let appMigrating @@ -110,6 +111,11 @@ + {#if appMigrating} + + {/if} diff --git a/yarn.lock b/yarn.lock index 150585ce1a..85dd6ab251 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18312,11 +18312,6 @@ regexparam@2.0.1: resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa" integrity sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw== -regexparam@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" - integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== - regexpu-core@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.1.tgz#66900860f88def39a5cb79ebd9490e84f17bcdfb"