diff --git a/.gitignore b/.gitignore
index edad41cdec..b6cfa424ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,3 +81,6 @@ typings/
# Mac files
.DS_Store
+
+# Nova Editor
+.nova
\ No newline at end of file
diff --git a/README.md b/README.md
index 50ef3dc855..f1eeda2588 100644
--- a/README.md
+++ b/README.md
@@ -8,10 +8,10 @@
- Build business apps 50x faster
+ Build internal tools 50x faster
- Budibase is an open-source low-code platform that helps developers and IT professionals design, build, and ship business apps 50x faster.
+ Budibase is an open-source low-code platform that helps developers and IT professionals build, automate and ship internal tools 50x faster.
@@ -67,18 +67,26 @@ When other platforms chose the closed source route, we decided to go open source
- **Automate processes, integrate with other tools, and connect to webhooks.** Save time by automating manual processes and workflows. From connecting to webhooks, to automating emails, simply tell Budibase what to do and let it work for you. You can easily [create new automations for Budibase here](https://github.com/Budibase/automations) or [request new integrations here](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
-- **Cloud hosting (available) and self-hosting (coming soon).** Users will soon have the option to host with Budibase in AWS (available now) or self-host (coming very soon). From the very beginning, we wanted our users to have the option to self-host. We understand the importance of having full control over data. This is why we are working incredibly hard to offer an easy path to self-hosting. If you are interested in self-hosting, please [join the conversation and add your thoughts](https://github.com/Budibase/budibase/discussions/648).
+- **Cloud hosting and self-hosting.** Users can self-host (see below), or host their apps with Budibase. Currently, our cloud hosting offering is limited to the free tier but we aim to change this in the future. For heavy usage, we advise users to self-host.
+
+
+## 🤖 Self-hosting
+
+
+
+
+
+Budibase wants to make sure anyone can use the tools we develop and we know a lot of people need to be able to host the apps they make on their own systems - that is why we've decided to try and make self hosting as easy as possible!
+
+Currently, you can host your apps using Docker. The documentation for self-hosting can be found [here](https://docs.budibase.com/self-hosting/introduction-to-self-hosting).
## ⌛ Status
- [x] Alpha: We are demoing Budibase to users and receiving feedback
- [x] Private Beta: We are testing Budibase with a closed set of customers
-- [x] Public Beta: Anyone can [sign-up and use Budibase](https://portal.budi.live/signup) but it's not production ready. We cannot ensure backwards compatibility
+- [x] Public Beta: Anyone can [sign-up and use Budibase](https://portal.budi.live/signup).
- [ ] Official Launch: Production-ready
-
-We are currently in Public Beta. Until our official launch, we cannot ensure backwards compatibility for your Budibase applications between versions. Issues may arise when trying to edit apps created with old versions of the Budibase builder.
-
Watch "releases" of this repo to get notified of major updates, and give the star button a click whilst you're there.
diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml
index c4a6c669b3..5b7c266c1e 100644
--- a/hosting/docker-compose.yaml
+++ b/hosting/docker-compose.yaml
@@ -6,8 +6,11 @@ services:
ports:
- "${APP_PORT}:4002"
environment:
- SELF_HOSTED: 1
+ SELF_HOSTED: 1
+ CLOUD: 1
COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984
+ WORKER_URL: http://worker-service:4003
+ HOSTING_KEY: ${HOSTING_KEY}
BUDIBASE_ENVIRONMENT: ${BUDIBASE_ENVIRONMENT}
PORT: 4002
JWT_SECRET: ${JWT_SECRET}
@@ -20,14 +23,13 @@ services:
- "${WORKER_PORT}:4003"
environment:
SELF_HOSTED: 1,
- DEPLOYMENT_API_KEY: ${WORKER_API_KEY}
PORT: 4003
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
RAW_MINIO_URL: http://minio-service:9000
COUCH_DB_USERNAME: ${COUCH_DB_USER}
COUCH_DB_PASSWORD: ${COUCH_DB_PASSWORD}
- RAW_COUCH_DB_URL: http://couchdb-service:5984
+ COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984
SELF_HOST_KEY: ${HOSTING_KEY}
depends_on:
- minio-service
diff --git a/hosting/hosting.properties b/hosting/hosting.properties
index 2ef83543a4..ad047a3826 100644
--- a/hosting/hosting.properties
+++ b/hosting/hosting.properties
@@ -12,7 +12,6 @@ MINIO_ACCESS_KEY=budibase
MINIO_SECRET_KEY=budibase
COUCH_DB_PASSWORD=budibase
COUCH_DB_USER=budibase
-WORKER_API_KEY=budibase
# This section contains variables that do not need to be altered under normal circumstances
APP_PORT=4002
diff --git a/package-lock.json b/package-lock.json
index 9a1f0055cb..40073784fd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -615,6 +615,17 @@
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"make-fetch-happen": {
@@ -1004,6 +1015,17 @@
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"make-fetch-happen": {
@@ -1087,6 +1109,17 @@
"npmlog": "^4.1.2",
"path-exists": "^3.0.0",
"rimraf": "^2.6.2"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"@lerna/run": {
@@ -1900,6 +1933,17 @@
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"cache-base": {
@@ -2494,6 +2538,17 @@
"mkdirp": "^0.5.1",
"rimraf": "^2.5.4",
"run-queue": "^1.0.0"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"copy-descriptor": {
@@ -3394,6 +3449,17 @@
"flatted": "^2.0.0",
"rimraf": "2.6.3",
"write": "1.0.3"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"flatted": {
@@ -3767,6 +3833,12 @@
"pump": "^3.0.0"
}
},
+ "get-them-args": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz",
+ "integrity": "sha1-dKILqKSr7OWuGZrQPyvMaP38m6U=",
+ "dev": true
+ },
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -4354,9 +4426,9 @@
"dev": true
},
"ini": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"dev": true
},
"init-package-json": {
@@ -4829,6 +4901,16 @@
"verror": "1.10.0"
}
},
+ "kill-port": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/kill-port/-/kill-port-1.6.1.tgz",
+ "integrity": "sha512-un0Y55cOM7JKGaLnGja28T38tDDop0AQ8N0KlAdyh+B1nmMoX8AnNmqPNZbS3mUMgiST51DCVqmbFT1gNJpVNw==",
+ "dev": true,
+ "requires": {
+ "get-them-args": "1.3.2",
+ "shell-exec": "1.0.2"
+ }
+ },
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -5370,6 +5452,17 @@
"mkdirp": "^0.5.1",
"rimraf": "^2.5.4",
"run-queue": "^1.0.3"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
}
},
"ms": {
@@ -5469,6 +5562,15 @@
"which": "1"
},
"dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
@@ -5966,6 +6068,15 @@
"which": "^1.3.1"
},
"dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@@ -6192,13 +6303,10 @@
}
},
"prettier-plugin-svelte": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-0.7.0.tgz",
- "integrity": "sha512-SuZSeMh48rx42kCFEpI/xE1XgjxQcS3r22Yo7jIhBYRhwbAa8laNxiIHsfeWWkX8BdyELkEayaTQp4ricckwTQ==",
- "dev": true,
- "requires": {
- "tslib": "^1.9.3"
- }
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-1.4.2.tgz",
+ "integrity": "sha512-O9VsNwII+raTG8QPoQWouk5ABQy/hmLm4dZ2eqJ7DPnbO35A+BxMSjlfqkw0cNP+UcbykHFYU8zNXm93ytWP9g==",
+ "dev": true
},
"process-nextick-args": {
"version": "2.0.1",
@@ -6603,9 +6711,9 @@
"dev": true
},
"rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
@@ -6733,6 +6841,12 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
+ "shell-exec": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz",
+ "integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==",
+ "dev": true
+ },
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@@ -7213,9 +7327,9 @@
}
},
"svelte": {
- "version": "3.29.0",
- "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.29.0.tgz",
- "integrity": "sha512-f+A65eyOQ5ujETLy+igNXtlr6AEjAQLYd1yJE1VwNiXMQO5Z/Vmiy3rL+zblV/9jd7rtTTWqO1IcuXsP2Qv0OA==",
+ "version": "3.31.2",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.31.2.tgz",
+ "integrity": "sha512-TxZGrXzX2ggFH3BIKY5fmbeMdJuZrMIMDYPMX6R9255bueuYIuVaBQSLUeY2oD7W4IdeqRZiAVGCjDw2POKBRA==",
"dev": true
},
"table": {
diff --git a/package.json b/package.json
index fd601dd099..37efca51ba 100644
--- a/package.json
+++ b/package.json
@@ -34,8 +34,5 @@
"test:e2e": "lerna run cy:test",
"test:e2e:ci": "lerna run cy:ci",
"build:docker": "cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -"
- },
- "dependencies": {
- "@fortawesome/fontawesome": "^1.1.8"
}
}
diff --git a/packages/builder/package.json b/packages/builder/package.json
index 32601d97dd..f1c91e9e7c 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -63,14 +63,14 @@
}
},
"dependencies": {
- "@budibase/bbui": "^1.52.4",
+ "@budibase/bbui": "^1.54.0",
"@budibase/client": "^0.5.3",
"@budibase/colorpicker": "^1.0.1",
"@budibase/svelte-ag-grid": "^0.0.16",
- "@fortawesome/fontawesome-free": "^5.14.0",
"@sentry/browser": "5.19.1",
"@svelteschool/svelte-forms": "^0.7.0",
"britecharts": "^2.16.0",
+ "codemirror": "^5.59.0",
"d3-selection": "^1.4.1",
"deepmerge": "^4.2.2",
"fast-sort": "^2.2.0",
diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js
index 7d3f390220..6b114891b0 100644
--- a/packages/builder/src/builderStore/dataBinding.js
+++ b/packages/builder/src/builderStore/dataBinding.js
@@ -10,9 +10,10 @@ const CAPTURE_VAR_INSIDE_MUSTACHE = /{{([^}]+)}}/g
* Gets all bindable data context fields and instance fields.
*/
export const getBindableProperties = (rootComponent, componentId) => {
- const bindableContexts = getBindableContexts(rootComponent, componentId)
- const bindableComponents = getBindableComponents(rootComponent)
- return [...bindableContexts, ...bindableComponents]
+ const contextBindings = getContextBindings(rootComponent, componentId)
+ const queryBindings = getQueryBindings(rootComponent, componentId)
+ const componentBindings = getComponentBindings(rootComponent)
+ return [...contextBindings, ...queryBindings, componentBindings]
}
/**
@@ -71,11 +72,10 @@ export const getDatasourceForProvider = component => {
* Gets all bindable data contexts. These are fields of schemas of data contexts
* provided by data provider components, such as lists or row detail components.
*/
-export const getBindableContexts = (rootComponent, componentId) => {
- const dataProviders = getDataProviderComponents(rootComponent, componentId)
-
+export const getContextBindings = (rootComponent, componentId) => {
// Extract any components which provide data contexts
- let contexts = []
+ const dataProviders = getDataProviderComponents(rootComponent, componentId)
+ let contextBindings = []
dataProviders.forEach(component => {
const datasource = getDatasourceForProvider(component)
if (!datasource) {
@@ -99,7 +99,7 @@ export const getBindableContexts = (rootComponent, componentId) => {
runtimeBoundKey = `${key}_first`
}
- contexts.push({
+ contextBindings.push({
type: "context",
runtimeBinding: `${component._id}.${runtimeBoundKey}`,
readableBinding: `${component._instanceName}.${table.name}.${key}`,
@@ -110,14 +110,14 @@ export const getBindableContexts = (rootComponent, componentId) => {
})
})
})
- return contexts
+ return contextBindings
}
/**
* Gets all bindable components. These are form components which allow their
* values to be bound to.
*/
-export const getBindableComponents = rootComponent => {
+export const getComponentBindings = rootComponent => {
if (!rootComponent) {
return []
}
@@ -137,6 +137,47 @@ export const getBindableComponents = rootComponent => {
})
}
+/**
+ * Gets all bindable query fields. These are fields of schemas of data contexts
+ * provided by data provider components, such as lists or row detail components.
+ */
+export const getQueryBindings = (rootComponent, componentId) => {
+ // Extract any components which provide data contexts
+ const dataProviders = getDataProviderComponents(rootComponent, componentId)
+ const queries = get(backendUiStore).queries
+ let queryBindings = []
+ dataProviders.forEach(component => {
+ const datasource = getDatasourceForProvider(component)
+ if (!datasource) {
+ return
+ }
+
+ // Find a query for this table ID
+ const queryId = datasource.tableId
+ const query = queries.find(query => query._id === queryId)
+ const schema = query?.schema
+ if (!schema) {
+ return
+ }
+
+ // Add all schema fields as bindable values
+ const keys = Object.keys(schema).sort()
+ keys.forEach(key => {
+ const fieldSchema = schema[key]
+ queryBindings.push({
+ type: "context",
+ fieldSchema,
+ runtimeBinding: `${component._id}.${key}`,
+ readableBinding: `${component._instanceName}.${query.name}.${key}`,
+ providerId: component._id,
+ tableId: datasource.tableId,
+ field: key,
+ })
+ })
+ })
+ return queryBindings
+}
+
/**
* Gets a schema for a datasource object.
*/
diff --git a/packages/builder/src/builderStore/store/backend.js b/packages/builder/src/builderStore/store/backend.js
index 5592488590..0a235dd9a0 100644
--- a/packages/builder/src/builderStore/store/backend.js
+++ b/packages/builder/src/builderStore/store/backend.js
@@ -7,6 +7,9 @@ const INITIAL_BACKEND_UI_STATE = {
views: [],
users: [],
roles: [],
+ datasources: [],
+ queries: [],
+ integrations: {},
selectedDatabase: {},
selectedTable: {},
draftTable: {},
@@ -21,9 +24,19 @@ export const getBackendUiStore = () => {
select: async db => {
const tablesResponse = await api.get(`/api/tables`)
const tables = await tablesResponse.json()
+ const datasourcesResponse = await api.get(`/api/datasources`)
+ const datasources = await datasourcesResponse.json()
+ const queriesResponse = await api.get(`/api/queries`)
+ const queries = await queriesResponse.json()
+ const integrationsResponse = await api.get("/api/integrations")
+ const integrations = await integrationsResponse.json()
+
store.update(state => {
state.selectedDatabase = db
state.tables = tables
+ state.datasources = datasources
+ state.queries = queries
+ state.integrations = integrations
return state
})
},
@@ -45,6 +58,107 @@ export const getBackendUiStore = () => {
return state
}),
},
+ datasources: {
+ fetch: async () => {
+ const response = await api.get(`/api/datasources`)
+ const json = await response.json()
+ store.update(state => {
+ state.datasources = json
+ return state
+ })
+ return json
+ },
+ select: async datasourceId => {
+ store.update(state => {
+ state.selectedDatasourceId = datasourceId
+ state.selectedQueryId = null
+ return state
+ })
+ },
+ save: async datasource => {
+ const response = await api.post("/api/datasources", datasource)
+ const json = await response.json()
+ store.update(state => {
+ const currentIdx = state.datasources.findIndex(
+ ds => ds._id === json._id
+ )
+
+ if (currentIdx >= 0) {
+ state.datasources.splice(currentIdx, 1, json)
+ } else {
+ state.datasources.push(json)
+ }
+
+ state.datasources = state.datasources
+ state.selectedDatasourceId = json._id
+ return state
+ })
+ return json
+ },
+ delete: async datasource => {
+ await api.delete(
+ `/api/datasources/${datasource._id}/${datasource._rev}`
+ )
+ store.update(state => {
+ state.datasources = state.datasources.filter(
+ existing => existing._id !== datasource._id
+ )
+ state.selectedDatasourceId = null
+ return state
+ })
+ },
+ },
+ queries: {
+ fetch: async () => {
+ const response = await api.get(`/api/queries`)
+ const json = await response.json()
+ store.update(state => {
+ state.queries = json
+ return state
+ })
+ return json
+ },
+ save: async (datasourceId, query) => {
+ query.datasourceId = datasourceId
+ const response = await api.post(`/api/queries`, query)
+ const json = await response.json()
+ store.update(state => {
+ const currentIdx = state.queries.findIndex(
+ query => query._id === json._id
+ )
+
+ if (currentIdx >= 0) {
+ state.queries.splice(currentIdx, 1, json)
+ } else {
+ state.queries.push(json)
+ }
+
+ state.queries = state.queries
+ state.selectedQueryId = json._id
+ return state
+ })
+ return json
+ },
+ select: query =>
+ store.update(state => {
+ state.selectedDatasourceId = query.datasourceId
+ state.selectedQueryId = query._id
+ return state
+ }),
+ delete: async query => {
+ await api.delete(`/api/queries/${query._id}/${query._rev}`)
+ store.update(state => {
+ state.queries = state.queries.filter(
+ existing => existing._id !== query._id
+ )
+ if (state.selectedQueryId === query._id) {
+ state.selectedQueryId = null
+ }
+
+ return state
+ })
+ },
+ },
tables: {
fetch: async () => {
const tablesResponse = await api.get(`/api/tables`)
diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js
index 80b572c8e2..340e2829aa 100644
--- a/packages/builder/src/builderStore/store/frontend.js
+++ b/packages/builder/src/builderStore/store/frontend.js
@@ -19,6 +19,7 @@ import { uuid } from "../uuid"
const INITIAL_FRONTEND_STATE = {
apps: [],
name: "",
+ url: "",
description: "",
layouts: [],
screens: [],
@@ -48,6 +49,7 @@ export const getFrontendStore = () => {
name: application.name,
description: application.description,
appId: application._id,
+ url: application.url,
layouts,
screens,
hasAppPackage: true,
diff --git a/packages/builder/src/builderStore/store/hosting.js b/packages/builder/src/builderStore/store/hosting.js
index 36067773b5..f180d4157a 100644
--- a/packages/builder/src/builderStore/store/hosting.js
+++ b/packages/builder/src/builderStore/store/hosting.js
@@ -1,13 +1,16 @@
import { writable } from "svelte/store"
-import api from "../api"
+import api, { get } from "../api"
-const INITIAL_BACKEND_UI_STATE = {
+const INITIAL_HOSTING_UI_STATE = {
hostingInfo: {},
appUrl: "",
+ deployedApps: {},
+ deployedAppNames: [],
+ deployedAppUrls: [],
}
export const getHostingStore = () => {
- const store = writable({ ...INITIAL_BACKEND_UI_STATE })
+ const store = writable({ ...INITIAL_HOSTING_UI_STATE })
store.actions = {
fetch: async () => {
const responses = await Promise.all([
@@ -33,6 +36,16 @@ export const getHostingStore = () => {
return state
})
},
+ fetchDeployedApps: async () => {
+ let deployments = await (await get("/api/hosting/apps")).json()
+ store.update(state => {
+ state.deployedApps = deployments
+ state.deployedAppNames = Object.values(deployments).map(app => app.name)
+ state.deployedAppUrls = Object.values(deployments).map(app => app.url)
+ return state
+ })
+ return deployments
+ },
}
return store
}
diff --git a/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte b/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
index 5ea1d64e51..e00fb92e27 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
@@ -50,7 +50,10 @@
function addBlockToAutomation(stepId, blockDefinition) {
const newBlock = $automationStore.selectedAutomation.constructBlock(
- selectedTab, stepId, blockDefinition)
+ selectedTab,
+ stepId,
+ blockDefinition
+ )
automationStore.actions.addBlockToAutomation(newBlock)
closePopover()
if (stepId === "WEBHOOK") {
diff --git a/packages/builder/src/components/automation/SetupPanel/BindableInput.svelte b/packages/builder/src/components/automation/SetupPanel/BindableInput.svelte
index 76624abd06..b1521bee20 100644
--- a/packages/builder/src/components/automation/SetupPanel/BindableInput.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/BindableInput.svelte
@@ -1,9 +1,13 @@
diff --git a/packages/builder/src/components/automation/SetupPanel/GenericBindingPopover.svelte b/packages/builder/src/components/automation/SetupPanel/GenericBindingPopover.svelte
index 0b53ab91ad..a326f60a08 100644
--- a/packages/builder/src/components/automation/SetupPanel/GenericBindingPopover.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/GenericBindingPopover.svelte
@@ -50,7 +50,9 @@
{binding.label}
{binding.type}
-
{binding.description}
+
+ {binding.description || ''}
+
{/each}
{/each}
diff --git a/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte b/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte
index 51c105e9f4..8855fb6895 100644
--- a/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte
@@ -36,9 +36,7 @@
-
-
-
+
{#each fieldsArray as field}
@@ -57,13 +55,11 @@
datetime
- removeField(field.name)} />
-
-
{/each}
-
diff --git a/packages/builder/src/components/backend/DataTable/ExternalDataSourceTable.svelte b/packages/builder/src/components/backend/DataTable/ExternalDataSourceTable.svelte
new file mode 100644
index 0000000000..9be0481c58
--- /dev/null
+++ b/packages/builder/src/components/backend/DataTable/ExternalDataSourceTable.svelte
@@ -0,0 +1,28 @@
+
+
+{#if error}
+ {error}
+{/if}
+
+
+
diff --git a/packages/builder/src/components/backend/DataTable/Table.svelte b/packages/builder/src/components/backend/DataTable/Table.svelte
index 1e6c53bd11..070ebec080 100644
--- a/packages/builder/src/components/backend/DataTable/Table.svelte
+++ b/packages/builder/src/components/backend/DataTable/Table.svelte
@@ -199,7 +199,6 @@
align-items: stretch;
}
.grid-wrapper :global(> *) {
- height: auto;
flex: 1 1 auto;
}
:global(.grid-wrapper) {
@@ -236,6 +235,7 @@
}
:global(.ag-filter) {
+ background: var(--background);
padding: var(--spacing-s);
outline: none;
box-sizing: border-box;
diff --git a/packages/builder/src/components/backend/DataTable/api.js b/packages/builder/src/components/backend/DataTable/api.js
index 629405a9fc..91ebc19b26 100644
--- a/packages/builder/src/components/backend/DataTable/api.js
+++ b/packages/builder/src/components/backend/DataTable/api.js
@@ -23,5 +23,10 @@ export async function fetchDataForView(view) {
const FETCH_ROWS_URL = `/api/views/${view.name}`
const response = await api.get(FETCH_ROWS_URL)
- return await response.json()
+ const json = await response.json()
+
+ if (response.status !== 200) {
+ throw new Error(json.message)
+ }
+ return json
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
new file mode 100644
index 0000000000..aa8954cb8d
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
@@ -0,0 +1,63 @@
+
+
+{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
+
+ {#each $backendUiStore.datasources as datasource, idx}
+
0}
+ text={datasource.name}
+ selected={$backendUiStore.selectedDatasourceId === datasource._id}
+ on:click={() => selectDatasource(datasource)}>
+
+
+
+
+
+ {#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
+
onClickQuery(query)}>
+
+
+ {/each}
+ {/each}
+
+{/if}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/ListItem.svelte b/packages/builder/src/components/backend/DatasourceNavigator/ListItem.svelte
new file mode 100644
index 0000000000..f148eaf8b2
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/ListItem.svelte
@@ -0,0 +1,55 @@
+
+
+
+
+ {title}
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte
new file mode 100644
index 0000000000..79bb951c01
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte
new file mode 100644
index 0000000000..dbe289caba
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/index.svelte
@@ -0,0 +1,97 @@
+
+
+
+
+ {#each Object.keys(integrations) as integrationType}
+
selectIntegration(integrationType)}>
+
+ {integrationType}
+
+ {/each}
+
+
+ {#if schema}
+ {#each Object.keys(schema) as configKey}
+
+
+ {/each}
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Airtable.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Airtable.svelte
new file mode 100644
index 0000000000..ce689df205
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Airtable.svelte
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/CouchDB.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/CouchDB.svelte
new file mode 100644
index 0000000000..1ed737fc81
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/CouchDB.svelte
@@ -0,0 +1,35 @@
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/DynamoDB.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/DynamoDB.svelte
new file mode 100644
index 0000000000..1ec061ca20
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/DynamoDB.svelte
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Elasticsearch.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Elasticsearch.svelte
new file mode 100644
index 0000000000..20df3bd620
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Elasticsearch.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/MongoDB.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/MongoDB.svelte
new file mode 100644
index 0000000000..823ec3a2fa
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/MongoDB.svelte
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Postgres.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Postgres.svelte
new file mode 100644
index 0000000000..56268f75b3
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Postgres.svelte
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/S3.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/S3.svelte
new file mode 100644
index 0000000000..23168a3501
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/S3.svelte
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/SQLServer.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/SQLServer.svelte
new file mode 100644
index 0000000000..6aa2fcafca
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/SQLServer.svelte
@@ -0,0 +1,391 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js b/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js
new file mode 100644
index 0000000000..afedb9e78f
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js
@@ -0,0 +1,19 @@
+import Postgres from "./Postgres.svelte"
+import DynamoDB from "./DynamoDB.svelte"
+import Elasticsearch from "./Elasticsearch.svelte"
+import MongoDB from "./MongoDB.svelte"
+import CouchDB from "./CouchDB.svelte"
+import S3 from "./S3.svelte"
+import Airtable from "./Airtable.svelte"
+import SqlServer from "./SQLServer.svelte"
+
+export default {
+ POSTGRES: Postgres,
+ DYNAMODB: DynamoDB,
+ MONGODB: MongoDB,
+ ELASTICSEARCH: Elasticsearch,
+ COUCHDB: CouchDB,
+ SQL_SERVER: SqlServer,
+ S3: S3,
+ AIRTABLE: Airtable,
+}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
new file mode 100644
index 0000000000..a41cbd2466
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
@@ -0,0 +1,61 @@
+
+
+
+
+ Source
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateQueryModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateQueryModal.svelte
new file mode 100644
index 0000000000..6a98313335
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateQueryModal.svelte
@@ -0,0 +1,61 @@
+
+
+
+
+ Create Integrated Table from External Source
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte
new file mode 100644
index 0000000000..1bbaddf5ef
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte
@@ -0,0 +1,87 @@
+
+
+
+
+ Are you sure you wish to delete the datasource
+ {datasource.name}?
+ This action cannot be undone.
+
+
+
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte
new file mode 100644
index 0000000000..92a541ac1d
--- /dev/null
+++ b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte
@@ -0,0 +1,84 @@
+
+
+
+
+ Are you sure you wish to delete this query? This action cannot be undone.
+
+
+
diff --git a/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte b/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte
index 810d7960f5..293f52b487 100644
--- a/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte
@@ -5,7 +5,7 @@
import api from "builderStore/api"
const BYTES_IN_MB = 1000000
- const FILE_SIZE_LIMIT = BYTES_IN_MB * 1
+ const FILE_SIZE_LIMIT = BYTES_IN_MB * 5
export let files = []
export let dataImport = {
diff --git a/packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte b/packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte
index 30a0568e8e..3719d62c62 100644
--- a/packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/TableNavigator.svelte
@@ -2,13 +2,11 @@
import { goto } from "@sveltech/routify"
import { backendUiStore } from "builderStore"
import { TableNames } from "constants"
- import CreateTableModal from "./modals/CreateTableModal.svelte"
import EditTablePopover from "./popovers/EditTablePopover.svelte"
import EditViewPopover from "./popovers/EditViewPopover.svelte"
- import { Modal } from "@budibase/bbui"
+ import { Switcher } from "@budibase/bbui"
import NavItem from "components/common/NavItem.svelte"
- let modal
$: selectedView =
$backendUiStore.selectedView && $backendUiStore.selectedView.name
@@ -34,10 +32,6 @@
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
-
-
Tables
-
-
{#each $backendUiStore.tables as table, idx}
{/if}
-
-
-
-
-
diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte
index 3338072ec2..faadbdeb49 100644
--- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte
@@ -2,7 +2,14 @@
import { goto } from "@sveltech/routify"
import { backendUiStore, store } from "builderStore"
import { notifier } from "builderStore/store/notifications"
- import { Input, Label, ModalContent, Toggle } from "@budibase/bbui"
+ import {
+ Input,
+ Label,
+ ModalContent,
+ Button,
+ Spacer,
+ Toggle,
+ } from "@budibase/bbui"
import TableDataImport from "../TableDataImport.svelte"
import analytics from "analytics"
import screenTemplates from "builderStore/store/screenTemplates"
diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte
index 8eca07b1b0..972427328b 100644
--- a/packages/builder/src/components/common/NavItem.svelte
+++ b/packages/builder/src/components/common/NavItem.svelte
@@ -29,6 +29,8 @@
{/if}
+
+
{#if icon}
{/if}
diff --git a/packages/builder/src/components/deploy/DeploymentHistory.svelte b/packages/builder/src/components/deploy/DeploymentHistory.svelte
index fe95b1369f..8061e08ed1 100644
--- a/packages/builder/src/components/deploy/DeploymentHistory.svelte
+++ b/packages/builder/src/components/deploy/DeploymentHistory.svelte
@@ -6,7 +6,7 @@
import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications"
import CreateWebhookDeploymentModal from "./CreateWebhookDeploymentModal.svelte"
- import { hostingStore } from "builderStore"
+ import { store, hostingStore } from "builderStore"
const DeploymentStatus = {
SUCCESS: "SUCCESS",
@@ -36,7 +36,9 @@
let errorReason
let poll
let deployments = []
- let deploymentUrl = `${$hostingStore.appUrl}/${appId}`
+ let urlComponent =
+ $hostingStore.hostingInfo.type === "self" ? $store.url : `/${appId}`
+ let deploymentUrl = `${$hostingStore.appUrl}${urlComponent}`
const formatDate = (date, format) =>
Intl.DateTimeFormat("en-GB", DATE_OPTIONS[format]).format(date)
diff --git a/packages/builder/src/components/design/AppPreview/iframeTemplate.html b/packages/builder/src/components/design/AppPreview/iframeTemplate.html
index cec0b789da..49df3b5c0b 100644
--- a/packages/builder/src/components/design/AppPreview/iframeTemplate.html
+++ b/packages/builder/src/components/design/AppPreview/iframeTemplate.html
@@ -1,6 +1,7 @@
+
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/BindingDropdown.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/BindingDropdown.svelte
deleted file mode 100644
index 018691ee51..0000000000
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/BindingDropdown.svelte
+++ /dev/null
@@ -1,142 +0,0 @@
-
-
-
-
- {#if hasBindableProperties}
- {#if context}
-
Datasources
-
-
- {#each context as { readableBinding }}
- addToText(readableBinding)}>
- {readableBinding}
-
- {/each}
-
- {/if}
- {#if instance}
-
-
Components
-
-
- {#each instance as { readableBinding }}
- addToText(readableBinding)}>
- {readableBinding}
-
- {/each}
-
- {/if}
- {:else}
-
There aren't any bindable properties available.
- {/if}
-
-
-
Data Binding
-
-
- Binding connects one piece of data to another and makes it dynamic. Click
- the objects on the left to add them to the extbox.
-
-
-
-
-
-
-
-
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte
new file mode 100644
index 0000000000..5dd8f8a423
--- /dev/null
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+ {#each actionTypes as actionType}
+
+ {actionType.name}
+
+ {/each}
+
+
+
+
+ {#if actions && actions.length > 0}
+ {#each actions as action, index}
+
+
+ deleteAction(index)} />
+
+ {/each}
+ {/if}
+
+
+ {#if selectedAction}
+
+
+
+ {/if}
+
+
+
+
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditorModal.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditorModal.svelte
index d92ebed33e..ac976317ec 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditorModal.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditorModal.svelte
@@ -47,32 +47,36 @@
await createAutomation(action.parameters)
}
}
- dispatch("change", actions)
+ dispatch("change", actions)
}
- // called by the parent modal when actions are saved
+ // called by the parent modal when actions are saved
const createAutomation = async parameters => {
if (parameters.automationId || !parameters.newAutomationName) return
- await automationStore.actions.create({name: parameters.newAutomationName})
+ await automationStore.actions.create({ name: parameters.newAutomationName })
const appActionDefinition = $automationStore.blockDefinitions.TRIGGER.APP
const newBlock = $automationStore.selectedAutomation.constructBlock(
- "TRIGGER", "APP", appActionDefinition)
-
+ "TRIGGER",
+ "APP",
+ appActionDefinition
+ )
newBlock.inputs = {
- fields: Object.entries(parameters.fields).reduce((fields, [key, value]) => {
- fields[key] = value.type
- return fields
- }, {})
+ fields: Object.entries(parameters.fields).reduce(
+ (fields, [key, value]) => {
+ fields[key] = value.type
+ return fields
+ },
+ {}
+ ),
}
automationStore.actions.addBlockToAutomation(newBlock)
- await automationStore.actions.save(
- $automationStore.selectedAutomation)
+ await automationStore.actions.save($automationStore.selectedAutomation)
parameters.automationId = $automationStore.selectedAutomation.automation._id
delete parameters.newAutomationName
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte
index 044d0ca5d5..9340ec4c28 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte
@@ -1,17 +1,68 @@
-Define Actions
-
-
-
-
+Define Actions
+
+
+ Save
+
+
+
+
+
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte
new file mode 100644
index 0000000000..61b0edda1f
--- /dev/null
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte
@@ -0,0 +1,69 @@
+
+
+
+
Datasource
+
+
+ {#each $backendUiStore.datasources as datasource}
+ {datasource.name}
+ {/each}
+
+
+
+
+ {#if parameters.datasourceId}
+
Query
+
+
+ {#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
+ {query.name}
+ {/each}
+
+ {/if}
+
+
+
+ {#if query?.parameters?.length > 0}
+
+ {#if query.fields.sql}
+
{query.fields.queryString}
+ {/if}
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte
index 3addd55ea0..3f61bbcb7e 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte
@@ -3,9 +3,16 @@
import { automationStore } from "builderStore"
import SaveFields from "./SaveFields.svelte"
+ const AUTOMATION_STATUS = {
+ NEW: "new",
+ EXISTING: "existing",
+ }
+
export let parameters = {}
- let newOrExisting = parameters.automationId ? "existing" : "new"
+ let automationStatus = parameters.automationId
+ ? AUTOMATION_STATUS.EXISTING
+ : AUTOMATION_STATUS.NEW
$: automations = $automationStore.automations
.filter(a => a.definition.trigger?.stepId === "APP")
@@ -33,12 +40,12 @@
}
const setNew = () => {
- newOrExisting = "new"
+ automationStatus = AUTOMATION_STATUS.NEW
parameters.automationId = undefined
}
const setExisting = () => {
- newOrExisting = "existing"
+ automationStatus = AUTOMATION_STATUS.EXISTING
parameters.newAutomationName = ""
}
@@ -47,8 +54,8 @@
Create a new automation
@@ -57,8 +64,8 @@
Use an existing automation
@@ -66,7 +73,7 @@
Automation
- {#if newOrExisting === 'existing'}
+ {#if automationStatus === AUTOMATION_STATUS.EXISTING}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js
index 1bb0ab4d00..677c646728 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js
@@ -1,6 +1,7 @@
import NavigateTo from "./NavigateTo.svelte"
import SaveRow from "./SaveRow.svelte"
import DeleteRow from "./DeleteRow.svelte"
+import ExecuteQuery from "./ExecuteQuery.svelte"
import TriggerAutomation from "./TriggerAutomation.svelte"
// defines what actions are available, when adding a new one
@@ -21,6 +22,10 @@ export default [
name: "Navigate To",
component: NavigateTo,
},
+ {
+ name: "Execute Query",
+ component: ExecuteQuery,
+ },
{
name: "Trigger Automation",
component: TriggerAutomation,
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/IconSelect/IconSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/IconSelect/IconSelect.svelte
index fe3a029716..80c729af27 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/IconSelect/IconSelect.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/IconSelect/IconSelect.svelte
@@ -1,9 +1,15 @@
+
+
- {value && value.label ? value.label : 'Table / View'}
+ {value.label ? value.label : 'Table / View / Query'}
+{#if value.type === 'query'}
+
+
+
+ {
+ notifier.success('Query parameters saved.')
+ handleSelected(value)
+ drawer.hide()
+ }}>
+ Save
+
+
+
+
+
+ {#if value.parameters.length > 0}
+
query._id === value._id).parameters}
+ bindings={queryBindableProperties} />
+ {/if}
+
+
+{/if}
@@ -96,6 +157,20 @@
{/each}
+
+
+
+ Queries
+
+
+ {#each queries as query}
+ handleSelected(query)}>
+ {query.label}
+
+ {/each}
+
@@ -160,4 +235,23 @@
li:hover {
background-color: var(--grey-4);
}
+
+ .drawer-contents {
+ padding: var(--spacing-xl);
+ height: 40vh;
+ overflow-y: auto;
+ }
+
+ i {
+ margin-left: 5px;
+ display: flex;
+ align-items: center;
+ transition: all 0.2s;
+ }
+
+ i:hover {
+ transform: scale(1.1);
+ font-weight: 500;
+ cursor: pointer;
+ }
diff --git a/packages/builder/src/components/integration/QueryEditor.svelte b/packages/builder/src/components/integration/QueryEditor.svelte
new file mode 100644
index 0000000000..22cddb5606
--- /dev/null
+++ b/packages/builder/src/components/integration/QueryEditor.svelte
@@ -0,0 +1,162 @@
+
+
+
+
+
diff --git a/packages/builder/src/components/integration/QueryFieldsBuilder.svelte b/packages/builder/src/components/integration/QueryFieldsBuilder.svelte
new file mode 100644
index 0000000000..83a03c72d1
--- /dev/null
+++ b/packages/builder/src/components/integration/QueryFieldsBuilder.svelte
@@ -0,0 +1,56 @@
+
+
+
+
Data
+{#if schema.customisable}
+
+{/if}
+
+
diff --git a/packages/builder/src/components/integration/QueryParameterBuilder.svelte b/packages/builder/src/components/integration/QueryParameterBuilder.svelte
new file mode 100644
index 0000000000..1be4a9d1ce
--- /dev/null
+++ b/packages/builder/src/components/integration/QueryParameterBuilder.svelte
@@ -0,0 +1,88 @@
+
+
+
+ Parameters
+
+
Parameter Name
+
Default
+ {#if bindable}
+
Value
+ {:else}
+
+ {/if}
+ {#each parameters as parameter, idx}
+
+
+ {#if bindable}
+
onBindingChange(parameter.name, evt.detail)}
+ value={runtimeToReadableBinding(bindings, customParams[parameter.name])}
+ {bindings} />
+ {:else}
+ deleteQueryParameter(idx)} />
+ {/if}
+ {/each}
+
+ {#if !bindable}
+
+ Add Parameter
+
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte
new file mode 100644
index 0000000000..5ac3e550c1
--- /dev/null
+++ b/packages/builder/src/components/integration/QueryViewer.svelte
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+{#if shouldShowQueryConfig}
+
+
+
Query Name
+
+
+
+
+
+
+
+
+
+
+ Save
+
+ Run
+
+
+
+
+
+{/if}
+
+
diff --git a/packages/builder/src/components/integration/codemirror.js b/packages/builder/src/components/integration/codemirror.js
new file mode 100644
index 0000000000..434adc254b
--- /dev/null
+++ b/packages/builder/src/components/integration/codemirror.js
@@ -0,0 +1,10 @@
+import CodeMirror from "codemirror"
+import "codemirror/lib/codemirror.css"
+import "codemirror/theme/tomorrow-night-eighties.css"
+import "codemirror/theme/neo.css"
+import "codemirror/mode/sql/sql"
+import "codemirror/mode/css/css"
+import "codemirror/mode/handlebars/handlebars"
+import "codemirror/mode/javascript/javascript"
+
+export default CodeMirror
diff --git a/packages/builder/src/components/integration/index.svelte b/packages/builder/src/components/integration/index.svelte
new file mode 100644
index 0000000000..1f0aa30c49
--- /dev/null
+++ b/packages/builder/src/components/integration/index.svelte
@@ -0,0 +1,52 @@
+
+
+{#if editable}
+
+
+{/if}
+
+
Query
+
+
+{#if schema}
+ {#key query._id}
+ {#if schema.type === QueryTypes.SQL}
+
+ {:else if schema.type === QueryTypes.JSON}
+
+
+ {:else if schema.type === QueryTypes.FIELDS}
+
+ {/if}
+ {/key}
+{/if}
diff --git a/packages/builder/src/components/settings/tabs/General.svelte b/packages/builder/src/components/settings/tabs/General.svelte
index 809917f27d..9e9daf5f57 100644
--- a/packages/builder/src/components/settings/tabs/General.svelte
+++ b/packages/builder/src/components/settings/tabs/General.svelte
@@ -1,11 +1,20 @@