diff --git a/.github/workflows/release-selfhost.yml b/.github/workflows/release-selfhost.yml index e842da9d7c..f51648074c 100644 --- a/.github/workflows/release-selfhost.yml +++ b/.github/workflows/release-selfhost.yml @@ -25,14 +25,17 @@ jobs: # Pull apps and worker images docker pull budibase/apps:$release_tag docker pull budibase/worker:$release_tag + docker pull budibase/proxy:$release_tag # Tag apps and worker images docker tag budibase/apps:$release_tag budibase/apps:$SELFHOST_TAG docker tag budibase/worker:$release_tag budibase/worker:$SELFHOST_TAG + docker tag budibase/proxy:$release_tag budibase/proxy:$SELFHOST_TAG # Push images docker push budibase/apps:$SELFHOST_TAG docker push budibase/worker:$SELFHOST_TAG + docker push budibase/proxy:$SELFHOST_TAG env: DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }} @@ -73,4 +76,4 @@ jobs: files: | packages/cli/build/cli-win.exe packages/cli/build/cli-linux - packages/cli/build/cli-macos \ No newline at end of file + packages/cli/build/cli-macos diff --git a/hosting/envoy.yaml b/hosting/envoy.yaml new file mode 100644 index 0000000000..d9f8384688 --- /dev/null +++ b/hosting/envoy.yaml @@ -0,0 +1,152 @@ +static_resources: + listeners: + - name: main_listener + address: + socket_address: { address: 0.0.0.0, port_value: 10000 } + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress + codec_type: auto + route_config: + name: local_route + virtual_hosts: + - name: local_services + domains: ["*"] + routes: + - match: { prefix: "/app/" } + route: + cluster: app-service + prefix_rewrite: "/" + + - match: { path: "/v1/update" } + route: + cluster: watchtower-service + + - match: { prefix: "/builder/" } + route: + cluster: app-service + + - match: { prefix: "/builder" } + route: + cluster: app-service + + - match: { prefix: "/app_" } + route: + cluster: app-service + + # special cases for worker admin (deprecated), global and system API + - match: { prefix: "/api/global/" } + route: + cluster: worker-service + + - match: { prefix: "/api/admin/" } + route: + cluster: worker-service + + - match: { prefix: "/api/system/" } + route: + cluster: worker-service + + - match: { path: "/" } + route: + cluster: app-service + + # special case for when API requests are made, can just forward, not to minio + - match: { prefix: "/api/" } + route: + cluster: app-service + timeout: 120s + + - match: { prefix: "/worker/" } + route: + cluster: worker-service + prefix_rewrite: "/" + + - match: { prefix: "/db/" } + route: + cluster: couchdb-service + prefix_rewrite: "/" + + # minio is on the default route because this works + # best, minio + AWS SDK doesn't handle path proxy + - match: { prefix: "/" } + route: + cluster: minio-service + + http_filters: + - name: envoy.filters.http.router + + clusters: + - name: app-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: app-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: app-service + port_value: 4002 + + - name: minio-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: minio-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: minio-service + port_value: 9000 + + - name: worker-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: worker-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: worker-service + port_value: 4003 + + - name: couchdb-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: couchdb-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: couchdb-service + port_value: 5984 + + - name: watchtower-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: watchtower-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: watchtower-service + port_value: 8080 + diff --git a/hosting/kubernetes/nginx/nginx.conf b/hosting/kubernetes/nginx/nginx.conf index 2bf512964b..9d03aaab18 100644 --- a/hosting/kubernetes/nginx/nginx.conf +++ b/hosting/kubernetes/nginx/nginx.conf @@ -22,7 +22,7 @@ http { # buffering client_body_buffer_size 1K; client_header_buffer_size 1k; - client_max_body_size 1k; + client_max_body_size 10M; ignore_invalid_headers off; proxy_buffering off; @@ -36,20 +36,28 @@ http { server { listen 10000 default_server; + listen [::]:10000 default_server; server_name _; + port_in_redirect off; # Security Headers add_header X-Frame-Options SAMEORIGIN always; add_header X-Content-Type-Options nosniff always; add_header X-XSS-Protection "1; mode=block" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src http: https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; location /app { - proxy_pass http://app-service:4002; + proxy_pass http://app-service.budibase.svc.cluster.local:4002; rewrite ^/app/(.*)$ /$1 break; } location = / { + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://app-service.budibase.svc.cluster.local:4002; } @@ -63,16 +71,22 @@ http { proxy_pass http://app-service.budibase.svc.cluster.local:4002; } - location ^/(builder|app_) { + location ~ ^/(builder|app_) { + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://app-service.budibase.svc.cluster.local:4002; } location ~ ^/api/(system|admin|global)/ { - proxy_pass http://worker-service.budibase.svc.cluster.local:4003; + proxy_pass http://worker-service.budibase.svc.cluster.local:4001; } location /worker/ { - proxy_pass http://worker-service.budibase.svc.cluster.local:4003; + proxy_pass http://worker-service.budibase.svc.cluster.local:4001; rewrite ^/worker/(.*)$ /$1 break; } @@ -105,11 +119,11 @@ http { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; + proxy_set_header Connection ""; + proxy_http_version 1.1; + chunked_transfer_encoding off; proxy_connect_timeout 300; - proxy_http_version 1.1; - proxy_set_header Connection ""; - chunked_transfer_encoding off; proxy_pass http://minio-service.budibase.svc.cluster.local:9000; } diff --git a/hosting/proxy/nginx.conf b/hosting/proxy/nginx.conf index 7a8a44e2d8..ff12e2f49e 100644 --- a/hosting/proxy/nginx.conf +++ b/hosting/proxy/nginx.conf @@ -24,7 +24,6 @@ http { client_header_buffer_size 1k; client_max_body_size 1k; ignore_invalid_headers off; - proxy_buffering off; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' @@ -37,16 +36,18 @@ http { server { listen 10000 default_server; + listen [::]:10000 default_server; server_name _; client_max_body_size 1000m; ignore_invalid_headers off; proxy_buffering off; + port_in_redirect off; # Security Headers add_header X-Frame-Options SAMEORIGIN always; add_header X-Content-Type-Options nosniff always; add_header X-XSS-Protection "1; mode=block" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'unsafe-inline' 'unsafe-eval' 'self' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src http: https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; location /app { proxy_pass http://app-service:4002; @@ -54,6 +55,7 @@ http { } location = / { + port_in_redirect off; proxy_pass http://app-service:4002; } @@ -62,6 +64,7 @@ http { } location /builder/ { + port_in_redirect off; proxy_http_version 1.1; proxy_set_header Connection $connection_upgrade; proxy_set_header Upgrade $http_upgrade; @@ -71,7 +74,14 @@ http { proxy_pass http://app-service:4002; } - location ^/(builder|app_) { + location ~ ^/(builder|app_) { + port_in_redirect off; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://app-service:4002; } diff --git a/lerna.json b/lerna.json index 27d67043be..39b194d354 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.0.58-alpha.4", + "version": "1.0.66-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 3c024fe1ea..d98829c4b9 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.0.58-alpha.4", + "version": "1.0.66-alpha.0", "description": "Budibase backend core libraries used in server and worker", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index baf41fa072..a7570b12a0 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.58-alpha.4", + "version": "1.0.66-alpha.0", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/bbui/src/Button/Button.svelte b/packages/bbui/src/Button/Button.svelte index 67930b8030..8e5cc5468c 100644 --- a/packages/bbui/src/Button/Button.svelte +++ b/packages/bbui/src/Button/Button.svelte @@ -17,61 +17,55 @@ let showTooltip = false -
- - {#if showTooltip && tooltip} -
-
- -
{/if} -
+ {#if showTooltip && tooltip} +
+ +
+ {/if} + diff --git a/packages/bbui/src/Table/Table.svelte b/packages/bbui/src/Table/Table.svelte index 2aea31857e..a40ec2a45b 100644 --- a/packages/bbui/src/Table/Table.svelte +++ b/packages/bbui/src/Table/Table.svelte @@ -3,8 +3,7 @@ import "@spectrum-css/table/dist/index-vars.css" import CellRenderer from "./CellRenderer.svelte" import SelectEditRenderer from "./SelectEditRenderer.svelte" - import { cloneDeep } from "lodash" - import { deepGet } from "../helpers" + import { cloneDeep, deepGet } from "../helpers" /** * The expected schema is our normal couch schemas for our tables. diff --git a/packages/bbui/src/helpers.js b/packages/bbui/src/helpers.js index e80db76537..cf40e12d74 100644 --- a/packages/bbui/src/helpers.js +++ b/packages/bbui/src/helpers.js @@ -98,3 +98,11 @@ export const deepSet = (obj, key, value) => { } obj[split[split.length - 1]] = value } + +/** + * Deeply clones an object. Functions are not supported. + * @param obj the object to clone + */ +export const cloneDeep = obj => { + return JSON.parse(JSON.stringify(obj)) +} diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock index 1a4f5e4417..5baad30282 100644 --- a/packages/bbui/yarn.lock +++ b/packages/bbui/yarn.lock @@ -1601,9 +1601,9 @@ ms@^2.1.1: integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== nanoid@^3.1.22: - version "3.1.22" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844" - integrity sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ== + version "3.3.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.0.tgz#5906f776fd886c66c24f3653e0c46fcb1d4ad6b0" + integrity sha512-JzxqqT5u/x+/KOFSd7JP15DOo9nOoHpx6DYatqIHUW2+flybkm+mdcraotSQR5WcnZr+qhGVh8Ted0KdfSMxlg== negotiator@0.6.2: version "0.6.2" diff --git a/packages/builder/package.json b/packages/builder/package.json index b764a7a481..af4f892f0d 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "1.0.58-alpha.4", + "version": "1.0.66-alpha.0", "license": "GPL-3.0", "private": true, "scripts": { @@ -64,10 +64,10 @@ } }, "dependencies": { - "@budibase/bbui": "^1.0.58-alpha.4", - "@budibase/client": "^1.0.58-alpha.4", - "@budibase/frontend-core": "^1.0.58-alpha.4", - "@budibase/string-templates": "^1.0.58-alpha.4", + "@budibase/bbui": "^1.0.66-alpha.0", + "@budibase/client": "^1.0.66-alpha.0", + "@budibase/frontend-core": "^1.0.66-alpha.0", + "@budibase/string-templates": "^1.0.66-alpha.0", "@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 23dede9fe2..db797bc743 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -275,10 +275,7 @@ const getProviderContextBindings = (asset, dataProviders) => { */ const getUserBindings = () => { let bindings = [] - const { schema } = getSchemaForDatasource(null, { - type: "table", - tableId: TableNames.USERS, - }) + const { schema } = getSchemaForTable(TableNames.USERS) const keys = Object.keys(schema).sort() const safeUser = makePropSafe("user") keys.forEach(key => { @@ -385,9 +382,33 @@ export const getButtonContextBindings = (actions, actionId) => { } /** - * Gets a schema for a datasource object. + * Gets the schema for a certain table ID. + * The options which can be passed in are: + * formSchema: whether the schema is for a form + * searchableSchema: whether to generate a searchable schema, which may have + * fewer fields than a readable schema + * @param tableId the table ID to get the schema for + * @param options options for generating the schema + * @return {{schema: Object, table: Object}} */ -export const getSchemaForDatasource = (asset, datasource, isForm = false) => { +export const getSchemaForTable = (tableId, options) => { + return getSchemaForDatasource(null, { type: "table", tableId }, options) +} + +/** + * Gets a schema for a datasource object. + * The options which can be passed in are: + * formSchema: whether the schema is for a form + * searchableSchema: whether to generate a searchable schema, which may have + * fewer fields than a readable schema + * @param asset the current root client app asset (layout or screen). This is + * optional and only needed for "provider" datasource types. + * @param datasource the datasource definition + * @param options options for generating the schema + * @return {{schema: Object, table: Object}} + */ +export const getSchemaForDatasource = (asset, datasource, options) => { + options = options || {} let schema, table if (datasource) { @@ -399,7 +420,7 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { if (type === "provider") { const component = findComponent(asset.props, datasource.providerId) const source = getDatasourceForProvider(asset, component) - return getSchemaForDatasource(asset, source, isForm) + return getSchemaForDatasource(asset, source, options) } // "query" datasources are those targeting non-plus datasources or @@ -448,8 +469,16 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { // Determine the schema from the backing entity if not already determined if (table && !schema) { if (type === "view") { + // For views, the schema is pulled from the `views` property of the + // table schema = cloneDeep(table.views?.[datasource.name]?.schema) - } else if (type === "query" && isForm) { + } else if ( + type === "query" && + (options.formSchema || options.searchableSchema) + ) { + // For queries, if we are generating a schema for a form or a searchable + // schema then we want to use the query parameters rather than the + // query schema schema = {} const params = table.parameters || [] params.forEach(param => { @@ -458,6 +487,7 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { } }) } else { + // Otherwise we just want the schema of the table schema = cloneDeep(table.schema) } } @@ -485,9 +515,31 @@ export const getSchemaForDatasource = (asset, datasource, isForm = false) => { schema = { ...schema, ...jsonAdditions } } - // Add _id and _rev fields for certain types - if (schema && !isForm && ["table", "link"].includes(datasource.type)) { + // Determine if we should add ID and rev to the schema + const isInternal = table && !table.sql + const isTable = ["table", "link"].includes(datasource.type) + + // ID is part of the readable schema for all tables + // Rev is part of the readable schema for internal tables only + let addId = isTable + let addRev = isTable && isInternal + + // Don't add ID or rev for form schemas + if (options.formSchema) { + addId = false + addRev = false + } + + // ID is only searchable for internal tables + else if (options.searchableSchema) { + addId = isTable && isInternal + } + + // Add schema properties if required + if (addId) { schema["_id"] = { type: "string" } + } + if (addRev) { schema["_rev"] = { type: "string" } } diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js b/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js index 9fe8cc9563..e748161529 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js +++ b/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js @@ -141,7 +141,9 @@ const fieldTypeToComponentMap = { } export function makeDatasourceFormComponents(datasource) { - const { schema } = getSchemaForDatasource(null, datasource, true) + const { schema } = getSchemaForDatasource(null, datasource, { + formSchema: true, + }) let components = [] let fields = Object.keys(schema || {}) fields.forEach(field => { diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 64b7cff78d..15d8f2484c 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -28,8 +28,8 @@ import { debounce } from "lodash" import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte" import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte" - // need the client lucene builder to convert to the structure API expects import { LuceneUtils } from "@budibase/frontend-core" + import { getSchemaForTable } from "builderStore/dataBinding" export let block export let testData @@ -46,13 +46,13 @@ block || $automationStore.selectedBlock, $automationStore.selectedAutomation?.automation?.definition ) - $: inputData = testData ? testData : block.inputs $: tableId = inputData ? inputData.tableId : null $: table = tableId ? $tables.list.find(table => table._id === inputData.tableId) : { schema: {} } - $: schemaFields = table ? Object.values(table.schema) : [] + $: schema = getSchemaForTable(tableId, { searchableSchema: true }).schema + $: schemaFields = Object.values(schema || {}) const onChange = debounce(async function (e, key) { try { diff --git a/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte b/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte index f04a6c25c9..f7bb0e3cc8 100644 --- a/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte @@ -48,6 +48,3 @@ - - diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte index 091e3e7ce6..7f0cc7357b 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte @@ -213,6 +213,3 @@ {/if} - - diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte index 86cc25a0f3..8a34edade0 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte @@ -130,6 +130,3 @@ - - diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index ee0169f9e7..5c12d43ceb 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -23,6 +23,10 @@ const dispatch = createEventDispatcher() export let bindings + // jsValue/hbsValue are the state of the value that is being built + // within this binding panel - the value should not be updated until + // the binding panel is saved. This is the default value of the + // expression when the binding panel is opened, but shouldn't be updated. export let value = "" export let valid export let allowJS = false @@ -51,8 +55,8 @@ }) $: codeMirrorHints = bindings?.map(x => `$("${x.readableBinding}")`) - const updateValue = value => { - valid = isValid(readableToRuntimeBinding(bindings, value)) + const updateValue = val => { + valid = isValid(readableToRuntimeBinding(bindings, val)) if (valid) { dispatch("change", value) } @@ -60,7 +64,7 @@ // Adds a HBS helper to the expression const addHelper = helper => { - hbsValue = addHBSBinding(value, getCaretPosition(), helper.text) + hbsValue = addHBSBinding(hbsValue, getCaretPosition(), helper.text) updateValue(hbsValue) } diff --git a/packages/builder/src/components/common/bindings/utils.js b/packages/builder/src/components/common/bindings/utils.js index 28845fe12b..42a3f11677 100644 --- a/packages/builder/src/components/common/bindings/utils.js +++ b/packages/builder/src/components/common/bindings/utils.js @@ -1,7 +1,10 @@ export function addHBSBinding(value, caretPos, binding) { binding = typeof binding === "string" ? binding : binding.path value = value == null ? "" : value - if (!value.includes("{{") && !value.includes("}}")) { + + const left = caretPos?.start ? value.substring(0, caretPos.start) : "" + const right = caretPos?.end ? value.substring(caretPos.end) : "" + if (!left.includes("{{") || !right.includes("}}")) { binding = `{{ ${binding} }}` } if (caretPos.start) { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte index 1f729af0c9..8cf0f37f70 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte @@ -126,13 +126,15 @@ {#if selectedActionComponent} -
- -
+ {#key selectedAction.id} +
+ +
+ {/key} {/if}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/DuplicateRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/DuplicateRow.svelte index 38c4347e43..7e72a051ce 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/DuplicateRow.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/DuplicateRow.svelte @@ -4,7 +4,7 @@ import { tables } from "stores/backend" import { getContextProviderComponents, - getSchemaForDatasource, + getSchemaForTable, } from "builderStore/dataBinding" import SaveFields from "./SaveFields.svelte" @@ -60,7 +60,7 @@ } const getSchemaFields = (asset, tableId) => { - const { schema } = getSchemaForDatasource(asset, { type: "table", tableId }) + const { schema } = getSchemaForTable(tableId) delete schema._id delete schema._rev return Object.values(schema || {}) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/SaveRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/SaveRow.svelte index 55aac87cfd..c88b301fc9 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/SaveRow.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/SaveRow.svelte @@ -4,7 +4,7 @@ import { tables } from "stores/backend" import { getContextProviderComponents, - getSchemaForDatasource, + getSchemaForTable, } from "builderStore/dataBinding" import SaveFields from "./SaveFields.svelte" @@ -60,7 +60,7 @@ } const getSchemaFields = (asset, tableId) => { - const { schema } = getSchemaForDatasource(asset, { type: "table", tableId }) + const { schema } = getSchemaForTable(tableId) return Object.values(schema || {}) } diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ColumnEditor/ColumnDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ColumnEditor/ColumnDrawer.svelte new file mode 100644 index 0000000000..ef4726751b --- /dev/null +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ColumnEditor/ColumnDrawer.svelte @@ -0,0 +1,178 @@ + + + +
+ + {#if columns?.length} + +
+
+ + +
+
+
+ {#each columns as column (column.id)} +
+
(dragDisabled = false)} + > + +
+ + removeColumn(column.id)} + disabled={columns.length === 1} + /> +
+ {/each} +
+ + {:else} +
+
+ Add the first column to your table. +
+ {/if} +
+
+
+
+ + +
+
+
+ +
+ + + diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ColumnEditor/ColumnEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ColumnEditor/ColumnEditor.svelte new file mode 100644 index 0000000000..8cebf5a657 --- /dev/null +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ColumnEditor/ColumnEditor.svelte @@ -0,0 +1,64 @@ + + +Configure columns + + + Configure the columns in your table. + + + + diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte index ef56c610bd..bca78f6cbb 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte @@ -90,7 +90,7 @@ -
+
{#if !filters?.length} @@ -184,6 +184,7 @@ max-width: 1000px; margin: 0 auto; } + .fields { display: grid; column-gap: var(--spacing-l); diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte index 2cb35a9cf5..25c39d9f79 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte @@ -18,7 +18,9 @@ let tempValue = value || [] $: dataSource = getDatasourceForProvider($currentAsset, componentInstance) - $: schema = getSchemaForDatasource($currentAsset, dataSource)?.schema + $: schema = getSchemaForDatasource($currentAsset, dataSource, { + searchableSchema: true, + })?.schema $: schemaFields = Object.values(schema || {}) const saveFilter = async () => { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FormFieldSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FormFieldSelect.svelte index ba54de5478..94a542480f 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FormFieldSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FormFieldSelect.svelte @@ -17,7 +17,9 @@ component => component._component === "@budibase/standard-components/form" ) $: datasource = getDatasourceForProvider($currentAsset, form) - $: schema = getSchemaForDatasource($currentAsset, datasource, true).schema + $: schema = getSchemaForDatasource($currentAsset, datasource, { + formSchema: true, + }).schema $: options = getOptions(schema, type) const getOptions = (schema, type) => { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte index 40357f50be..33a82d1886 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte @@ -15,7 +15,7 @@ } -Configure Links +Configure links Configure the links in your navigation bar. diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte index e609426b1e..b3387fdd05 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte @@ -15,7 +15,9 @@ const dispatch = createEventDispatcher() $: datasource = getDatasourceForProvider($currentAsset, componentInstance) - $: schema = getSchemaForDatasource($currentAsset, datasource).schema + $: schema = getSchemaForDatasource($currentAsset, datasource, { + searchableSchema: true, + }).schema $: options = getOptions(datasource, schema || {}) $: boundValue = getSelectedOption(value, options) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ValidationEditor/ValidationDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ValidationEditor/ValidationDrawer.svelte index c7c4bda481..081e748caf 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ValidationEditor/ValidationDrawer.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ValidationEditor/ValidationDrawer.svelte @@ -116,6 +116,7 @@ $: schemaRules = parseRulesFromSchema(field, dataSourceSchema || {}) $: fieldType = type?.split("/")[1] || "string" $: constraintOptions = getConstraintsForType(fieldType) + const getConstraintsForType = type => { return ConstraintMap[type] } diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js index 15aa670fa9..23a0a312bc 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js @@ -18,6 +18,7 @@ import OptionsEditor from "./OptionsEditor/OptionsEditor.svelte" import FormFieldSelect from "./FormFieldSelect.svelte" import ValidationEditor from "./ValidationEditor/ValidationEditor.svelte" import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte" +import ColumnEditor from "./ColumnEditor/ColumnEditor.svelte" const componentMap = { text: DrawerBindableCombobox, @@ -40,6 +41,7 @@ const componentMap = { navigation: NavigationEditor, filter: FilterEditor, url: URLSelect, + columns: ColumnEditor, "field/string": FormFieldSelect, "field/number": FormFieldSelect, "field/options": FormFieldSelect, diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte index 0c23aa7908..5c39273668 100644 --- a/packages/builder/src/components/integration/QueryViewer.svelte +++ b/packages/builder/src/components/integration/QueryViewer.svelte @@ -39,7 +39,7 @@ $: datasource = $datasources.list.find(ds => ds._id === query.datasourceId) $: query.schema = fieldsToSchema(fields) $: datasourceType = datasource?.source - $: integrationInfo = $integrations[datasourceType] + $: integrationInfo = datasourceType ? $integrations[datasourceType] : null $: queryConfig = integrationInfo?.query $: shouldShowQueryConfig = queryConfig && query.queryVerb $: readQuery = query.queryVerb === "read" || query.readable @@ -160,7 +160,7 @@
Results - + diff --git a/packages/builder/vite.config.js b/packages/builder/vite.config.js index b68d265bc5..47fed87e1e 100644 --- a/packages/builder/vite.config.js +++ b/packages/builder/vite.config.js @@ -15,6 +15,7 @@ export default ({ mode }) => { build: { minify: isProduction, outDir: "../server/builder", + sourcemap: !isProduction, }, plugins: [ svelte({ diff --git a/packages/cli/package.json b/packages/cli/package.json index e6ae183b2d..c6bcfaf689 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "1.0.58-alpha.4", + "version": "1.0.66-alpha.0", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/cli/src/hosting/index.js b/packages/cli/src/hosting/index.js index ecf3b710b2..2b147810b4 100644 --- a/packages/cli/src/hosting/index.js +++ b/packages/cli/src/hosting/index.js @@ -15,7 +15,7 @@ const makeEnv = require("./makeEnv") const axios = require("axios") const AnalyticsClient = require("../analytics/Client") -const BUDIBASE_SERVICES = ["app-service", "worker-service"] +const BUDIBASE_SERVICES = ["app-service", "worker-service", "proxy-service"] const ERROR_FILE = "docker-error.log" const FILE_URLS = [ "https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml", diff --git a/packages/client/.gitignore b/packages/client/.gitignore index 1947eba17b..9f84a3631d 100644 --- a/packages/client/.gitignore +++ b/packages/client/.gitignore @@ -2,4 +2,5 @@ node_modules package-lock.json release/ -dist/ \ No newline at end of file +dist/ +stats.html \ No newline at end of file diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 06dbaad660..1b8d261398 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -851,16 +851,12 @@ "type": "color", "label": "Color", "key": "color", - "showInBar": true, - "barSeparator": false + "showInBar": true }, { "type": "boolean", "label": "Show delete icon", - "key": "closable", - "showInBar": true, - "barIcon": "TagItalic", - "barTitle": "Show delete icon" + "key": "closable" }, { "type": "event", @@ -2680,11 +2676,10 @@ "defaultValue": 8 }, { - "type": "multifield", + "type": "columns", "label": "Columns", "key": "columns", - "dependsOn": "dataProvider", - "placeholder": "All columns" + "dependsOn": "dataProvider" }, { "type": "select", @@ -2951,7 +2946,7 @@ "defaultValue": 8 }, { - "type": "multifield", + "type": "columns", "label": "Table Columns", "key": "tableColumns", "dependsOn": "dataSource", diff --git a/packages/client/package.json b/packages/client/package.json index 7c54737de0..efc0703100 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "1.0.58-alpha.4", + "version": "1.0.66-alpha.0", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,18 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^1.0.58-alpha.4", - "@budibase/frontend-core": "^1.0.58-alpha.4", - "@budibase/string-templates": "^1.0.58-alpha.4", - "regexparam": "^1.3.0", - "rollup-plugin-polyfill-node": "^0.8.0", - "shortid": "^2.2.15", - "svelte-spa-router": "^3.0.5" - }, - "devDependencies": { - "@rollup/plugin-alias": "^3.1.5", - "@rollup/plugin-commonjs": "^18.0.0", - "@rollup/plugin-node-resolve": "^11.2.1", + "@budibase/bbui": "^1.0.66-alpha.0", + "@budibase/frontend-core": "^1.0.66-alpha.0", + "@budibase/string-templates": "^1.0.66-alpha.0", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", @@ -41,8 +32,18 @@ "@spectrum-css/vars": "^3.0.1", "apexcharts": "^3.22.1", "dayjs": "^1.10.5", - "fs-extra": "^8.1.0", - "jsdom": "^16.0.1", + "regexparam": "^1.3.0", + "rollup-plugin-polyfill-node": "^0.8.0", + "shortid": "^2.2.15", + "svelte": "^3.38.2", + "svelte-apexcharts": "^1.0.2", + "svelte-flatpickr": "^3.1.0", + "svelte-spa-router": "^3.0.5" + }, + "devDependencies": { + "@rollup/plugin-alias": "^3.1.5", + "@rollup/plugin-commonjs": "^18.0.0", + "@rollup/plugin-node-resolve": "^11.2.1", "postcss": "^8.2.10", "rollup": "^2.44.0", "rollup-plugin-json": "^4.0.0", @@ -50,9 +51,7 @@ "rollup-plugin-svelte": "^7.1.0", "rollup-plugin-svg": "^2.0.0", "rollup-plugin-terser": "^7.0.2", - "svelte": "^3.38.2", - "svelte-apexcharts": "^1.0.2", - "svelte-flatpickr": "^3.1.0" + "rollup-plugin-visualizer": "^5.5.4" }, "gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc" } diff --git a/packages/client/rollup.config.js b/packages/client/rollup.config.js index 1aee91df42..5206b63884 100644 --- a/packages/client/rollup.config.js +++ b/packages/client/rollup.config.js @@ -8,6 +8,7 @@ import svg from "rollup-plugin-svg" import json from "rollup-plugin-json" import nodePolyfills from "rollup-plugin-polyfill-node" import path from "path" +import { visualizer } from "rollup-plugin-visualizer" const production = !process.env.ROLLUP_WATCH const ignoredWarnings = [ @@ -79,6 +80,7 @@ export default { svg(), json(), production && terser(), + !production && visualizer(), ], watch: { clearScreen: false, diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index f43c2b30ec..78fff52426 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -1,10 +1,15 @@