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", + } + ) }