diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 68e71f4cf7..792191af7a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -68,5 +68,6 @@ jobs:
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}
- run: docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
- run: yarn build:docker
+ run: |
+ docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
+ yarn build:docker
diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml
index 32659ec53c..c4a6c669b3 100644
--- a/hosting/docker-compose.yaml
+++ b/hosting/docker-compose.yaml
@@ -9,7 +9,6 @@ services:
SELF_HOSTED: 1
COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984
BUDIBASE_ENVIRONMENT: ${BUDIBASE_ENVIRONMENT}
- LOGO_URL: ${LOGO_URL}
PORT: 4002
JWT_SECRET: ${JWT_SECRET}
depends_on:
@@ -43,6 +42,7 @@ services:
environment:
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
+ MINIO_BROWSER: "off"
command: server /data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
diff --git a/hosting/hosting.properties b/hosting/hosting.properties
index 5776f108e3..2ef83543a4 100644
--- a/hosting/hosting.properties
+++ b/hosting/hosting.properties
@@ -5,9 +5,6 @@ MAIN_PORT=10000
# This should be updated
HOSTING_KEY=budibase
-# This section contains customisation options
-LOGO_URL=https://logoipsum.com/logo/logo-15.svg
-
# This section contains all secrets pertaining to the system
# These should be updated
JWT_SECRET=testsecret
diff --git a/lerna.json b/lerna.json
index 1585b03a18..22963e707b 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "0.4.3",
+ "version": "0.5.3",
"npmClient": "yarn",
"packages": [
"packages/*"
diff --git a/packages/builder/package.json b/packages/builder/package.json
index 9d176926b0..073bbd5e9d 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
- "version": "0.4.3",
+ "version": "0.5.3",
"license": "AGPL-3.0",
"private": true,
"scripts": {
@@ -64,7 +64,7 @@
},
"dependencies": {
"@budibase/bbui": "^1.52.4",
- "@budibase/client": "^0.4.3",
+ "@budibase/client": "^0.5.3",
"@budibase/colorpicker": "^1.0.1",
"@budibase/svelte-ag-grid": "^0.0.16",
"@fortawesome/fontawesome-free": "^5.14.0",
diff --git a/packages/builder/src/builderStore/store/automation/Automation.js b/packages/builder/src/builderStore/store/automation/Automation.js
index cbdcabeccc..a9dce88258 100644
--- a/packages/builder/src/builderStore/store/automation/Automation.js
+++ b/packages/builder/src/builderStore/store/automation/Automation.js
@@ -56,4 +56,13 @@ export default class Automation {
steps.splice(stepIdx, 1)
this.automation.definition.steps = steps
}
+
+ constructBlock(type, stepId, blockDefinition) {
+ return {
+ ...blockDefinition,
+ inputs: blockDefinition.inputs || {},
+ stepId,
+ type,
+ }
+ }
}
diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js
index 3f0743aa1e..7a01bccfab 100644
--- a/packages/builder/src/builderStore/store/automation/index.js
+++ b/packages/builder/src/builderStore/store/automation/index.js
@@ -2,6 +2,7 @@ import { writable } from "svelte/store"
import api from "../../api"
import Automation from "./Automation"
import { cloneDeep } from "lodash/fp"
+import analytics from "analytics"
const automationActions = store => ({
fetch: async () => {
@@ -93,6 +94,9 @@ const automationActions = store => ({
state.selectedBlock = newBlock
return state
})
+ analytics.captureEvent("Added Automation Block", {
+ name: block.name,
+ })
},
deleteAutomationBlock: block => {
store.update(state => {
diff --git a/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte b/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
index de3e9660ad..5ea1d64e51 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
@@ -49,16 +49,9 @@
}
function addBlockToAutomation(stepId, blockDefinition) {
- const newBlock = {
- ...blockDefinition,
- inputs: blockDefinition.inputs || {},
- stepId,
- type: selectedTab,
- }
+ const newBlock = $automationStore.selectedAutomation.constructBlock(
+ selectedTab, stepId, blockDefinition)
automationStore.actions.addBlockToAutomation(newBlock)
- analytics.captureEvent("Added Automation Block", {
- name: blockDefinition.name,
- })
closePopover()
if (stepId === "WEBHOOK") {
webhookModal.show()
diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
index 7e26b2155e..5d3371ee7d 100644
--- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
@@ -1,6 +1,7 @@
+
+
+
+
+
+
+ {#each fieldsArray as field}
+
+
+
+
+ removeField(field.name)} />
+
+
+
+ {/each}
+
+
+
+
diff --git a/packages/builder/src/components/integration/QueryFieldsBuilder.svelte b/packages/builder/src/components/integration/QueryFieldsBuilder.svelte
index 24916ef170..dfcf03b5ba 100644
--- a/packages/builder/src/components/integration/QueryFieldsBuilder.svelte
+++ b/packages/builder/src/components/integration/QueryFieldsBuilder.svelte
@@ -7,6 +7,7 @@
Heading,
Select
} from "@budibase/bbui"
+ import Editor from "./QueryEditor.svelte"
export let fields = {}
export let schema
@@ -17,23 +18,8 @@
$: fieldKeys = Object.keys(fields)
$: schemaKeys = Object.keys(schema.fields)
- $: console.log({ fields, schema })
-
- function addField() {
- // Add the new field to custom fields for the query
- schema.fields[draftField.name] = {
- type: draftField.type
- }
- // reset the draft field
- draftField = {}
- }
-
- function removeField(field) {
- delete fields[field]
- fields = fields
-
- delete schema.fields[field]
- schema = schema
+ function updateCustomFields({ detail }) {
+ fields.customData = detail.value
}
@@ -46,38 +32,21 @@
type={schema.fields[field]?.type}
required={schema.fields[field]?.required}
bind:value={fields[field]} />
- {#if !schema.fields[field]?.required}
- removeField(field)} />
- {/if}
{/each}
-{#if schema.customisable && editable}
-
-
-
-
-
-
-
-
-
-
+
+{#if schema.customisable}
+
{/if}
\ No newline at end of file
diff --git a/packages/builder/src/components/integration/index.svelte b/packages/builder/src/components/integration/index.svelte
index 455f2fef40..fa56853d40 100644
--- a/packages/builder/src/components/integration/index.svelte
+++ b/packages/builder/src/components/integration/index.svelte
@@ -47,5 +47,5 @@
value={query.fields.json} />
{:else if schema.type === QueryTypes.FIELDS}
- {:else if schema.type === QueryTypes.LIST}LIST STUFF{/if}
+ {/if}
{/if}
diff --git a/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte b/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte
index dd28ad1c6e..55ec125773 100644
--- a/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte
+++ b/packages/builder/src/components/userInterface/EventsEditor/EventEditor.svelte
@@ -8,8 +8,10 @@
} from "@budibase/bbui"
import { AddIcon, ArrowDownIcon } from "components/common/Icons/"
import actionTypes from "./actions"
+ import { createEventDispatcher } from "svelte"
+ import { automationStore } from "builderStore"
- const eventTypeKey = "##eventHandlerType"
+ const EVENT_TYPE_KEY = "##eventHandlerType"
export let event
@@ -17,16 +19,10 @@
let addActionDropdown
let selectedAction
- let draftEventHandler = { parameters: [] }
-
$: actions = event || []
$: selectedActionComponent =
selectedAction &&
- actionTypes.find(t => t.name === selectedAction[eventTypeKey]).component
-
- const updateEventHandler = (updatedHandler, index) => {
- actions[index] = updatedHandler
- }
+ actionTypes.find(t => t.name === selectedAction[EVENT_TYPE_KEY]).component
const deleteAction = index => {
actions.splice(index, 1)
@@ -36,7 +32,7 @@
const addAction = actionType => () => {
const newAction = {
parameters: {},
- [eventTypeKey]: actionType.name,
+ [EVENT_TYPE_KEY]: actionType.name,
}
actions.push(newAction)
selectedAction = newAction
@@ -79,7 +75,7 @@
{
+ const saveEventData = async () => {
+ // any automations that need created from event triggers
+ const automationsToCreate = value.filter(
+ action => action["##eventHandlerType"] === "Trigger Automation"
+ )
+ automationsToCreate.forEach(action => createAutomation(action.parameters))
+
dispatch("change", value)
notifier.success("Component actions 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 })
+
+ const appActionDefinition = $automationStore.blockDefinitions.TRIGGER.APP
+
+ const newBlock = $automationStore.selectedAutomation.constructBlock(
+ "TRIGGER",
+ "APP",
+ appActionDefinition
+ )
+
+ newBlock.inputs = {
+ 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)
+
+ parameters.automationId = $automationStore.selectedAutomation.automation._id
+ delete parameters.newAutomationName
+ }
diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte
index 3fe85cbfda..71d0ddf17f 100644
--- a/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte
+++ b/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte
@@ -1,6 +1,6 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if automationStatus === AUTOMATION_STATUS.EXISTING}
+
+ {:else}
+
+ {/if}
+
+
+
+
+
+
diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/index.js b/packages/builder/src/components/userInterface/EventsEditor/actions/index.js
index f9645b6caa..677c646728 100644
--- a/packages/builder/src/components/userInterface/EventsEditor/actions/index.js
+++ b/packages/builder/src/components/userInterface/EventsEditor/actions/index.js
@@ -2,6 +2,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
// the component is the setup panel for the action
@@ -25,4 +26,8 @@ export default [
name: "Execute Query",
component: ExecuteQuery,
},
+ {
+ name: "Trigger Automation",
+ component: TriggerAutomation,
+ },
]
diff --git a/packages/client/package.json b/packages/client/package.json
index 55ad2531ff..9a40bea639 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/client",
- "version": "0.4.3",
+ "version": "0.5.3",
"license": "MPL-2.0",
"main": "dist/budibase-client.js",
"module": "dist/budibase-client.js",
@@ -15,7 +15,7 @@
"svelte-spa-router": "^3.0.5"
},
"devDependencies": {
- "@budibase/standard-components": "^0.4.3",
+ "@budibase/standard-components": "^0.5.3",
"@rollup/plugin-commonjs": "^16.0.0",
"@rollup/plugin-node-resolve": "^10.0.0",
"fs-extra": "^8.1.0",
@@ -29,5 +29,5 @@
"svelte": "^3.30.0",
"svelte-jester": "^1.0.6"
},
- "gitHead": "e4e053cb6ff9a0ddc7115b44ccaa24b8ec41fb9a"
+ "gitHead": "62ebf3cedcd7e9b2494b4f8cbcfb90927609b491"
}
diff --git a/packages/client/src/api/automations.js b/packages/client/src/api/automations.js
new file mode 100644
index 0000000000..c163ffee82
--- /dev/null
+++ b/packages/client/src/api/automations.js
@@ -0,0 +1,10 @@
+import API from "./api"
+/**
+ * Executes an automation. Must have "App Action" trigger.
+ */
+export const triggerAutomation = async (automationId, fields) => {
+ return await API.post({
+ url: `/api/automations/${automationId}/trigger`,
+ body: { fields },
+ })
+}
diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js
index 5c05ee15ae..d83ede61f0 100644
--- a/packages/client/src/api/index.js
+++ b/packages/client/src/api/index.js
@@ -8,3 +8,4 @@ export * from "./relationships"
export * from "./routes"
export * from "./queries"
export * from "./app"
+export * from "./automations"
diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js
index 4d0ff98dfb..357dfdaa33 100644
--- a/packages/client/src/utils/buttonActions.js
+++ b/packages/client/src/utils/buttonActions.js
@@ -1,6 +1,6 @@
import { enrichDataBinding, enrichDataBindings } from "./enrichDataBinding"
import { routeStore } from "../store"
-import { saveRow, deleteRow, executeQuery } from "../api"
+import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
const saveRowHandler = async (action, context) => {
let draft = context[`${action.parameters.contextPath}_draft`]
@@ -21,6 +21,17 @@ const deleteRowHandler = async (action, context) => {
})
}
+const triggerAutomationHandler = async (action, context) => {
+ const params = {}
+ for (let field in action.parameters.fields) {
+ params[field] = enrichDataBinding(
+ action.parameters.fields[field].value,
+ context
+ )
+ }
+ await triggerAutomation(action.parameters.automationId, params)
+}
+
const navigationHandler = action => {
routeStore.actions.navigate(action.parameters.url)
}
@@ -42,6 +53,7 @@ const handlerMap = {
["Delete Row"]: deleteRowHandler,
["Navigate To"]: navigationHandler,
["Execute Query"]: queryExecutionHandler,
+ ["Trigger Automation"]: triggerAutomationHandler,
}
/**
diff --git a/packages/server/package.json b/packages/server/package.json
index c4e2377ed8..f4c6d52289 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
- "version": "0.4.3",
+ "version": "0.5.3",
"description": "Budibase Web Server",
"main": "src/electron.js",
"repository": {
@@ -49,8 +49,8 @@
"author": "Budibase",
"license": "AGPL-3.0-or-later",
"dependencies": {
- "@budibase/client": "^0.4.3",
"@elastic/elasticsearch": "^7.10.0",
+ "@budibase/client": "^0.5.3",
"@koa/router": "^8.0.0",
"@sendgrid/mail": "^7.1.1",
"@sentry/node": "^5.19.2",
@@ -118,5 +118,5 @@
"./scripts/jestSetup.js"
]
},
- "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691"
+ "gitHead": "62ebf3cedcd7e9b2494b4f8cbcfb90927609b491"
}
diff --git a/packages/server/src/api/controllers/query.js b/packages/server/src/api/controllers/query.js
index 257e644b3c..d4dd693ca7 100644
--- a/packages/server/src/api/controllers/query.js
+++ b/packages/server/src/api/controllers/query.js
@@ -31,11 +31,18 @@ exports.save = async function(ctx) {
function enrichQueryFields(fields, parameters) {
const enrichedQuery = {}
+
// enrich the fields with dynamic parameters
for (let key in fields) {
const template = handlebars.compile(fields[key])
enrichedQuery[key] = template(parameters)
}
+
+ if (fields.json || fields.customData) {
+ enrichedQuery.json = JSON.parse(fields.json || fields.customData)
+ delete enrichedQuery.customData
+ }
+
return enrichedQuery
}
diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js
index 6fbd8e4c25..6634016e3f 100644
--- a/packages/server/src/automations/triggers.js
+++ b/packages/server/src/automations/triggers.js
@@ -2,6 +2,7 @@ const CouchDB = require("../db")
const emitter = require("../events/index")
const InMemoryQueue = require("../utilities/queue/inMemoryQueue")
const { getAutomationParams } = require("../db/utils")
+const { coerceValue } = require("../utilities")
let automationQueue = new InMemoryQueue("automationQueue")
@@ -119,6 +120,37 @@ const BUILTIN_DEFINITIONS = {
},
type: "TRIGGER",
},
+ APP: {
+ name: "App Action",
+ event: "app:trigger",
+ icon: "ri-window-fill",
+ tagline: "Automation fired from the frontend",
+ description: "Trigger an automation from an action inside your app",
+ stepId: "APP",
+ inputs: {},
+ schema: {
+ inputs: {
+ properties: {
+ fields: {
+ type: "object",
+ customType: "triggerSchema",
+ title: "Fields",
+ },
+ },
+ required: [],
+ },
+ outputs: {
+ properties: {
+ fields: {
+ type: "object",
+ description: "Fields submitted from the app frontend",
+ },
+ },
+ required: ["fields"],
+ },
+ },
+ type: "TRIGGER",
+ },
}
async function queueRelevantRowAutomations(event, eventType) {
@@ -200,12 +232,19 @@ async function fillRowOutput(automation, params) {
module.exports.externalTrigger = async function(automation, params) {
// TODO: replace this with allowing user in builder to input values in future
- if (
- automation.definition != null &&
- automation.definition.trigger != null &&
- automation.definition.trigger.inputs.tableId != null
- ) {
- params = await fillRowOutput(automation, params)
+ if (automation.definition != null && automation.definition.trigger != null) {
+ if (automation.definition.trigger.inputs.tableId != null) {
+ params = await fillRowOutput(automation, params)
+ }
+ if (automation.definition.trigger.stepId === "APP") {
+ // values are likely to be submitted as strings, so we shall convert to correct type
+ const coercedFields = {}
+ const fields = automation.definition.trigger.inputs.fields
+ for (let key in fields) {
+ coercedFields[key] = coerceValue(params.fields[key], fields[key])
+ }
+ params.fields = coercedFields
+ }
}
automationQueue.add({ automation, event: params })
diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js
index 8e129913fd..5fbf57448a 100644
--- a/packages/server/src/environment.js
+++ b/packages/server/src/environment.js
@@ -36,8 +36,6 @@ module.exports = {
ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
DEPLOYMENT_DB_URL: process.env.DEPLOYMENT_DB_URL,
LOCAL_TEMPLATES: process.env.LOCAL_TEMPLATES,
- // self hosting features
- LOGO_URL: process.env.LOGO_URL,
_set(key, value) {
process.env[key] = value
module.exports[key] = value
diff --git a/packages/server/src/integrations/airtable.js b/packages/server/src/integrations/airtable.js
index 19aa3236ed..cb085f823c 100644
--- a/packages/server/src/integrations/airtable.js
+++ b/packages/server/src/integrations/airtable.js
@@ -56,7 +56,7 @@ const SCHEMA = {
},
delete: {
"Airtable Ids": {
- type: FIELD_TYPES.LIST,
+ type: FIELD_TYPES.JSON,
},
},
},
@@ -69,12 +69,12 @@ class AirtableIntegration {
}
async create(query) {
- const { table, ...rest } = query
+ const { table, json } = query
try {
const records = await this.client(table).create([
{
- fields: rest,
+ fields: json,
},
])
return records
@@ -87,7 +87,7 @@ class AirtableIntegration {
async read(query) {
try {
const records = await this.client(query.table)
- .select({ maxRecords: 10, view: query.view })
+ .select({ maxRecords: query.numRecords || 10, view: query.view })
.firstPage()
return records.map(({ fields }) => fields)
} catch (err) {
@@ -97,13 +97,13 @@ class AirtableIntegration {
}
async update(query) {
- const { table, id, ...rest } = query
+ const { table, id, json } = query
try {
const records = await this.client(table).update([
{
id,
- fields: rest,
+ fields: json,
},
])
return records
diff --git a/packages/server/src/integrations/couchdb.js b/packages/server/src/integrations/couchdb.js
index c47e3698f6..c6474ff2b5 100644
--- a/packages/server/src/integrations/couchdb.js
+++ b/packages/server/src/integrations/couchdb.js
@@ -6,21 +6,39 @@ const SCHEMA = {
url: {
type: FIELD_TYPES.STRING,
required: true,
- default: "localhost",
+ default: "http://localhost:5984",
},
database: {
type: FIELD_TYPES.STRING,
required: true,
},
- view: {
- type: FIELD_TYPES.STRING,
- required: true,
- },
},
query: {
- json: {
- type: QUERY_TYPES.JSON,
- required: true,
+ create: {
+ "CouchDB DSL": {
+ type: QUERY_TYPES.JSON,
+ },
+ },
+ read: {
+ "CouchDB DSL": {
+ type: QUERY_TYPES.JSON,
+ },
+ },
+ update: {
+ "CouchDB Document": {
+ type: QUERY_TYPES.JSON,
+ },
+ },
+ delete: {
+ "Document ID": {
+ type: QUERY_TYPES.FIELDS,
+ fields: {
+ id: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ },
+ },
},
},
}
@@ -31,10 +49,21 @@ class CouchDBIntegration {
this.client = new PouchDB(`${config.url}/${config.database}`)
}
- async read() {
+ async create(query) {
+ try {
+ const result = await this.client.post(query.json)
+ return result
+ } catch (err) {
+ console.error("Error writing to couchDB", err)
+ throw err
+ }
+ }
+
+ async read(query) {
try {
const result = await this.client.allDocs({
include_docs: true,
+ ...query.json,
})
return result.rows.map(row => row.doc)
} catch (err) {
@@ -42,6 +71,26 @@ class CouchDBIntegration {
throw err
}
}
+
+ async update(query) {
+ try {
+ const result = await this.client.put(query.json)
+ return result
+ } catch (err) {
+ console.error("Error updating couchDB document", err)
+ throw err
+ }
+ }
+
+ async delete(query) {
+ try {
+ const result = await this.client.remove(query.id)
+ return result
+ } catch (err) {
+ console.error("Error deleting couchDB document", err)
+ throw err
+ }
+ }
}
module.exports = {
diff --git a/packages/server/src/integrations/elasticsearch.js b/packages/server/src/integrations/elasticsearch.js
index 610fa99041..817cb43696 100644
--- a/packages/server/src/integrations/elasticsearch.js
+++ b/packages/server/src/integrations/elasticsearch.js
@@ -1,21 +1,69 @@
const { Client } = require("@elastic/elasticsearch")
+const { QUERY_TYPES, FIELD_TYPES } = require("./Integration")
const SCHEMA = {
datasource: {
url: {
type: "string",
required: true,
- default: "localhost",
- },
- index: {
- type: "string",
- required: true,
+ default: "http://localhost:9200",
},
},
query: {
- json: {
- type: "json",
- required: true,
+ create: {
+ "ES Query DSL": {
+ type: QUERY_TYPES.FIELDS,
+ customisable: true,
+ fields: {
+ index: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ },
+ },
+ },
+ read: {
+ "ES Query DSL": {
+ type: QUERY_TYPES.FIELDS,
+ customisable: true,
+ fields: {
+ index: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ },
+ },
+ },
+ update: {
+ "ES Query DSL": {
+ type: QUERY_TYPES.FIELDS,
+ customisable: true,
+ fields: {
+ id: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ index: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ },
+ },
+ },
+ delete: {
+ "Document ID": {
+ type: QUERY_TYPES.FIELDS,
+ fields: {
+ index: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ id: {
+ type: FIELD_TYPES.STRING,
+ required: true,
+ },
+ },
+ },
},
},
}
@@ -27,12 +75,14 @@ class ElasticSearchIntegration {
}
async create(query) {
+ const { index, json } = query
+
try {
const result = await this.client.index({
- index: this.config.index,
- body: JSON.parse(query.json),
+ index,
+ body: json,
})
- return [result]
+ return result.body
} catch (err) {
console.error("Error writing to elasticsearch", err)
throw err
@@ -42,10 +92,11 @@ class ElasticSearchIntegration {
}
async read(query) {
+ const { index, json } = query
try {
const result = await this.client.search({
- index: this.config.index,
- body: JSON.parse(query.json),
+ index: index,
+ body: json,
})
return result.body.hits.hits.map(({ _source }) => _source)
} catch (err) {
@@ -55,6 +106,35 @@ class ElasticSearchIntegration {
await this.client.close()
}
}
+
+ async update(query) {
+ const { id, index, json } = query
+ try {
+ const result = await this.client.update({
+ id,
+ index,
+ body: json,
+ })
+ return result.body
+ } catch (err) {
+ console.error("Error querying elasticsearch", err)
+ throw err
+ } finally {
+ await this.client.close()
+ }
+ }
+
+ async delete(query) {
+ try {
+ const result = await this.client.delete(query)
+ return result.body
+ } catch (err) {
+ console.error("Error deleting from elasticsearch", err)
+ throw err
+ } finally {
+ await this.client.close()
+ }
+ }
}
module.exports = {
diff --git a/packages/server/src/integrations/mongodb.js b/packages/server/src/integrations/mongodb.js
index 2fa8719825..51af4573aa 100644
--- a/packages/server/src/integrations/mongodb.js
+++ b/packages/server/src/integrations/mongodb.js
@@ -43,14 +43,13 @@ class MongoIntegration {
async create(query) {
try {
- const mongoQuery = query.json ? JSON.parse(query.json) : {}
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(this.config.collection)
- const result = await collection.insertOne(mongoQuery)
+ const result = await collection.insertOne(query.json)
return result
} catch (err) {
- console.error("Error querying mongodb", err)
+ console.error("Error writing to mongodb", err)
throw err
} finally {
await this.client.close()
@@ -59,11 +58,10 @@ class MongoIntegration {
async read(query) {
try {
- const mongoQuery = query.json ? JSON.parse(query.json) : {}
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(this.config.collection)
- const result = await collection.find(mongoQuery).toArray()
+ const result = await collection.find(query.json).toArray()
return result
} catch (err) {
console.error("Error querying mongodb", err)
diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js
index c8e2e57bff..b9b512a80f 100644
--- a/packages/server/src/utilities/index.js
+++ b/packages/server/src/utilities/index.js
@@ -144,6 +144,23 @@ exports.walkDir = (dirPath, callback) => {
}
}
+/**
+ * This will coerce a value to the correct types based on the type transform map
+ * @param {object} row The value to coerce
+ * @param {object} type The type fo coerce to
+ * @returns {object} The coerced value
+ */
+exports.coerceValue = (value, type) => {
+ // eslint-disable-next-line no-prototype-builtins
+ if (TYPE_TRANSFORM_MAP[type].hasOwnProperty(value)) {
+ return TYPE_TRANSFORM_MAP[type][value]
+ } else if (TYPE_TRANSFORM_MAP[type].parse) {
+ return TYPE_TRANSFORM_MAP[type].parse(value)
+ }
+
+ return value
+}
+
/**
* This will coerce the values in a row to the correct types based on the type transform map and the
* table schema.
@@ -159,25 +176,11 @@ exports.coerceRowValues = (row, table) => {
const field = table.schema[key]
if (!field) continue
- // eslint-disable-next-line no-prototype-builtins
- if (TYPE_TRANSFORM_MAP[field.type].hasOwnProperty(value)) {
- clonedRow[key] = TYPE_TRANSFORM_MAP[field.type][value]
- } else if (TYPE_TRANSFORM_MAP[field.type].parse) {
- clonedRow[key] = TYPE_TRANSFORM_MAP[field.type].parse(value)
- }
+ clonedRow[key] = exports.coerceValue(value, field.type)
}
return clonedRow
}
-/**
- * Gets the correct link to the logo URL depending on if running in Cloud or if running in self hosting.
- * @returns {string} A URL which links to the correct default logo for new apps.
- */
exports.getLogoUrl = () => {
- const BB_LOGO_URL =
- "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
- if (env.SELF_HOSTED) {
- return env.LOGO_URL || BB_LOGO_URL
- }
- return BB_LOGO_URL
+ return "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
}
diff --git a/packages/standard-components/package.json b/packages/standard-components/package.json
index 006fe9da5c..0b018d251c 100644
--- a/packages/standard-components/package.json
+++ b/packages/standard-components/package.json
@@ -29,9 +29,9 @@
"keywords": [
"svelte"
],
- "version": "0.4.3",
+ "version": "0.5.3",
"license": "MIT",
- "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
+ "gitHead": "62ebf3cedcd7e9b2494b4f8cbcfb90927609b491",
"dependencies": {
"@budibase/bbui": "^1.52.4",
"@budibase/svelte-ag-grid": "^0.0.16",
diff --git a/packages/worker/package.json b/packages/worker/package.json
index d3def44844..16275084c5 100644
--- a/packages/worker/package.json
+++ b/packages/worker/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/deployment",
"email": "hi@budibase.com",
- "version": "0.3.8",
+ "version": "0.5.3",
"description": "Budibase Deployment Server",
"main": "src/index.js",
"repository": {
@@ -30,5 +30,6 @@
"koa-static": "^5.0.0",
"pino-pretty": "^4.0.0",
"server-destroy": "^1.0.1"
- }
+ },
+ "gitHead": "62ebf3cedcd7e9b2494b4f8cbcfb90927609b491"
}