diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js
index c33a1d653a..cea4e98dfe 100644
--- a/packages/builder/src/builderStore/store/frontend.js
+++ b/packages/builder/src/builderStore/store/frontend.js
@@ -75,6 +75,7 @@ export const getFrontendStore = () => {
appInstance: application.instance,
clientLibPath,
previousTopNavPath: {},
+ version: application.version,
}))
await hostingStore.actions.fetch()
diff --git a/packages/builder/src/components/deploy/VersionModal.svelte b/packages/builder/src/components/deploy/VersionModal.svelte
new file mode 100644
index 0000000000..4a42fac0c1
--- /dev/null
+++ b/packages/builder/src/components/deploy/VersionModal.svelte
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+ {#if updateAvailable}
+
+ This app is currently using version {$store.version}, but version
+ {clientPackage.version} is available. Updates can contain new
+ features, performance improvements and bug fixes.
+
+ Would you like to update this app?
+
+ {:else}
+
+ This app is currently using version {$store.version} which is the
+ latest version available.
+
+ {/if}
+
+
+
+
diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
index eab765b502..f3ae6e7c8e 100644
--- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
@@ -4,6 +4,7 @@
import { Icon, ActionGroup, Tabs, Tab } from "@budibase/bbui"
import DeployModal from "components/deploy/DeployModal.svelte"
import RevertModal from "components/deploy/RevertModal.svelte"
+ import VersionModal from "components/deploy/VersionModal.svelte"
import { get } from "builderStore/api"
import { isActive, goto, layout } from "@roxi/routify"
import Logo from "assets/bb-emblem.svg"
@@ -80,6 +81,7 @@
+
{
+ const url = await getAppUrlIfNotInUse(ctx)
+ const db = new CouchDB(appId)
+ const application = await db.get(DocumentTypes.APP_METADATA)
+
+ const newAppPackage = { ...application, ...appPackage, url }
+ if (appPackage._rev !== application._rev) {
+ newAppPackage._rev = application._rev
+ }
+
+ // the locked by property is attached by server but generated from
+ // Redis, shouldn't ever store it
+ if (newAppPackage.lockedBy) {
+ delete newAppPackage.lockedBy
+ }
+
+ const response = await db.put(newAppPackage)
+ console.log(response)
+
+ return response
+}
+
const createEmptyAppPackage = async (ctx, app) => {
const db = new CouchDB(app.appId)
diff --git a/packages/server/src/api/routes/application.js b/packages/server/src/api/routes/application.js
index a7209df3e9..6ffd3a4b5b 100644
--- a/packages/server/src/api/routes/application.js
+++ b/packages/server/src/api/routes/application.js
@@ -11,6 +11,11 @@ router
.get("/api/applications/:appId/appPackage", controller.fetchAppPackage)
.put("/api/applications/:appId", authorized(BUILDER), controller.update)
.post("/api/applications", authorized(BUILDER), controller.create)
+ .post(
+ "/api/applications/:appId/client/update",
+ authorized(BUILDER),
+ controller.updateClient
+ )
.delete("/api/applications/:appId", authorized(BUILDER), controller.delete)
module.exports = router
diff --git a/packages/server/src/utilities/fileSystem/index.js b/packages/server/src/utilities/fileSystem/index.js
index afacbf8cdf..c64d83dd67 100644
--- a/packages/server/src/utilities/fileSystem/index.js
+++ b/packages/server/src/utilities/fileSystem/index.js
@@ -13,7 +13,7 @@ const {
deleteFolder,
downloadTarball,
} = require("./utilities")
-const { downloadLibraries, uploadClientLibrary } = require("./newApp")
+const { uploadClientLibrary } = require("./newApp")
const download = require("download")
const env = require("../../environment")
const { homedir } = require("os")
@@ -144,7 +144,6 @@ exports.performBackup = async (appId, backupName) => {
* @return {Promise} once promise completes app resources should be ready in object store.
*/
exports.createApp = async appId => {
- await downloadLibraries(appId)
await uploadClientLibrary(appId)
}
@@ -193,8 +192,17 @@ exports.getComponentLibraryManifest = async (appId, library) => {
delete require.cache[require.resolve(path)]
return require(path)
}
- const path = join(appId, "node_modules", library, "package", filename)
- let resp = await retrieve(ObjectStoreBuckets.APPS, path)
+
+ let resp
+ try {
+ // Try to load the manifest from the new file location
+ const path = join(appId, filename)
+ resp = await retrieve(ObjectStoreBuckets.APPS, path)
+ } catch (error) {
+ // Fallback to loading it from the old location for old apps
+ const path = join(appId, "node_modules", library, "package", filename)
+ resp = await retrieve(ObjectStoreBuckets.APPS, path)
+ }
if (typeof resp !== "string") {
resp = resp.toString("utf8")
}
diff --git a/packages/server/src/utilities/fileSystem/newApp.js b/packages/server/src/utilities/fileSystem/newApp.js
index 735f0d523e..749e7a278d 100644
--- a/packages/server/src/utilities/fileSystem/newApp.js
+++ b/packages/server/src/utilities/fileSystem/newApp.js
@@ -1,36 +1,27 @@
-const packageJson = require("../../../package.json")
const { join } = require("path")
const { ObjectStoreBuckets } = require("../../constants")
-const { streamUpload, downloadTarball } = require("./utilities")
+const { streamUpload } = require("./utilities")
const fs = require("fs")
const BUCKET_NAME = ObjectStoreBuckets.APPS
-// can't really test this due to the downloading nature of it, wouldn't be a great test case
-/* istanbul ignore next */
-exports.downloadLibraries = async appId => {
- const LIBRARIES = ["standard-components"]
-
- const paths = {}
- // Need to download tarballs directly from NPM as our users may not have node on their machine
- for (let lib of LIBRARIES) {
- // download tarball
- const registryUrl = `https://registry.npmjs.org/@budibase/${lib}/-/${lib}-${packageJson.version}.tgz`
- const path = join(appId, "node_modules", "@budibase", lib)
- paths[`@budibase/${lib}`] = await downloadTarball(
- registryUrl,
- BUCKET_NAME,
- path
- )
- }
- return paths
-}
-
exports.uploadClientLibrary = async appId => {
- const sourcepath = require.resolve("@budibase/client")
- const destPath = join(appId, "budibase-client.js")
-
- await streamUpload(BUCKET_NAME, destPath, fs.createReadStream(sourcepath), {
- ContentType: "application/javascript",
- })
+ await streamUpload(
+ BUCKET_NAME,
+ join(appId, "budibase-client.js"),
+ fs.createReadStream(require.resolve("@budibase/client")),
+ {
+ ContentType: "application/javascript",
+ }
+ )
+ await streamUpload(
+ BUCKET_NAME,
+ join(appId, "manifest.json"),
+ fs.createReadStream(
+ require.resolve("@budibase/standard-components/manifest.json")
+ ),
+ {
+ ContentType: "application/javascript",
+ }
+ )
}