diff --git a/hosting/kubernetes/envoy/envoy.yaml b/hosting/kubernetes/envoy/envoy.yaml index 4bf751b3a3..25a774dc7e 100644 --- a/hosting/kubernetes/envoy/envoy.yaml +++ b/hosting/kubernetes/envoy/envoy.yaml @@ -50,6 +50,11 @@ static_resources: route: cluster: app-service + - match: { path: "/api/deploy" } + route: + timeout: 60s + cluster: app-service + # special case for when API requests are made, can just forward, not to minio - match: { prefix: "/api/" } route: diff --git a/lerna.json b/lerna.json index 07435f204d..370edc641d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.148", + "version": "0.9.149-alpha.3", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 3df577ca58..3596ec7800 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "multi:disable": "lerna run multi:disable", "selfhost:enable": "lerna run selfhost:enable", "selfhost:disable": "lerna run selfhost:disable", + "localdomain:enable": "lerna run localdomain:enable", + "localdomain:disable": "lerna run localdomain:disable", "postinstall": "husky install" } } diff --git a/packages/auth/package.json b/packages/auth/package.json index 3a392a0d57..0a5cfdc4d2 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.148", + "version": "0.9.149-alpha.3", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 7cf6ce0a83..53f3896a3c 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.148", + "version": "0.9.149-alpha.3", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/bbui/src/Form/Core/TextField.svelte b/packages/bbui/src/Form/Core/TextField.svelte index 926c3eda11..37989a291e 100644 --- a/packages/bbui/src/Form/Core/TextField.svelte +++ b/packages/bbui/src/Form/Core/TextField.svelte @@ -90,6 +90,7 @@ on:input={onInput} on:keyup={updateValueOnEnter} {type} + inputmode={type === "number" ? "decimal" : "text"} class="spectrum-Textfield-input" /> diff --git a/packages/builder/cypress/integration/createTable.spec.js b/packages/builder/cypress/integration/createTable.spec.js index faaae3f8a3..876894e5aa 100644 --- a/packages/builder/cypress/integration/createTable.spec.js +++ b/packages/builder/cypress/integration/createTable.spec.js @@ -24,9 +24,7 @@ context("Create a Table", () => { it("updates a column on the table", () => { cy.get(".title").click() cy.get(".spectrum-Table-editIcon > use").click() - cy.get("input") - .eq(1) - .type("updated", { force: true }) + cy.get("input").eq(1).type("updated", { force: true }) // Unset table display column cy.get(".spectrum-Switch-input").eq(1).click() cy.contains("Save Column").click() @@ -45,9 +43,7 @@ context("Create a Table", () => { it("deletes a row", () => { cy.get(".spectrum-Checkbox-input").check({ force: true }) cy.contains("Delete 1 row(s)").click() - cy.get(".spectrum-Modal") - .contains("Delete") - .click() + cy.get(".spectrum-Modal").contains("Delete").click() cy.contains("RoverUpdated").should("not.exist") }) @@ -56,15 +52,18 @@ context("Create a Table", () => { cy.get(".spectrum-Table-editIcon > use").click() cy.contains("Delete").click() cy.wait(50) - cy.contains("Delete Column") - .click() + cy.contains("Delete Column").click() cy.contains("nameupdated").should("not.exist") }) it("deletes a table", () => { - cy.get(".actions > :nth-child(1) > .icon > .spectrum-Icon > use") - .eq(1) - .click({ force: true }) + cy.get(".nav-item") + .contains("dog") + .parents(".nav-item") + .first() + .within(() => { + cy.get(".actions .spectrum-Icon").click({ force: true }) + }) cy.get(".spectrum-Menu > :nth-child(2)").click() cy.contains("Delete Table").click() cy.contains("dog").should("not.exist") diff --git a/packages/builder/cypress/integration/createView.spec.js b/packages/builder/cypress/integration/createView.spec.js index 3aef927e8d..62d0740a39 100644 --- a/packages/builder/cypress/integration/createView.spec.js +++ b/packages/builder/cypress/integration/createView.spec.js @@ -28,11 +28,7 @@ context("Create a View", () => { const headers = Array.from($headers).map(header => header.textContent.trim() ) - expect(removeSpacing(headers)).to.deep.eq([ - "group", - "age", - "rating", - ]) + expect(removeSpacing(headers)).to.deep.eq(["group", "age", "rating"]) }) }) @@ -57,11 +53,12 @@ context("Create a View", () => { }) it("creates a stats calculation view based on age", () => { + cy.wait(1000) cy.contains("Calculate").click() cy.get(".modal-inner-wrapper").within(() => { cy.get(".spectrum-Picker-label").eq(0).click() cy.contains("Statistics").click() - + cy.get(".spectrum-Picker-label").eq(1).click() cy.contains("age").click({ force: true }) @@ -104,20 +101,20 @@ context("Create a View", () => { cy.get(".spectrum-Table-cell").then($values => { let values = Array.from($values).map(header => header.textContent.trim()) expect(values).to.deep.eq([ - "Students", - "70", - "20", - "25", - "3", - "1650", - "23.333333333333332", - "Teachers", - "85", - "36", - "49", - "2", - "3697", - "42.5", + "Students", + "70", + "20", + "25", + "3", + "1650", + "23.333333333333332", + "Teachers", + "85", + "36", + "49", + "2", + "3697", + "42.5", ]) }) }) diff --git a/packages/builder/package.json b/packages/builder/package.json index edb59cedb7..1e255b5454 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.148", + "version": "0.9.149-alpha.3", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.148", - "@budibase/client": "^0.9.148", + "@budibase/bbui": "^0.9.149-alpha.3", + "@budibase/client": "^0.9.149-alpha.3", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.148", + "@budibase/string-templates": "^0.9.149-alpha.3", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 0858b29bcb..dc1e40e517 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -1,12 +1,12 @@ import { cloneDeep } from "lodash/fp" import { get } from "svelte/store" import { + findAllMatchingComponents, findComponent, findComponentPath, - findAllMatchingComponents, } from "./storeUtils" import { store } from "builderStore" -import { tables as tablesStore, queries as queriesStores } from "stores/backend" +import { queries as queriesStores, tables as tablesStore } from "stores/backend" import { makePropSafe } from "@budibase/string-templates" import { TableNames } from "../constants" @@ -422,6 +422,10 @@ function shouldReplaceBinding(currentValue, from, convertTo) { return !invalids.find(invalid => noSpaces?.includes(invalid)) } +function replaceBetween(string, start, end, replacement) { + return string.substring(0, start) + replacement + string.substring(end) +} + /** * utility function for the readableToRuntimeBinding and runtimeToReadableBinding. */ @@ -431,6 +435,7 @@ function bindingReplacement(bindableProperties, textWithBindings, convertTo) { if (typeof textWithBindings !== "string") { return textWithBindings } + // work from longest to shortest const convertFromProps = bindableProperties .map(el => el[convertFrom]) .sort((a, b) => { @@ -440,12 +445,29 @@ function bindingReplacement(bindableProperties, textWithBindings, convertTo) { let result = textWithBindings for (let boundValue of boundValues) { let newBoundValue = boundValue + // we use a search string, where any time we replace something we blank it out + // in the search, working from longest to shortest so always use best match first + let searchString = newBoundValue for (let from of convertFromProps) { if (shouldReplaceBinding(newBoundValue, from, convertTo)) { const binding = bindableProperties.find(el => el[convertFrom] === from) - while (newBoundValue.includes(from)) { - newBoundValue = newBoundValue.replace(from, binding[convertTo]) - } + let idx + do { + // see if any instances of this binding exist in the search string + idx = searchString.indexOf(from) + if (idx !== -1) { + let end = idx + from.length, + searchReplace = Array(binding[convertTo].length).join("*") + // blank out parts of the search string + searchString = replaceBetween(searchString, idx, end, searchReplace) + newBoundValue = replaceBetween( + newBoundValue, + idx, + end, + binding[convertTo] + ) + } + } while (idx !== -1) } } result = result.replace(boundValue, newBoundValue) diff --git a/packages/builder/src/components/deploy/DeployModal.svelte b/packages/builder/src/components/deploy/DeployModal.svelte index 3dcf0c27b1..33fe8d5321 100644 --- a/packages/builder/src/components/deploy/DeployModal.svelte +++ b/packages/builder/src/components/deploy/DeployModal.svelte @@ -1,21 +1,10 @@ diff --git a/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte b/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte index c5c85fad46..ac70fb9b29 100644 --- a/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte +++ b/packages/builder/src/components/design/AppPreview/ThemeEditor.svelte @@ -62,7 +62,7 @@ diff --git a/packages/builder/src/components/upgrade/UpgradeModal.svelte b/packages/builder/src/components/upgrade/UpgradeModal.svelte index 570dcc06a1..a8702ee3eb 100644 --- a/packages/builder/src/components/upgrade/UpgradeModal.svelte +++ b/packages/builder/src/components/upgrade/UpgradeModal.svelte @@ -21,12 +21,12 @@ Upgrade to Budibase self-hosting for free, and get SSO, unlimited apps, - and more - and it only takes a few minutes!Self-host budibase for free, and get SSO, unlimited apps, and more - and + it only takes a few minutes! diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index 338322b785..625071c07e 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -4,9 +4,6 @@ import { onMount } from "svelte" let loaded = false - // don't react to these - let cloud = $admin.cloud - let shouldRedirect = !cloud || $admin.disableAccountPortal $: multiTenancyEnabled = $admin.multiTenancy $: hasAdminUser = $admin?.checklist?.adminUser?.checked @@ -14,17 +11,33 @@ $: cloud = $admin.cloud $: user = $auth.user - const validateTenantId = async () => { - // set the tenant from the url in the cloud - const tenantId = window.location.host.split(".")[0] + $: useAccountPortal = cloud && !$admin.disableAccountPortal - if (!tenantId.includes("localhost:")) { - // user doesn't have permission to access this tenant - kick them out - if (user && user.tenantId !== tenantId) { - await auth.logout() - await auth.setOrganisation(null) + const validateTenantId = async () => { + const host = window.location.host + if (host.includes("localhost:")) { + // ignore local dev + return + } + + if (user && user.tenantId) { + let urlTenantId + const hostParts = host.split(".") + + // only run validation when we know we are in a tenant url + // not when we visit the root budibase.app domain + // e.g. ['tenant', 'budibase', 'app'] vs ['budibase', 'app'] + if (hostParts.length > 2) { + urlTenantId = hostParts[0] } else { - await auth.setOrganisation(tenantId) + // no tenant in the url - send to account portal to fix this + window.location.href = $admin.accountPortalUrl + return + } + + if (user.tenantId !== urlTenantId) { + // user should not be here - play it safe and log them out + await auth.logout() } } } @@ -33,7 +46,7 @@ await auth.checkAuth() await admin.init() - if (cloud && multiTenancyEnabled) { + if (useAccountPortal && multiTenancyEnabled) { await validateTenantId() } @@ -41,12 +54,11 @@ }) $: { - // We should never see the org or admin user creation screens in the cloud const apiReady = $admin.loaded && $auth.loaded // if tenant is not set go to it if ( loaded && - shouldRedirect && + !useAccountPortal && apiReady && multiTenancyEnabled && !tenantSet @@ -54,7 +66,7 @@ $redirect("./auth/org") } // Force creation of an admin user if one doesn't exist - else if (loaded && shouldRedirect && apiReady && !hasAdminUser) { + else if (loaded && !useAccountPortal && apiReady && !hasAdminUser) { $redirect("./admin") } // Redirect to log in at any time if the user isn't authenticated diff --git a/packages/builder/src/pages/builder/admin/_layout.svelte b/packages/builder/src/pages/builder/admin/_layout.svelte index 602b6a6de3..f03a7b8285 100644 --- a/packages/builder/src/pages/builder/admin/_layout.svelte +++ b/packages/builder/src/pages/builder/admin/_layout.svelte @@ -5,8 +5,11 @@ let loaded = false + $: cloud = $admin.cloud + $: useAccountPortal = cloud && !$admin.disableAccountPortal + onMount(() => { - if ($admin?.checklist?.adminUser.checked) { + if ($admin?.checklist?.adminUser.checked || useAccountPortal) { $redirect("../") } else { loaded = true diff --git a/packages/builder/src/pages/builder/auth/org.svelte b/packages/builder/src/pages/builder/auth/org.svelte index 1e6b58dbe2..5a484b6c93 100644 --- a/packages/builder/src/pages/builder/auth/org.svelte +++ b/packages/builder/src/pages/builder/auth/org.svelte @@ -9,7 +9,8 @@ let tenantId = get(auth).tenantSet ? get(auth).tenantId : "" $: multiTenancyEnabled = $admin.multiTenancy $: cloud = $admin.cloud - $: disableAccountPortal = $admin.disableAccountPortal + + $: useAccountPortal = cloud && !$admin.disableAccountPortal async function setOrg() { if (tenantId == null || tenantId === "") { @@ -27,7 +28,7 @@ onMount(async () => { await auth.checkQueryString() - if (!multiTenancyEnabled || (cloud && !disableAccountPortal)) { + if (!multiTenancyEnabled || useAccountPortal) { $goto("../") } else { admin.unload() diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index ef019f6ae1..5c2b4e9f2f 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -216,6 +216,7 @@