diff --git a/README.md b/README.md index 1dec1737da..bd38610566 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Budibase is open-source - licensed as GPL v3. This should fill you with confiden

### Load data or start from scratch -Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, MySQL, Airtable, S3, DynamoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no data sources. [Request new data sources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas). +Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, MySQL, Airtable, S3, DynamoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no datasources. [Request new datasources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).

Budibase data diff --git a/examples/nextjs-api-sales/definitions/openapi.ts b/examples/nextjs-api-sales/definitions/openapi.ts index 4f4ad45fc6..7f7f6befec 100644 --- a/examples/nextjs-api-sales/definitions/openapi.ts +++ b/examples/nextjs-api-sales/definitions/openapi.ts @@ -348,7 +348,7 @@ export interface paths { } } responses: { - /** Returns the created table, including the ID which has been generated for it. This can be internal or external data sources. */ + /** Returns the created table, including the ID which has been generated for it. This can be internal or external datasources. */ 200: { content: { "application/json": components["schemas"]["tableOutput"] @@ -959,7 +959,7 @@ export interface components { query: { /** @description The ID of the query. */ _id: string - /** @description The ID of the data source the query belongs to. */ + /** @description The ID of the datasource the query belongs to. */ datasourceId?: string /** @description The bindings which are required to perform this query. */ parameters?: string[] @@ -983,7 +983,7 @@ export interface components { data: { /** @description The ID of the query. */ _id: string - /** @description The ID of the data source the query belongs to. */ + /** @description The ID of the datasource the query belongs to. */ datasourceId?: string /** @description The bindings which are required to perform this query. */ parameters?: string[] diff --git a/hosting/nginx.dev.conf.hbs b/hosting/nginx.dev.conf.hbs index 430ea75398..14c32b1bba 100644 --- a/hosting/nginx.dev.conf.hbs +++ b/hosting/nginx.dev.conf.hbs @@ -65,10 +65,6 @@ http { proxy_pass http://{{ address }}:4001; } - location /preview { - proxy_pass http://{{ address }}:4001; - } - location /builder { proxy_pass http://{{ address }}:3000; rewrite ^/builder(.*)$ /builder/$1 break; @@ -84,9 +80,18 @@ http { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } - location /vite { - proxy_pass http://{{ address }}:3000; - rewrite ^/vite(.*)$ /$1 break; + location /vite/ { + proxy_pass http://{{ address }}:3000; + rewrite ^/vite(.*)$ /$1 break; + } + + location /socket/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_pass http://{{ address }}:4001; } location / { diff --git a/hosting/nginx.prod.conf.hbs b/hosting/nginx.prod.conf.hbs index 0ff986d0a7..f3202ad4a4 100644 --- a/hosting/nginx.prod.conf.hbs +++ b/hosting/nginx.prod.conf.hbs @@ -88,10 +88,6 @@ http { proxy_pass http://$apps:4002; } - location /preview { - proxy_pass http://$apps:4002; - } - location = / { proxy_pass http://$apps:4002; } @@ -162,6 +158,15 @@ http { rewrite ^/db/(.*)$ /$1 break; } + location /socket/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_pass http://$apps:4002; + } + location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/hosting/scripts/build-target-paths.sh b/hosting/scripts/build-target-paths.sh index ee314c1ce4..fce768e2ee 100644 --- a/hosting/scripts/build-target-paths.sh +++ b/hosting/scripts/build-target-paths.sh @@ -4,9 +4,9 @@ echo ${TARGETBUILD} > /buildtarget.txt if [[ "${TARGETBUILD}" = "aas" ]]; then # Azure AppService uses /home for persisent data & SSH on port 2222 DATA_DIR=/home - mkdir -p $DATA_DIR/{search,minio,couchdb} - mkdir -p $DATA_DIR/couchdb/{dbs,views} - chown -R couchdb:couchdb $DATA_DIR/couchdb/ + mkdir -p $DATA_DIR/{search,minio,couch} + mkdir -p $DATA_DIR/couch/{dbs,views} + chown -R couchdb:couchdb $DATA_DIR/couch/ apt update apt-get install -y openssh-server sed -i "s/#Port 22/Port 2222/" /etc/ssh/sshd_config @@ -16,5 +16,4 @@ if [[ "${TARGETBUILD}" = "aas" ]]; then else sed -i "s#DATA_DIR#/data#g" /opt/clouseau/clouseau.ini sed -i "s#DATA_DIR#/data#g" /opt/couchdb/etc/local.ini - fi \ No newline at end of file diff --git a/hosting/single/couch/local.ini b/hosting/single/couch/local.ini index 35f0383dfc..266c0d4b60 100644 --- a/hosting/single/couch/local.ini +++ b/hosting/single/couch/local.ini @@ -1,5 +1,5 @@ ; CouchDB Configuration Settings [couchdb] -database_dir = DATA_DIR/couchdb/dbs -view_index_dir = DATA_DIR/couchdb/views +database_dir = DATA_DIR/couch/dbs +view_index_dir = DATA_DIR/couch/views diff --git a/hosting/single/nginx/nginx-default-site.conf b/hosting/single/nginx/nginx-default-site.conf index c0d80a0185..bd89e21251 100644 --- a/hosting/single/nginx/nginx-default-site.conf +++ b/hosting/single/nginx/nginx-default-site.conf @@ -66,6 +66,15 @@ server { rewrite ^/db/(.*)$ /$1 break; } + location /socket/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_pass http://127.0.0.1:4001; + } + location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/hosting/single/runner.sh b/hosting/single/runner.sh index 09387343ba..77015d75ee 100644 --- a/hosting/single/runner.sh +++ b/hosting/single/runner.sh @@ -36,10 +36,10 @@ fi export COUCH_DB_URL=http://$COUCHDB_USER:$COUCHDB_PASSWORD@localhost:5984 # make these directories in runner, incase of mount -mkdir -p ${DATA_DIR}/couchdb/{dbs,views} +mkdir -p ${DATA_DIR}/couch/{dbs,views} mkdir -p ${DATA_DIR}/minio mkdir -p ${DATA_DIR}/search -chown -R couchdb:couchdb ${DATA_DIR}/couchdb +chown -R couchdb:couchdb ${DATA_DIR}/couch redis-server --requirepass $REDIS_PASSWORD & /opt/clouseau/bin/clouseau & /minio/minio server ${DATA_DIR}/minio & diff --git a/lerna.json b/lerna.json index bee30cbc57..ea81293bd9 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.3.12-alpha.3", + "version": "1.3.15-alpha.9", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 3f5cb33241..24df48b8f7 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.3.12-alpha.3", + "version": "1.3.15-alpha.9", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -20,11 +20,12 @@ "test:watch": "jest --watchAll" }, "dependencies": { - "@budibase/types": "1.3.12-alpha.3", + "@budibase/types": "1.3.15-alpha.9", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-sdk": "2.1030.0", "bcrypt": "5.0.1", + "bcryptjs": "2.4.3", "dotenv": "16.0.1", "emitter-listener": "1.1.2", "ioredis": "4.28.0", diff --git a/packages/backend-core/plugins.js b/packages/backend-core/plugins.js new file mode 100644 index 0000000000..018e214dcb --- /dev/null +++ b/packages/backend-core/plugins.js @@ -0,0 +1,3 @@ +module.exports = { + ...require("./src/plugin"), +} diff --git a/packages/backend-core/src/db/Replication.ts b/packages/backend-core/src/db/Replication.ts index b46f6072be..e0bd3c7a43 100644 --- a/packages/backend-core/src/db/Replication.ts +++ b/packages/backend-core/src/db/Replication.ts @@ -1,4 +1,5 @@ import { dangerousGetDB, closeDB } from "." +import { DocumentType } from "./constants" class Replication { source: any @@ -53,6 +54,14 @@ class Replication { return this.replication } + appReplicateOpts() { + return { + filter: (doc: any) => { + return doc._id !== DocumentType.APP_METADATA + }, + } + } + /** * Rollback the target DB back to the state of the source DB */ @@ -60,6 +69,7 @@ class Replication { await this.target.destroy() // Recreate the DB again this.target = dangerousGetDB(this.target.name) + // take the opportunity to remove deleted tombstones await this.replicate() } diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index 321ebd7f58..4926a60150 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -254,7 +254,16 @@ export async function getAllApps({ dev, all, idsOnly, efficient }: any = {}) { return false }) if (idsOnly) { - return appDbNames + const devAppIds = appDbNames.filter(appId => isDevAppID(appId)) + const prodAppIds = appDbNames.filter(appId => !isDevAppID(appId)) + switch (dev) { + case true: + return devAppIds + case false: + return prodAppIds + default: + return appDbNames + } } const appPromises = appDbNames.map((app: any) => // skip setup otherwise databases could be re-created diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 83d9a582fd..be1e1eacfc 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -19,6 +19,7 @@ if (!LOADED && isDev() && !isTest()) { const env = { isTest, isDev, + JS_BCRYPT: process.env.JS_BCRYPT, JWT_SECRET: process.env.JWT_SECRET, COUCH_DB_URL: process.env.COUCH_DB_URL || "http://localhost:4005", COUCH_DB_USERNAME: process.env.COUCH_DB_USER, diff --git a/packages/backend-core/src/hashing.js b/packages/backend-core/src/hashing.js index 45abe2f9bd..7524e66043 100644 --- a/packages/backend-core/src/hashing.js +++ b/packages/backend-core/src/hashing.js @@ -1,5 +1,5 @@ -const bcrypt = require("bcrypt") const env = require("./environment") +const bcrypt = env.JS_BCRYPT ? require("bcryptjs") : require("bcrypt") const { v4 } = require("uuid") const SALT_ROUNDS = env.SALT_ROUNDS || 10 diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index d2ea8328a6..2c234bd4b8 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -17,6 +17,7 @@ import * as dbConstants from "./db/constants" import * as logging from "./logging" import pino from "./pino" import * as middleware from "./middleware" +import plugins from "./plugin" // mimic the outer package exports import * as db from "./pkg/db" @@ -55,6 +56,7 @@ const core = { errors, logging, roles, + plugins, ...pino, ...errorClasses, middleware, diff --git a/packages/backend-core/src/objectStore/index.ts b/packages/backend-core/src/objectStore/index.ts index a9f7981844..a97aa8f65d 100644 --- a/packages/backend-core/src/objectStore/index.ts +++ b/packages/backend-core/src/objectStore/index.ts @@ -307,9 +307,13 @@ export const uploadDirectory = async ( return files } -exports.downloadTarballDirect = async (url: string, path: string) => { +exports.downloadTarballDirect = async ( + url: string, + path: string, + headers = {} +) => { path = sanitizeKey(path) - const response = await fetch(url) + const response = await fetch(url, { headers }) if (!response.ok) { throw new Error(`unexpected response ${response.statusText}`) } diff --git a/packages/backend-core/src/plugin/index.ts b/packages/backend-core/src/plugin/index.ts new file mode 100644 index 0000000000..a6d1853007 --- /dev/null +++ b/packages/backend-core/src/plugin/index.ts @@ -0,0 +1,7 @@ +import * as utils from "./utils" + +const pkg = { + ...utils, +} + +export = pkg diff --git a/packages/cli/src/plugins/validate.js b/packages/backend-core/src/plugin/utils.js similarity index 91% rename from packages/cli/src/plugins/validate.js rename to packages/backend-core/src/plugin/utils.js index a6b4555cbd..020fb4484d 100644 --- a/packages/cli/src/plugins/validate.js +++ b/packages/backend-core/src/plugin/utils.js @@ -1,5 +1,8 @@ -const { PluginTypes } = require("./constants") -const { DatasourceFieldType, QueryType } = require("@budibase/types") +const { + DatasourceFieldType, + QueryType, + PluginType, +} = require("@budibase/types") const joi = require("joi") const DATASOURCE_TYPES = [ @@ -78,11 +81,11 @@ function validateDatasource(schema) { } exports.validate = schema => { - switch (schema.type) { - case PluginTypes.COMPONENT: + switch (schema?.type) { + case PluginType.COMPONENT: validateComponent(schema) break - case PluginTypes.DATASOURCE: + case PluginType.DATASOURCE: validateDatasource(schema) break default: diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 22c17a9444..2e62aea734 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -1377,6 +1377,11 @@ bcrypt@5.0.1: "@mapbox/node-pre-gyp" "^1.0.0" node-addon-api "^3.1.0" +bcryptjs@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" + integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" diff --git a/packages/bbui/package.json b/packages/bbui/package.json index c9e35848f3..c05ea9b038 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.3.12-alpha.3", + "version": "1.3.15-alpha.9", "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.3.12-alpha.3", + "@budibase/string-templates": "1.3.15-alpha.9", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/bbui/src/Label/Label.svelte b/packages/bbui/src/Label/Label.svelte index 3395ab4179..6b3392ce2d 100644 --- a/packages/bbui/src/Label/Label.svelte +++ b/packages/bbui/src/Label/Label.svelte @@ -4,10 +4,15 @@ export let size = "M" export let tooltip = "" + export let muted - @@ -17,4 +22,8 @@ padding: 0; white-space: nowrap; } + + .muted { + opacity: 0.5; + } diff --git a/packages/bbui/src/Modal/ModalContent.svelte b/packages/bbui/src/Modal/ModalContent.svelte index 6d609d6f1b..25fac63ec8 100644 --- a/packages/bbui/src/Modal/ModalContent.svelte +++ b/packages/bbui/src/Modal/ModalContent.svelte @@ -24,7 +24,6 @@ export let secondaryAction = undefined export let secondaryButtonWarning = false export let dataCy = null - const { hide, cancel } = getContext(Context.Modal) let loading = false $: confirmDisabled = disabled || loading @@ -88,12 +87,11 @@

- {#if showCancelButton || showConfirmButton} + {#if showCancelButton || showConfirmButton || $$slots.footer}
- {#if showSecondaryButton && secondaryButtonText && secondaryAction}
diff --git a/packages/builder/src/pages/builder/portal/_layout.svelte b/packages/builder/src/pages/builder/portal/_layout.svelte index b5b6556f06..69dfa646b5 100644 --- a/packages/builder/src/pages/builder/portal/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/_layout.svelte @@ -54,6 +54,8 @@ : undefined, { title: "Auth", href: "/builder/portal/manage/auth" }, { title: "Email", href: "/builder/portal/manage/email" }, + { title: "Plugins", href: "/builder/portal/manage/plugins" }, + { title: "Organisation", href: "/builder/portal/settings/organisation", diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index 13d23f6a51..f0206db411 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -15,7 +15,6 @@ import Spinner from "components/common/Spinner.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte" import UpdateAppModal from "components/start/UpdateAppModal.svelte" - import ExportAppModal from "components/start/ExportAppModal.svelte" import { store, automationStore } from "builderStore" import { API } from "api" @@ -33,7 +32,6 @@ let selectedApp let creationModal let updatingModal - let exportModal let creatingApp = false let loaded = $apps?.length || $templates?.length let searchTerm = "" @@ -407,10 +405,6 @@ - - - - diff --git a/packages/builder/src/pages/builder/portal/manage/plugins/_components/DeletePluginModal.svelte b/packages/builder/src/pages/builder/portal/manage/plugins/_components/DeletePluginModal.svelte new file mode 100644 index 0000000000..6b09e7b276 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/plugins/_components/DeletePluginModal.svelte @@ -0,0 +1,33 @@ + + + + + Are you sure you want to delete {plugin?.name} + + diff --git a/packages/builder/src/pages/builder/portal/manage/plugins/_components/PluginRow.svelte b/packages/builder/src/pages/builder/portal/manage/plugins/_components/PluginRow.svelte new file mode 100644 index 0000000000..18390c7fcb --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/plugins/_components/PluginRow.svelte @@ -0,0 +1,155 @@ + + +
detailsModal.show()}> +
+
+
+ +
+
+ + {plugin.name} + + + {friendlyName} + +
+
+
+
{plugin.version}
+
+ {plugin.schema.type.charAt(0).toUpperCase() + plugin.schema.type.slice(1)} +
+
+ +
+
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+ + + + +
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/plugins/index.svelte b/packages/builder/src/pages/builder/portal/manage/plugins/index.svelte new file mode 100644 index 0000000000..5d73447710 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/plugins/index.svelte @@ -0,0 +1,95 @@ + + + + + Plugins + Add your own custom datasources and components + + + +
+
+ +
+
+
+
-