diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 0881d2528d..8e235532cf 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -11,6 +11,7 @@ on: branches: - master - develop + workflow_dispatch: env: BRANCH: ${{ github.event.pull_request.head.ref }} diff --git a/.github/workflows/deploy-cloud.yaml b/.github/workflows/deploy-cloud.yaml index db03165a91..a05f97f097 100644 --- a/.github/workflows/deploy-cloud.yaml +++ b/.github/workflows/deploy-cloud.yaml @@ -66,7 +66,7 @@ jobs: config-files: values.production.yaml chart-path: charts/budibase namespace: budibase - values: globals.appVersion=v${{ env.RELEASE_VERSION }} + values: globals.appVersion=v${{ env.RELEASE_VERSION }},services.couchdb.url=${{ secrets.PRODUCTION_COUCHDB_URL }},services.couchdb.password=${{ secrets.PRODUCTION_COUCHDB_PASSWORD }} name: budibase-prod - name: Discord Webhook Action diff --git a/.github/workflows/release-develop.yml b/.github/workflows/release-develop.yml index 87e4f0988a..7ee02ccdd1 100644 --- a/.github/workflows/release-develop.yml +++ b/.github/workflows/release-develop.yml @@ -14,6 +14,7 @@ on: - 'yarn.lock' - 'package.json' - 'yarn.lock' + workflow_dispatch: env: POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }} @@ -26,6 +27,11 @@ jobs: runs-on: ubuntu-latest steps: + - name: Fail if branch is not develop + if: github.ref != 'refs/heads/develop' + run: | + echo "Ref is not develop, you must run this job from develop." + exit 1 - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3b2b01316..359ad4467b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,7 @@ on: - 'yarn.lock' - 'package.json' - 'yarn.lock' + workflow_dispatch: env: POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }} @@ -27,6 +28,11 @@ jobs: runs-on: ubuntu-latest steps: + - name: Fail if branch is not master + if: github.ref != 'refs/heads/master' + run: | + echo "Ref is not master, you must run this job from master." + exit 1 - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: @@ -53,8 +59,8 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | # setup the username and email. I tend to use 'GitHub Actions Bot' with no email by default - git config user.name "Budibase Release Bot" - git config user.email "<>" + git config --global user.name "Budibase Release Bot" + git config --global user.email "<>" echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} >> .npmrc yarn release diff --git a/.github/workflows/smoke_test.yaml b/.github/workflows/smoke_test.yaml index b26d0386fc..d5a5f0b02a 100644 --- a/.github/workflows/smoke_test.yaml +++ b/.github/workflows/smoke_test.yaml @@ -31,8 +31,11 @@ jobs: continue-on-error: true uses: cypress-io/github-action@v2 with: + record: true install: false - command: yarn test:e2e:ci + command: yarn test:e2e:ci:record + env: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} # TODO: upload recordings to s3 # - name: Configure AWS Credentials @@ -46,7 +49,7 @@ jobs: uses: tsickert/discord-webhook@v4.0.0 with: webhook-url: ${{ secrets.BUDI_QA_WEBHOOK }} - content: "Smoke test run completed with ${{ steps.cypress.outcome }}. See results at ${{ steps.cypress.dashboardUrl }}" + content: "Smoke test run completed with ${{ steps.cypress.outcome }}. See results at ${{ steps.cypress.outputs.dashboardUrl }}" embed-title: ${{ steps.cypress.outcome }} embed-color: ${{ steps.cypress.outcome == 'success' && '3066993' || '15548997' }} diff --git a/charts/budibase/templates/app-service-deployment.yaml b/charts/budibase/templates/app-service-deployment.yaml index c80cfa2ecc..98a949418c 100644 --- a/charts/budibase/templates/app-service-deployment.yaml +++ b/charts/budibase/templates/app-service-deployment.yaml @@ -34,6 +34,7 @@ spec: {{ else }} value: http://{{ .Release.Name }}-svc-couchdb:{{ .Values.services.couchdb.port }} {{ end }} + {{ if .Values.services.couchdb.enabled }} - name: COUCH_DB_USER valueFrom: secretKeyRef: @@ -44,6 +45,7 @@ spec: secretKeyRef: name: {{ template "couchdb.fullname" . }} key: adminPassword + {{ end }} - name: ENABLE_ANALYTICS value: {{ .Values.globals.enableAnalytics | quote }} - name: INTERNAL_API_KEY @@ -112,6 +114,8 @@ spec: value: {{ .Values.globals.google.secret | quote }} - name: AUTOMATION_MAX_ITERATIONS value: {{ .Values.globals.automationMaxIterations | quote }} + - name: TENANT_FEATURE_FLAGS + value: {{ .Values.globals.tenantFeatureFlags | quote }} image: budibase/apps:{{ .Values.globals.appVersion }} imagePullPolicy: Always diff --git a/charts/budibase/templates/minio-data-persistentvolumeclaim.yaml b/charts/budibase/templates/minio-data-persistentvolumeclaim.yaml index 7a6e05a66a..abcf341bc5 100644 --- a/charts/budibase/templates/minio-data-persistentvolumeclaim.yaml +++ b/charts/budibase/templates/minio-data-persistentvolumeclaim.yaml @@ -12,10 +12,8 @@ spec: resources: requests: storage: {{ .Values.services.objectStore.storage }} - {{- if (eq "-" .Values.services.objectStore.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.services.objectStore.storageClass }}" + {{ if .Values.services.objectStore.storageClass }} + storageClassName: {{ .Values.services.objectStore.storageClass }} {{- end }} status: {} {{- end }} diff --git a/charts/budibase/templates/redis-data-persistentvolumeclaim.yaml b/charts/budibase/templates/redis-data-persistentvolumeclaim.yaml index 5f063dc664..6f11492b58 100644 --- a/charts/budibase/templates/redis-data-persistentvolumeclaim.yaml +++ b/charts/budibase/templates/redis-data-persistentvolumeclaim.yaml @@ -12,10 +12,8 @@ spec: resources: requests: storage: {{ .Values.services.redis.storage }} - {{- if (eq "-" .Values.services.redis.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.services.redis.storageClass }}" - {{- end }} + {{ if .Values.services.redis.storageClass }} + storageClassName: {{ .Values.services.redis.storageClass }} + {{ end }} status: {} {{- end }} diff --git a/charts/budibase/templates/worker-service-deployment.yaml b/charts/budibase/templates/worker-service-deployment.yaml index c2180aca2b..15ff05e214 100644 --- a/charts/budibase/templates/worker-service-deployment.yaml +++ b/charts/budibase/templates/worker-service-deployment.yaml @@ -29,6 +29,7 @@ spec: - env: - name: CLUSTER_PORT value: {{ .Values.services.worker.port | quote }} + {{ if .Values.services.couchdb.enabled }} - name: COUCH_DB_USER valueFrom: secretKeyRef: @@ -39,6 +40,7 @@ spec: secretKeyRef: name: {{ template "couchdb.fullname" . }} key: adminPassword + {{ end }} - name: COUCH_DB_URL {{ if .Values.services.couchdb.url }} value: {{ .Values.services.couchdb.url }} diff --git a/charts/budibase/values.yaml b/charts/budibase/values.yaml index 5ada89de6c..52ead6d076 100644 --- a/charts/budibase/values.yaml +++ b/charts/budibase/values.yaml @@ -155,7 +155,7 @@ services: ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. - storageClass: "-" + storageClass: "" objectStore: minio: true @@ -171,7 +171,7 @@ services: ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. - storageClass: "-" + storageClass: "" # Override values in couchDB subchart couchdb: @@ -215,7 +215,7 @@ couchdb: ## The CouchDB image image: repository: couchdb - tag: 3.1.0 + tag: 3.2.1 pullPolicy: IfNotPresent ## Experimental integration with Lucene-powered fulltext search diff --git a/hosting/nginx.prod.conf.hbs b/hosting/nginx.prod.conf.hbs index 7ef597051b..a127dfbd5c 100644 --- a/hosting/nginx.prod.conf.hbs +++ b/hosting/nginx.prod.conf.hbs @@ -30,7 +30,7 @@ http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; - + map $http_upgrade $connection_upgrade { default "upgrade"; } @@ -42,13 +42,13 @@ http { client_max_body_size 1000m; ignore_invalid_headers off; proxy_buffering off; - + set $csp_default "default-src 'self'"; set $csp_script "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io"; set $csp_style "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com"; set $csp_object "object-src 'none'"; set $csp_base_uri "base-uri 'self'"; - set $csp_connect "connect-src 'self' https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com"; + set $csp_connect "connect-src 'self' https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.us-east-2.amazonaws.com https://*.s3.us-east-1.amazonaws.com https://*.s3.us-west-1.amazonaws.com https://*.s3.us-west-2.amazonaws.com https://*.s3.af-south-1.amazonaws.com https://*.s3.ap-east-1.amazonaws.com https://*.s3.ap-southeast-3.amazonaws.com https://*.s3.ap-south-1.amazonaws.com https://*.s3.ap-northeast-3.amazonaws.com https://*.s3.ap-northeast-2.amazonaws.com https://*.s3.ap-southeast-1.amazonaws.com https://*.s3.ap-southeast-2.amazonaws.com https://*.s3.ap-northeast-1.amazonaws.com https://*.s3.ca-central-1.amazonaws.com https://*.s3.cn-north-1.amazonaws.com https://*.s3.cn-northwest-1.amazonaws.com https://*.s3.eu-central-1.amazonaws.com https://*.s3.eu-west-1.amazonaws.com https://*.s3.eu-west-2.amazonaws.com https://*.s3.eu-south-1.amazonaws.com https://*.s3.eu-west-3.amazonaws.com https://*.s3.eu-north-1.amazonaws.com https://*.s3.sa-east-1.amazonaws.com https://*.s3.me-south-1.amazonaws.com https://*.s3.us-gov-east-1.amazonaws.com https://*.s3.us-gov-west-1.amazonaws.com"; set $csp_font "font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com https://js.intercomcdn.com https://fonts.intercomcdn.com"; set $csp_frame "frame-src 'self' https:"; set $csp_img "img-src http: https: data: blob:"; @@ -58,7 +58,7 @@ http { error_page 502 503 504 /error.html; location = /error.html { - root /usr/share/nginx/html; + root /usr/share/nginx/html; internal; } @@ -154,4 +154,4 @@ http { gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; } -} \ No newline at end of file +} diff --git a/lerna.json b/lerna.json index 3f69ccefda..0b0dae59bb 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.0.124-alpha.0", + "version": "1.0.148-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 727104d830..fb6d9da990 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "lint:fix": "yarn run lint:fix:prettier && yarn run lint:fix:eslint", "test:e2e": "lerna run cy:test --stream", "test:e2e:ci": "lerna run cy:ci --stream", + "test:e2e:ci:record": "lerna run cy:ci:record --stream", "build:specs": "lerna run specs", "build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -", "build:docker:proxy": "docker build hosting/proxy -t proxy-service", diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index b0ff91ab98..eda57e22ef 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.0.124-alpha.0", + "version": "1.0.148-alpha.0", "description": "Budibase backend core libraries used in server and worker", "main": "src/index.js", "author": "Budibase", diff --git a/packages/backend-core/src/db/conversions.js b/packages/backend-core/src/db/conversions.js index 50d896322f..455cc712d8 100644 --- a/packages/backend-core/src/db/conversions.js +++ b/packages/backend-core/src/db/conversions.js @@ -23,24 +23,30 @@ exports.isDevApp = app => { } /** - * Convert a development app ID to a deployed app ID. + * Generates a development app ID from a real app ID. + * @returns {string} the dev app ID which can be used for dev database. */ -exports.getProdAppID = appId => { - // if dev, convert it - if (appId.startsWith(APP_DEV_PREFIX)) { - const id = appId.split(APP_DEV_PREFIX)[1] - return `${APP_PREFIX}${id}` +exports.getDevelopmentAppID = appId => { + if (!appId || appId.startsWith(APP_DEV_PREFIX)) { + return appId } - return appId + // split to take off the app_ element, then join it together incase any other app_ exist + const split = appId.split(APP_PREFIX) + split.shift() + const rest = split.join(APP_PREFIX) + return `${APP_DEV_PREFIX}${rest}` } /** - * Convert a deployed app ID to a development app ID. + * Convert a development app ID to a deployed app ID. */ -exports.getDevelopmentAppID = appId => { - if (!appId.startsWith(APP_DEV_PREFIX)) { - const id = appId.split(APP_PREFIX)[1] - return `${APP_DEV_PREFIX}${id}` +exports.getProdAppID = appId => { + if (!appId || !appId.startsWith(APP_DEV_PREFIX)) { + return appId } - return appId + // split to take off the app_dev element, then join it together incase any other app_ exist + const split = appId.split(APP_DEV_PREFIX) + split.shift() + const rest = split.join(APP_DEV_PREFIX) + return `${APP_PREFIX}${rest}` } diff --git a/packages/backend-core/src/db/index.js b/packages/backend-core/src/db/index.js index 1a29c8c2b0..7d54b881b1 100644 --- a/packages/backend-core/src/db/index.js +++ b/packages/backend-core/src/db/index.js @@ -41,7 +41,8 @@ exports.closeDB = async db => { return } try { - return db.close() + // specifically await so that if there is an error, it can be ignored + return await db.close() } catch (err) { // ignore error, already closed } diff --git a/packages/backend-core/src/db/pouch.js b/packages/backend-core/src/db/pouch.js index 722913aa67..9c1ada8d76 100644 --- a/packages/backend-core/src/db/pouch.js +++ b/packages/backend-core/src/db/pouch.js @@ -1,29 +1,19 @@ const PouchDB = require("pouchdb") const env = require("../environment") -exports.getCouchUrl = () => { - if (!env.COUCH_DB_URL) return - - // username and password already exist in URL - if (env.COUCH_DB_URL.includes("@")) { - return env.COUCH_DB_URL - } - - const [protocol, ...rest] = env.COUCH_DB_URL.split("://") - - if (!env.COUCH_DB_USERNAME || !env.COUCH_DB_PASSWORD) { - throw new Error( - "CouchDB configuration invalid. You must provide a fully qualified CouchDB url, or the COUCH_DB_USER and COUCH_DB_PASSWORD environment variables." - ) - } - - return `${protocol}://${env.COUCH_DB_USERNAME}:${env.COUCH_DB_PASSWORD}@${rest}` -} - -exports.splitCouchUrl = url => { +function getUrlInfo() { + let url = env.COUCH_DB_URL + let username, password, host const [protocol, rest] = url.split("://") - const [auth, host] = rest.split("@") - const [username, password] = auth.split(":") + if (url.includes("@")) { + const hostParts = rest.split("@") + host = hostParts[1] + const authParts = hostParts[0].split(":") + username = authParts[0] + password = authParts[1] + } else { + host = rest + } return { url: `${protocol}://${host}`, auth: { @@ -33,32 +23,51 @@ exports.splitCouchUrl = url => { } } +exports.getCouchInfo = () => { + const urlInfo = getUrlInfo() + let username + let password + if (env.COUCH_DB_USERNAME) { + // set from env + username = env.COUCH_DB_USERNAME + } else if (urlInfo.auth.username) { + // set from url + username = urlInfo.auth.username + } else if (!env.isTest()) { + throw new Error("CouchDB username not set") + } + if (env.COUCH_DB_PASSWORD) { + // set from env + password = env.COUCH_DB_PASSWORD + } else if (urlInfo.auth.password) { + // set from url + password = urlInfo.auth.password + } else if (!env.isTest()) { + throw new Error("CouchDB password not set") + } + const authCookie = Buffer.from(`${username}:${password}`).toString("base64") + return { + url: urlInfo.url, + auth: { + username: username, + password: password, + }, + cookie: `Basic ${authCookie}`, + } +} + /** * Return a constructor for PouchDB. * This should be rarely used outside of the main application config. * Exposed for exceptional cases such as in-memory views. */ exports.getPouch = (opts = {}) => { - let auth = { - username: env.COUCH_DB_USERNAME, - password: env.COUCH_DB_PASSWORD, - } - let url = exports.getCouchUrl() || "http://localhost:4005" - // need to update security settings - if (!auth.username || !auth.password || url.includes("@")) { - const split = exports.splitCouchUrl(url) - url = split.url - auth = split.auth - } - - const authCookie = Buffer.from(`${auth.username}:${auth.password}`).toString( - "base64" - ) + let { url, cookie } = exports.getCouchInfo() let POUCH_DB_DEFAULTS = { prefix: url, fetch: (url, opts) => { // use a specific authorization cookie - be very explicit about how we authenticate - opts.headers.set("Authorization", `Basic ${authCookie}`) + opts.headers.set("Authorization", cookie) return PouchDB.fetch(url, opts) }, } diff --git a/packages/backend-core/src/db/tests/utils.spec.js b/packages/backend-core/src/db/tests/utils.spec.js new file mode 100644 index 0000000000..ebef670a81 --- /dev/null +++ b/packages/backend-core/src/db/tests/utils.spec.js @@ -0,0 +1,61 @@ +const { + generateAppID, + getDevelopmentAppID, + getProdAppID, + isDevAppID, + isProdAppID, +} = require("../utils") + +function getID() { + const appId = generateAppID() + const split = appId.split("_") + const uuid = split[split.length - 1] + const devAppId = `app_dev_${uuid}` + return { appId, devAppId, split, uuid } +} + +describe("app ID manipulation", () => { + it("should be able to generate a new app ID", () => { + expect(generateAppID().startsWith("app_")).toEqual(true) + }) + + it("should be able to convert a production app ID to development", () => { + const { appId, uuid } = getID() + expect(getDevelopmentAppID(appId)).toEqual(`app_dev_${uuid}`) + }) + + it("should be able to convert a development app ID to development", () => { + const { devAppId, uuid } = getID() + expect(getDevelopmentAppID(devAppId)).toEqual(`app_dev_${uuid}`) + }) + + it("should be able to convert a development ID to a production", () => { + const { devAppId, uuid } = getID() + expect(getProdAppID(devAppId)).toEqual(`app_${uuid}`) + }) + + it("should be able to convert a production ID to production", () => { + const { appId, uuid } = getID() + expect(getProdAppID(appId)).toEqual(`app_${uuid}`) + }) + + it("should be able to confirm dev app ID is development", () => { + const { devAppId } = getID() + expect(isDevAppID(devAppId)).toEqual(true) + }) + + it("should be able to confirm prod app ID is not development", () => { + const { appId } = getID() + expect(isDevAppID(appId)).toEqual(false) + }) + + it("should be able to confirm prod app ID is prod", () => { + const { appId } = getID() + expect(isProdAppID(appId)).toEqual(true) + }) + + it("should be able to confirm dev app ID is not prod", () => { + const { devAppId } = getID() + expect(isProdAppID(devAppId)).toEqual(false) + }) +}) \ No newline at end of file diff --git a/packages/backend-core/src/db/utils.js b/packages/backend-core/src/db/utils.js index 9e2a06d065..5f7bf794c2 100644 --- a/packages/backend-core/src/db/utils.js +++ b/packages/backend-core/src/db/utils.js @@ -12,7 +12,7 @@ const { const { getTenantId, getGlobalDBName } = require("../tenancy") const fetch = require("node-fetch") const { doWithDB, allDbs } = require("./index") -const { getCouchUrl } = require("./pouch") +const { getCouchInfo } = require("./pouch") const { getAppMetadata } = require("../cache/appMetadata") const { checkSlashesInUrl } = require("../helpers") const { @@ -43,6 +43,18 @@ exports.isDevAppID = isDevAppID exports.getDevelopmentAppID = getDevelopmentAppID exports.getProdAppID = getProdAppID +/** + * Generates a new app ID. + * @returns {string} The new app ID which the app doc can be stored under. + */ +exports.generateAppID = (tenantId = null) => { + let id = APP_PREFIX + if (tenantId) { + id += `${tenantId}${SEPARATOR}` + } + return `${id}${newid()}` +} + /** * If creating DB allDocs/query params with only a single top level ID this can be used, this * is usually the case as most of our docs are top level e.g. tables, automations, users and so on. @@ -169,8 +181,14 @@ exports.getAllDbs = async (opts = { efficient: false }) => { return allDbs() } let dbs = [] - async function addDbs(url) { - const response = await fetch(checkSlashesInUrl(encodeURI(url))) + let { url, cookie } = getCouchInfo() + async function addDbs(couchUrl) { + const response = await fetch(checkSlashesInUrl(encodeURI(couchUrl)), { + method: "GET", + headers: { + Authorization: cookie, + }, + }) if (response.status === 200) { let json = await response.json() dbs = dbs.concat(json) @@ -178,7 +196,7 @@ exports.getAllDbs = async (opts = { efficient: false }) => { throw "Cannot connect to CouchDB instance" } } - let couchUrl = `${getCouchUrl()}/_all_dbs` + let couchUrl = `${url}/_all_dbs` let tenantId = getTenantId() if (!env.MULTI_TENANCY || (!efficient && tenantId === DEFAULT_TENANT_ID)) { // just get all DBs when: diff --git a/packages/backend-core/src/environment.js b/packages/backend-core/src/environment.js index 8a92e39469..f628e899ad 100644 --- a/packages/backend-core/src/environment.js +++ b/packages/backend-core/src/environment.js @@ -6,9 +6,13 @@ function isTest() { ) } +function isDev() { + return process.env.NODE_ENV !== "production" +} + module.exports = { JWT_SECRET: process.env.JWT_SECRET, - COUCH_DB_URL: process.env.COUCH_DB_URL, + COUCH_DB_URL: process.env.COUCH_DB_URL || "http://localhost:4005", COUCH_DB_USERNAME: process.env.COUCH_DB_USER, COUCH_DB_PASSWORD: process.env.COUCH_DB_PASSWORD, GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, @@ -30,8 +34,15 @@ module.exports = { COOKIE_DOMAIN: process.env.COOKIE_DOMAIN, PLATFORM_URL: process.env.PLATFORM_URL, TENANT_FEATURE_FLAGS: process.env.TENANT_FEATURE_FLAGS, + BACKUPS_BUCKET_NAME: process.env.BACKUPS_BUCKET_NAME || "backups", + APPS_BUCKET_NAME: process.env.APPS_BUCKET_NAME || "prod-budi-app-assets", + TEMPLATES_BUCKET_NAME: process.env.TEMPLATES_BUCKET_NAME || "templates", + GLOBAL_BUCKET_NAME: process.env.GLOBAL_BUCKET_NAME || "global", + GLOBAL_CLOUD_BUCKET_NAME: + process.env.GLOBAL_CLOUD_BUCKET_NAME || "prod-budi-tenant-uploads", USE_COUCH: process.env.USE_COUCH || true, isTest, + isDev, _set(key, value) { process.env[key] = value module.exports[key] = value diff --git a/packages/backend-core/src/featureFlags/index.js b/packages/backend-core/src/featureFlags/index.js index 6d3d86978a..c050cbdfef 100644 --- a/packages/backend-core/src/featureFlags/index.js +++ b/packages/backend-core/src/featureFlags/index.js @@ -49,4 +49,5 @@ exports.getTenantFeatureFlags = tenantId => { exports.FeatureFlag = { LICENSING: "LICENSING", + GOOGLE_SHEETS: "GOOGLE_SHEETS", } diff --git a/packages/backend-core/src/objectStore/utils.js b/packages/backend-core/src/objectStore/utils.js index 1634a24981..a243553df8 100644 --- a/packages/backend-core/src/objectStore/utils.js +++ b/packages/backend-core/src/objectStore/utils.js @@ -1,12 +1,13 @@ const { join } = require("path") const { tmpdir } = require("os") +const env = require("../environment") exports.ObjectStoreBuckets = { - BACKUPS: "backups", - APPS: "prod-budi-app-assets", - TEMPLATES: "templates", - GLOBAL: "global", - GLOBAL_CLOUD: "prod-budi-tenant-uploads", + BACKUPS: env.BACKUPS_BUCKET_NAME, + APPS: env.APPS_BUCKET_NAME, + TEMPLATES: env.TEMPLATES_BUCKET_NAME, + GLOBAL: env.GLOBAL_BUCKET_NAME, + GLOBAL_CLOUD: env.GLOBAL_CLOUD_BUCKET_NAME, } exports.budibaseTempDir = function () { diff --git a/packages/bbui/package.json b/packages/bbui/package.json index bff13a354a..df3a503b2d 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": "1.0.124-alpha.0", + "version": "1.0.148-alpha.0", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.2.1", - "@budibase/string-templates": "^1.0.124-alpha.0", + "@budibase/string-templates": "^1.0.148-alpha.0", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/bbui/src/Table/DateTimeRenderer.svelte b/packages/bbui/src/Table/DateTimeRenderer.svelte index 5d856968e7..f4b0821069 100644 --- a/packages/bbui/src/Table/DateTimeRenderer.svelte +++ b/packages/bbui/src/Table/DateTimeRenderer.svelte @@ -2,17 +2,22 @@ import dayjs from "dayjs" export let value + export let schema // adding the 0- will turn a string like 00:00:00 into a valid ISO // date, but will make actual ISO dates invalid $: time = new Date(`0-${value}`) - $: isTime = !isNaN(time) + $: isTimeOnly = !isNaN(time) || schema?.timeOnly + $: isDateOnly = schema?.dateOnly + $: format = isTimeOnly + ? "HH:mm:ss" + : isDateOnly + ? "MMMM D YYYY" + : "MMMM D YYYY, HH:mm"