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 @@
- {index + 1}. {action[eventTypeKey]} + {index + 1}. {action[EVENT_TYPE_KEY]}
{ + 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" }