diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 8e235532cf..9865c94de6 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -7,6 +7,7 @@ on: branches: - master - develop + - new-design-ui pull_request: branches: - master @@ -58,3 +59,18 @@ jobs: with: install: false command: yarn test:e2e:ci + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: eu-west-1 + + - name: Upload to S3 + if: github.ref == 'refs/heads/new-design-ui' + run: | + tar -czvf new_ui.tar.gz packages/server/assets packages/server/index.html + aws s3 cp new_ui.tar.gz s3://prod-budi-app-assets/beta:design_ui/ + aws s3 cp packages/client/dist/budibase-client.js s3://prod-budi-app-assets/beta:design_ui/budibase-client.js + diff --git a/packages/backend-core/src/objectStore/index.js b/packages/backend-core/src/objectStore/index.js index 2385149f4d..75c556627a 100644 --- a/packages/backend-core/src/objectStore/index.js +++ b/packages/backend-core/src/objectStore/index.js @@ -288,6 +288,16 @@ exports.uploadDirectory = async (bucketName, localPath, bucketPath) => { await Promise.all(uploads) } +exports.downloadTarballDirect = async (url, path) => { + path = sanitizeKey(path) + const response = await fetch(url) + if (!response.ok) { + throw new Error(`unexpected response ${response.statusText}`) + } + + await streamPipeline(response.body, zlib.Unzip(), tar.extract(path)) +} + exports.downloadTarball = async (url, bucketName, path) => { bucketName = sanitizeBucket(bucketName) path = sanitizeKey(path) diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte index c94e750c29..cd19523476 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte @@ -91,7 +91,11 @@ notifications.success(`Datasource ${name} tables updated successfully.`) await tables.fetch() } catch (error) { - notifications.error("Error updating datasource schema") + notifications.error( + `Error updating datasource schema ${ + error?.message ? `: ${error.message}` : "" + }` + ) } } diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte index 4bda5c0fd3..130bc386ac 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -2,7 +2,6 @@ import { store, automationStore } from "builderStore" import { roles, flags } from "stores/backend" import { - Button, Icon, ActionGroup, Tabs, @@ -92,9 +91,8 @@
{:then _}
- - Wanna try the new UI? - + + Try the all new budibase design interface.
diff --git a/packages/frontend-core/src/api/flags.js b/packages/frontend-core/src/api/flags.js index f2dfbf115c..16adeb7b5d 100644 --- a/packages/frontend-core/src/api/flags.js +++ b/packages/frontend-core/src/api/flags.js @@ -22,9 +22,13 @@ export const buildFlagEndpoints = API => ({ }, }) }, + /** + * Allows us to experimentally toggle a beta UI feature through a cookie. + * @param value the feature to toggle + */ toggleUiFeature: async ({ value }) => { return await API.post({ - url: `/api/ui/feature/${value}`, + url: `/api/beta/${value}`, }) }, }) diff --git a/packages/server/src/api/controllers/static/index.js b/packages/server/src/api/controllers/static/index.js index bfa1daff16..d95bdd5bd8 100644 --- a/packages/server/src/api/controllers/static/index.js +++ b/packages/server/src/api/controllers/static/index.js @@ -20,6 +20,11 @@ const { setCookie, clearCookie } = require("@budibase/backend-core/utils") const AWS = require("aws-sdk") const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1" +const fs = require("fs") +const { + downloadTarballDirect, +} = require("../../../utilities/fileSystem/utilities") + async function prepareUpload({ s3Key, bucket, metadata, file }) { const response = await upload({ bucket, @@ -50,6 +55,16 @@ exports.toggleBetaUiFeature = async function (ctx) { return } + let builderPath = resolve(TOP_LEVEL_PATH, "new_design_ui") + + // // download it from S3 + if (!fs.existsSync(builderPath)) { + fs.mkdirSync(builderPath) + } + await downloadTarballDirect( + "https://cdn.budi.live/beta:design_ui/new_ui.tar.gz", + builderPath + ) setCookie(ctx, {}, cookieName) ctx.body = { @@ -58,17 +73,11 @@ exports.toggleBetaUiFeature = async function (ctx) { } exports.serveBuilder = async function (ctx) { - const newUiCookie = ctx.cookies.get("beta:design_ui") - // When user uses the builder, they should be able to switch to the new UI through a button in a banner - // When in the new UI, they should be able to switch back with a button in a banner - // Maybe use the flags abstraction - // COS - // - Users who click the button get the latest version of the new UI - // - let uiPath = "builder" - if (newUiCookie) { - uiPath = "newbuilder" - } + // Temporary: New Design UI + const designUiCookie = ctx.cookies.get("beta:design_ui") + // TODO: get this from the tmp Dir that we downloaded from MinIO + const uiPath = designUiCookie ? "new_design_ui" : "builder" + let builderPath = resolve(TOP_LEVEL_PATH, uiPath) await send(ctx, ctx.file, { root: builderPath }) } @@ -104,7 +113,7 @@ exports.serveApp = async function (ctx) { title: appInfo.name, production: env.isProd(), appId, - clientLibPath: clientLibraryPath(appId, appInfo.version), + clientLibPath: clientLibraryPath(appId, appInfo.version, ctx), }) const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`) @@ -117,13 +126,6 @@ exports.serveApp = async function (ctx) { } exports.serveClientLibrary = async function (ctx) { - const newUiCookie = ctx.cookies.get("beta:design_ui") - if (newUiCookie) { - return send(ctx, "budibase-client.js", { - root: join(TOP_LEVEL_PATH, "newbuilder"), - }) - } - return send(ctx, "budibase-client.js", { root: join(NODE_MODULES_PATH, "@budibase", "client", "dist"), }) diff --git a/packages/server/src/api/routes/static.ts b/packages/server/src/api/routes/static.ts index 775b6137f5..61cf2b1245 100644 --- a/packages/server/src/api/routes/static.ts +++ b/packages/server/src/api/routes/static.ts @@ -38,7 +38,7 @@ router // TODO: for now this builder endpoint is not authorized/secured, will need to be .get("/builder/:file*", controller.serveBuilder) .post("/api/attachments/process", authorized(BUILDER), controller.uploadFile) - .post("/api/ui/feature/:feature", controller.toggleBetaUiFeature) + .post("/api/beta/:feature", controller.toggleBetaUiFeature) .post( "/api/attachments/:tableId/upload", paramResource("tableId"), diff --git a/packages/server/src/utilities/fileSystem/utilities.js b/packages/server/src/utilities/fileSystem/utilities.js index e85f4f9c79..1c804c0142 100644 --- a/packages/server/src/utilities/fileSystem/utilities.js +++ b/packages/server/src/utilities/fileSystem/utilities.js @@ -9,6 +9,7 @@ const { deleteFolder, uploadDirectory, downloadTarball, + downloadTarballDirect, } = require("@budibase/backend-core/objectStore") /*********************************** @@ -29,4 +30,5 @@ exports.retrieveToTmp = retrieveToTmp exports.deleteFolder = deleteFolder exports.uploadDirectory = uploadDirectory exports.downloadTarball = downloadTarball +exports.downloadTarballDirect = downloadTarballDirect exports.deleteFiles = deleteFiles diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index 66005fd9cd..0fc18a1ae6 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -54,11 +54,17 @@ exports.objectStoreUrl = () => { * @return {string} The URL to be inserted into appPackage response or server rendered * app index file. */ -exports.clientLibraryPath = (appId, version) => { +exports.clientLibraryPath = (appId, version, ctx) => { if (env.isProd()) { + // TODO: remove - for beta testing UI + if (ctx && ctx.cookies.get("beta:design_ui")) { + return "https://cdn.budi.live/beta:design_ui/budibase-client.js" + } + let url = `${exports.objectStoreUrl()}/${sanitizeKey( appId )}/budibase-client.js` + // append app version to bust the cache if (version) { url += `?v=${version}`