diff --git a/lerna.json b/lerna.json
index dd7190c4b..a1b8faab3 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"npmClient": "yarn",
"packages": [
"packages/*"
diff --git a/packages/auth/package.json b/packages/auth/package.json
index ec7565163..f99ac5c90 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/auth",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"description": "Authentication middlewares for budibase builder and apps",
"main": "src/index.js",
"author": "Budibase",
diff --git a/packages/auth/src/cache/user.js b/packages/auth/src/cache/user.js
index 669192a90..2b2693ca0 100644
--- a/packages/auth/src/cache/user.js
+++ b/packages/auth/src/cache/user.js
@@ -6,8 +6,10 @@ const EXPIRY_SECONDS = 3600
/**
* The default populate user function
*/
-const populateFromDB = (userId, tenantId) => {
- return getGlobalDB(tenantId).get(userId)
+const populateFromDB = async (userId, tenantId) => {
+ const user = await getGlobalDB(tenantId).get(userId)
+ user.budibaseAccess = true
+ return user
}
/**
diff --git a/packages/bbui/package.json b/packages/bbui/package.json
index f7e06046a..56c390342 100644
--- a/packages/bbui/package.json
+++ b/packages/bbui/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"license": "AGPL-3.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",
diff --git a/packages/bbui/src/ActionButton/ActionButton.svelte b/packages/bbui/src/ActionButton/ActionButton.svelte
index 83f71d385..b518ac3d9 100644
--- a/packages/bbui/src/ActionButton/ActionButton.svelte
+++ b/packages/bbui/src/ActionButton/ActionButton.svelte
@@ -12,6 +12,7 @@
export let dataCy = null
export let size = "M"
export let active = false
+ export let fullWidth = false
function longPress(element) {
if (!longPressable) return
@@ -40,6 +41,7 @@
class:spectrum-ActionButton--quiet={quiet}
class:spectrum-ActionButton--emphasized={emphasized}
class:is-selected={selected}
+ class:fullWidth
class="spectrum-ActionButton spectrum-ActionButton--size{size}"
class:active
{disabled}
@@ -71,6 +73,9 @@
diff --git a/packages/builder/assets/discord.svg b/packages/builder/assets/discord.svg
new file mode 100644
index 000000000..3efe1ec11
--- /dev/null
+++ b/packages/builder/assets/discord.svg
@@ -0,0 +1,10 @@
+
diff --git a/packages/builder/assets/integromat.png b/packages/builder/assets/integromat.png
new file mode 100644
index 000000000..1fbbe63e7
Binary files /dev/null and b/packages/builder/assets/integromat.png differ
diff --git a/packages/builder/assets/n8n.png b/packages/builder/assets/n8n.png
new file mode 100644
index 000000000..b9dad93e5
Binary files /dev/null and b/packages/builder/assets/n8n.png differ
diff --git a/packages/builder/assets/slack.svg b/packages/builder/assets/slack.svg
new file mode 100644
index 000000000..adcae7e39
--- /dev/null
+++ b/packages/builder/assets/slack.svg
@@ -0,0 +1,33 @@
+
+
+
\ No newline at end of file
diff --git a/packages/builder/assets/zapier.png b/packages/builder/assets/zapier.png
new file mode 100644
index 000000000..380533144
Binary files /dev/null and b/packages/builder/assets/zapier.png differ
diff --git a/packages/builder/cypress/integration/createAutomation.spec.js b/packages/builder/cypress/integration/createAutomation.spec.js
index e5040c3c4..0620a15e2 100644
--- a/packages/builder/cypress/integration/createAutomation.spec.js
+++ b/packages/builder/cypress/integration/createAutomation.spec.js
@@ -7,26 +7,42 @@ context("Create a automation", () => {
// https://on.cypress.io/interacting-with-elements
it("should create a automation", () => {
cy.createTestTableWithData()
-
+ cy.wait(2000)
cy.contains("Automate").click()
cy.get("[data-cy='new-screen'] > .spectrum-Icon").click()
- cy.get(".spectrum-Dialog-grid").within(() => {
+ cy.get(".modal-inner-wrapper").within(() => {
cy.get("input").type("Add Row")
+ cy.contains("Row Created").click()
+ cy.wait(500)
cy.get(".spectrum-Button--cta").click()
})
- // Add trigger
- cy.contains("Trigger").click()
- cy.contains("Row Created").click()
- cy.get(".setup").within(() => {
- cy.get(".spectrum-Picker-label").click()
- cy.contains("dog").click()
- })
+ // Setup trigger
+ cy.contains("Setup").click()
+ cy.get(".spectrum-Picker-label").click()
+ cy.wait(500)
+ cy.contains("dog").click()
// Create action
- cy.contains("Internal").click()
- cy.contains("Create Row").click()
- cy.get(".setup").within(() => {
+ cy.contains("Add Action").click()
+ cy.get(".modal-inner-wrapper").within(() => {
+ cy.wait(1000)
+ cy.contains("Create Row").trigger('mouseover').click().click()
+ cy.get(".spectrum-Button--cta").click()
+ })
+ cy.contains("Setup").click()
+ cy.get(".spectrum-Picker-label").click()
+ cy.contains("dog").click()
+ cy.get(".spectrum-Textfield-input")
+ .first()
+ .type("goodboy")
+ cy.get(".spectrum-Textfield-input")
+ .eq(1)
+ .type("11")
+
+ cy.contains("Run test").click()
+ cy.get(".modal-inner-wrapper").within(() => {
+ cy.wait(1000)
cy.get(".spectrum-Picker-label").click()
cy.contains("dog").click()
cy.get(".spectrum-Textfield-input")
@@ -35,19 +51,12 @@ context("Create a automation", () => {
cy.get(".spectrum-Textfield-input")
.eq(1)
.type("11")
+ cy.get(".spectrum-Textfield-input")
+ .eq(2)
+ .type("123456")
+ cy.get(".spectrum-Textfield-input")
+ .eq(3)
+ .type("123456")
})
-
- // Save
- cy.contains("Save Automation").click()
-
- // Activate Automation
- cy.get("[data-cy=activate-automation]").click()
- })
-
- it("should add row when a new row is added", () => {
- cy.contains("Data").click()
- cy.addRow(["Rover", 15])
- cy.reload()
- cy.contains("goodboy").should("have.text", "goodboy")
})
})
diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js
index 261b84057..8bda515fb 100644
--- a/packages/builder/cypress/support/commands.js
+++ b/packages/builder/cypress/support/commands.js
@@ -37,9 +37,8 @@ Cypress.Commands.add("createApp", name => {
cy.contains("Create app").click()
})
.then(() => {
- cy.get(".selected > .content", {
- timeout: 20000,
- }).should("be.visible")
+ cy.expandBudibaseConnection()
+ cy.get(".nav-item.selected > .content").should("be.visible")
})
})
@@ -83,6 +82,7 @@ Cypress.Commands.add("createTable", tableName => {
Cypress.Commands.add("addColumn", (tableName, columnName, type) => {
// Select Table
+ cy.selectTable(tableName)
cy.contains(".nav-item", tableName).click()
cy.contains("Create column").click()
@@ -161,3 +161,15 @@ Cypress.Commands.add("createScreen", (screenName, route) => {
cy.get(".spectrum-Button--cta").click()
})
})
+
+Cypress.Commands.add("expandBudibaseConnection", () => {
+ if (Cypress.$(".nav-item > .content > .opened").length === 0) {
+ // expand the Budibase DB connection string
+ cy.get(".icon.arrow").eq(0).click()
+ }
+})
+
+Cypress.Commands.add("selectTable", tableName => {
+ cy.expandBudibaseConnection()
+ cy.contains(".nav-item", tableName).click()
+})
diff --git a/packages/builder/package.json b/packages/builder/package.json
index 14b0d8479..ad74b263a 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"license": "AGPL-3.0",
"private": true,
"scripts": {
@@ -65,10 +65,10 @@
}
},
"dependencies": {
- "@budibase/bbui": "^0.9.125-alpha.7",
- "@budibase/client": "^0.9.125-alpha.7",
+ "@budibase/bbui": "^0.9.125-alpha.11",
+ "@budibase/client": "^0.9.125-alpha.11",
"@budibase/colorpicker": "1.1.2",
- "@budibase/string-templates": "^0.9.125-alpha.7",
+ "@budibase/string-templates": "^0.9.125-alpha.11",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",
diff --git a/packages/builder/src/builderStore/store/automation/Automation.js b/packages/builder/src/builderStore/store/automation/Automation.js
index a9dce8825..dcbb747e3 100644
--- a/packages/builder/src/builderStore/store/automation/Automation.js
+++ b/packages/builder/src/builderStore/store/automation/Automation.js
@@ -13,6 +13,10 @@ export default class Automation {
return this.automation.definition.trigger
}
+ addTestData(data) {
+ this.automation.testData = data
+ }
+
addBlock(block) {
// Make sure to add trigger if doesn't exist
if (!this.hasTrigger() && block.type === "TRIGGER") {
diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js
index f8e7db04a..db06ce172 100644
--- a/packages/builder/src/builderStore/store/automation/index.js
+++ b/packages/builder/src/builderStore/store/automation/index.js
@@ -17,7 +17,6 @@ const automationActions = store => ({
state.blockDefinitions = {
TRIGGER: jsonResponses[1].trigger,
ACTION: jsonResponses[1].action,
- LOGIC: jsonResponses[1].logic,
}
// if previously selected find the new obj and select it
if (selected) {
@@ -80,9 +79,14 @@ const automationActions = store => ({
const { _id } = automation
return await api.post(`/api/automations/${_id}/trigger`)
},
- test: async ({ automation }) => {
+ test: async ({ automation }, testData) => {
const { _id } = automation
- return await api.post(`/api/automations/${_id}/test`)
+ const response = await api.post(`/api/automations/${_id}/test`, testData)
+ const json = await response.json()
+ store.update(state => {
+ state.selectedAutomation.testResults = json
+ return state
+ })
},
select: automation => {
store.update(state => {
@@ -91,6 +95,12 @@ const automationActions = store => ({
return state
})
},
+ addTestDataToAutomation: data => {
+ store.update(state => {
+ state.selectedAutomation.addTestData(data)
+ return state
+ })
+ },
addBlockToAutomation: block => {
store.update(state => {
const newBlock = state.selectedAutomation.addBlock(cloneDeep(block))
@@ -132,7 +142,6 @@ export const getAutomationStore = () => {
blockDefinitions: {
TRIGGER: [],
ACTION: [],
- LOGIC: [],
},
selectedAutomation: null,
}
diff --git a/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte b/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte
index 62faff3ca..7ce77a58e 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte
@@ -1,10 +1,8 @@
{#if automation}
-
{/if}
diff --git a/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte b/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
deleted file mode 100644
index a04541cfa..000000000
--- a/packages/builder/src/components/automation/AutomationBuilder/BlockList.svelte
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
- {#each tabs as tab, idx}
-
-
onChangeTab(idx)}
- >
- {tab.label}
-
-
- {/each}
-
- (selectedIndex = null)}
- bind:this={popover}
- {anchor}
- align="left"
->
-
- {#each blocks as [stepId, blockDefinition]}
- addBlockToAutomation(stepId, blockDefinition)}
- />
- {/each}
-
-
-
-
-
-
-
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte
new file mode 100644
index 000000000..8820259e9
--- /dev/null
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte
@@ -0,0 +1,136 @@
+
+
+ {
+ blockComplete = true
+ addBlockToAutomation()
+ }}
+>
+ Select an app or event.
+
+ Apps
+
+
+ {#each Object.entries(external) as [idx, action]}
+
selectAction(action)}
+ >
+
+

+
+ {idx.charAt(0).toUpperCase() + idx.slice(1)}
+
+
+ {/each}
+
+
+ Actions
+
+
+ {#each Object.entries(internal) as [idx, action]}
+
selectAction(action)}
+ >
+
+
+
+ {action.name}
+
+
+ {/each}
+
+
+
+
+
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/Arrow.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/Arrow.svelte
index 931490b19..5aec39abe 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/Arrow.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/Arrow.svelte
@@ -6,6 +6,7 @@
xmlns="http://www.w3.org/2000/svg"
>
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ExternalActions.js b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ExternalActions.js
new file mode 100644
index 000000000..843445a3c
--- /dev/null
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ExternalActions.js
@@ -0,0 +1,11 @@
+import DiscordLogo from "assets/discord.svg"
+import ZapierLogo from "assets/zapier.png"
+import IntegromatLogo from "assets/integromat.png"
+import SlackLogo from "assets/slack.svg"
+
+export const externalActions = {
+ zapier: { name: "zapier", icon: ZapierLogo },
+ discord: { name: "discord", icon: DiscordLogo },
+ slack: { name: "slack", icon: SlackLogo },
+ integromat: { name: "integromat", icon: IntegromatLogo },
+}
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte
index e960271b8..53a5de3b5 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte
@@ -1,12 +1,25 @@
-{#if !blocks.length}Add a trigger to your automation to get started{/if}
-
- {#each blocks as block, idx (block.id)}
-
-
- {#if idx !== blocks.length - 1}
-
- {/if}
+
+
+
+
+
{automation.name}
+
+
deleteAutomation()} class="iconPadding">
+
+
+
{
+ testDataModal.show()
+ }}
+ icon="MultipleCheck"
+ size="S">Run test
+
+
- {/each}
-
+ {#each blocks as block, idx (block.id)}
+
+
+ {#if idx !== blocks.length - 1}
+
+
+
+ {/if}
+
+ {/each}
+
+
+
+
+
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte
index 439db6263..5898537da 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte
@@ -1,86 +1,204 @@
onSelect(block)}
+ on:click={() => {
+ onSelect(block)
+ }}
>
-
- {#if block.type === "TRIGGER"}
-
- When this happens...
- {:else if block.type === "ACTION"}
-
- Do this...
- {:else if block.type === "LOGIC"}
-
- Only continue if...
- {/if}
-
- {#if block.type === "TRIGGER"}Trigger{:else}Step {blockIdx + 1}{/if}
+
+
{
+ blockComplete = !blockComplete
+ }}
+ class="splitHeader"
+ >
+
+ {#if externalActions[block.stepId]}
+
![{externalActions[block.stepId].name}]({externalActions[block.stepId].icon})
+ {:else}
+
+ {/if}
+
+ {#if isTrigger}
+ When this happens:
+ {:else}
+ Do this:
+ {/if}
+
+ {block?.name?.toUpperCase() || ""}
+
+
+ {#if testResult}
+
resultsModal.show()}>
+ View response
+
+ {/if}
+
+
+ {#if !blockComplete}
+
+
+
+
+
+ {#if setupToggled}
+
+ {#if lastStep}
+
+ {/if}
+
+ {/if}
+
- {#if block.type !== "TRIGGER" || allowDeleteTrigger}
-
- {/if}
-
-
-
-
-
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte
new file mode 100644
index 000000000..7dfdff20a
--- /dev/null
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte
@@ -0,0 +1,114 @@
+
+
+
+
+
+ {#if isTrigger || testResult[0].outputs.success}
+
+
+
+ {:else}
+
+
+
+ {/if}
+
+
+
+ {
+ inputToggled = !inputToggled
+ }}
+ class="toggle splitHeader"
+ >
+
+
+ {#if inputToggled}
+
+ {:else}
+
+ {/if}
+
+
+ {#if inputToggled}
+
+
+
+ {/if}
+
+ {
+ outputToggled = !outputToggled
+ }}
+ class="toggle splitHeader"
+ >
+
+
+ {#if outputToggled}
+
+ {:else}
+
+ {/if}
+
+
+ {#if outputToggled}
+
+
+
+ {/if}
+
+
+
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte
new file mode 100644
index 000000000..d05c8fa32
--- /dev/null
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/TestDataModal.svelte
@@ -0,0 +1,88 @@
+
+
+ {
+ automationStore.actions.addTestDataToAutomation(testData)
+ automationStore.actions.test($automationStore.selectedAutomation, testData)
+ }}
+ cancelText="Cancel"
+>
+
+
+
+
+
+
+
+
+
diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationList.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationList.svelte
index f70366773..79de4bfbe 100644
--- a/packages/builder/src/components/automation/AutomationPanel/AutomationList.svelte
+++ b/packages/builder/src/components/automation/AutomationPanel/AutomationList.svelte
@@ -6,7 +6,6 @@
import EditAutomationPopover from "./EditAutomationPopover.svelte"
$: selectedAutomationId = $automationStore.selectedAutomation?.automation?._id
-
onMount(() => {
automationStore.actions.fetch()
})
diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte
index dbcbc33db..0c975eab1 100644
--- a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte
+++ b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte
@@ -2,7 +2,9 @@
import AutomationList from "./AutomationList.svelte"
import CreateAutomationModal from "./CreateAutomationModal.svelte"
import { Icon, Modal, Tabs, Tab } from "@budibase/bbui"
- let modal
+
+ export let modal
+ export let webhookModal
@@ -11,7 +13,7 @@
diff --git a/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte b/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte
index dfcfc2ab9..e774c366a 100644
--- a/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte
+++ b/packages/builder/src/components/automation/AutomationPanel/CreateAutomationModal.svelte
@@ -3,12 +3,14 @@
import { database } from "stores/backend"
import { automationStore } from "builderStore"
import { notifications } from "@budibase/bbui"
- import { Icon, Input, ModalContent } from "@budibase/bbui"
+ import { Input, ModalContent, Layout, Body, Icon } from "@budibase/bbui"
import analytics from "analytics"
let name
+ let selectedTrigger
+ let triggerVal
+ export let webhookModal
- $: valid = !!name
$: instanceId = $database._id
async function createAutomation() {
@@ -16,41 +18,97 @@
name,
instanceId,
})
+ const newBlock = $automationStore.selectedAutomation.constructBlock(
+ "TRIGGER",
+ triggerVal.stepId,
+ triggerVal
+ )
+
+ automationStore.actions.addBlockToAutomation(newBlock)
+ if (triggerVal.stepId === "WEBHOOK") {
+ webhookModal.show
+ }
+
+ await automationStore.actions.save({
+ instanceId,
+ automation: $automationStore.selectedAutomation?.automation,
+ })
+
notifications.success(`Automation ${name} created.`)
+
$goto(`./${$automationStore.selectedAutomation.automation._id}`)
analytics.captureEvent("Automation Created", { name })
}
+ $: triggers = Object.entries($automationStore.blockDefinitions.TRIGGER)
+
+ const selectTrigger = trigger => {
+ triggerVal = trigger
+ selectedTrigger = trigger.name
+ }
+ Please name your automation, then select a trigger. Every automation must
+ start with a trigger.
+
-
-
- Learn about automations
-
+
+
+ Triggers
+
+
+ {#each triggers as [idx, trigger]}
+
selectTrigger(trigger)}
+ >
+
+
+
+ {trigger.name}
+
+
+ {/each}
+
+
diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
index d1c5d104d..f5bc2c04a 100644
--- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
@@ -2,8 +2,16 @@
import TableSelector from "./TableSelector.svelte"
import RowSelector from "./RowSelector.svelte"
import SchemaSetup from "./SchemaSetup.svelte"
- import { Button, Input, Select, Label } from "@budibase/bbui"
+ import {
+ Button,
+ Input,
+ Select,
+ Label,
+ ActionButton,
+ Drawer,
+ } from "@budibase/bbui"
import { automationStore } from "builderStore"
+ import { tables } from "stores/backend"
import WebhookDisplay from "../Shared/WebhookDisplay.svelte"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
@@ -12,15 +20,50 @@
import QueryParamSelector from "./QueryParamSelector.svelte"
import CronBuilder from "./CronBuilder.svelte"
import Editor from "components/integration/QueryEditor.svelte"
+ import { database } from "stores/backend"
+ import { debounce } from "lodash"
+ import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
+ import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte"
+ // need the client lucene builder to convert to the structure API expects
+ import { buildLuceneQuery } from "../../../../../client/src/utils/lucene"
export let block
export let webhookModal
- $: inputs = Object.entries(block.schema?.inputs?.properties || {})
+ export let testData
+ export let schemaProperties
+ export let isTestModal = false
+ let drawer
+ let tempFilters = lookForFilters(schemaProperties) || []
+ let fillWidth = true
+
$: stepId = block.stepId
$: bindings = getAvailableBindings(
- block,
+ block || $automationStore.selectedBlock,
$automationStore.selectedAutomation?.automation?.definition
)
+ $: instanceId = $database._id
+
+ $: inputData = testData ? testData : block.inputs
+ $: tableId = inputData ? inputData.tableId : null
+ $: table = tableId
+ ? $tables.list.find(table => table._id === inputData.tableId)
+ : { schema: {} }
+ $: schemaFields = table ? Object.values(table.schema) : []
+
+ const onChange = debounce(
+ async function (e, key) {
+ if (isTestModal) {
+ testData[key] = e.detail
+ } else {
+ block.inputs[key] = e.detail
+ await automationStore.actions.save({
+ instanceId,
+ automation: $automationStore.selectedAutomation?.automation,
+ })
+ }
+ },
+ isTestModal ? 0 : 800
+ )
function getAvailableBindings(block, automation) {
if (!block || !automation) {
@@ -52,64 +95,159 @@
}
return bindings
}
+
+ function lookForFilters(properties) {
+ console.log("testing")
+ if (!properties) {
+ return []
+ }
+ let filters
+ const inputs = testData ? testData : block.inputs
+ for (let [key, field] of properties) {
+ // need to look for the builder definition (keyed separately, see saveFilters)
+ const defKey = `${key}-def`
+ if (field.customType === "filters" && inputs?.[defKey]) {
+ filters = inputs[defKey]
+ break
+ }
+ }
+ return filters || []
+ }
+
+ function saveFilters(key) {
+ const filters = buildLuceneQuery(tempFilters)
+ const defKey = `${key}-def`
+ inputData[key] = filters
+ inputData[defKey] = tempFilters
+ onChange({ detail: filters }, key)
+ // need to store the builder definition in the automation
+ onChange({ detail: tempFilters }, defKey)
+ drawer.hide()
+ }
-
{block.name}
- {#each inputs as [key, value]}
+ {#each schemaProperties as [key, value]}
-
+
{#if value.type === "string" && value.enum}
{/each}
@@ -132,9 +270,7 @@
grid-gap: 5px;
}
- .block-label {
- font-weight: 600;
- font-size: var(--font-size-s);
- color: var(--grey-7);
+ .test :global(.drawer) {
+ width: 10000px !important;
}
diff --git a/packages/builder/src/components/automation/SetupPanel/CronBuilder.svelte b/packages/builder/src/components/automation/SetupPanel/CronBuilder.svelte
index 810e45274..1b410cd86 100644
--- a/packages/builder/src/components/automation/SetupPanel/CronBuilder.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/CronBuilder.svelte
@@ -1,7 +1,13 @@
-
+
diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte
index 99f41908e..3f390e0a4 100644
--- a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte
@@ -3,12 +3,25 @@
import { Select } from "@budibase/bbui"
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
+ import { createEventDispatcher } from "svelte"
+ import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
+ import { automationStore } from "builderStore"
+
+ const dispatch = createEventDispatcher()
export let value
export let bindings
-
$: table = $tables.list.find(table => table._id === value?.tableId)
$: schemaFields = Object.entries(table?.schema ?? {})
+ const onChangeTable = e => {
+ value = { tableId: e.detail }
+ dispatch("change", value)
+ }
+
+ const onChange = (e, field) => {
+ value[field] = e.detail
+ dispatch("change", value)
+ }
// Ensure any nullish tableId values get set to empty string so
// that the select works
@@ -20,7 +33,8 @@
table.name}
getOptionValue={table => table._id}
@@ -32,19 +46,32 @@
{#if !schema.autocolumn}
{#if schemaHasOptions(schema)}
onChange(e, field)}
label={field}
- bind:value={value[field]}
+ value={value[field]}
options={schema.constraints.inclusion}
/>
{:else if schema.type === "string" || schema.type === "number"}
- (value[field] = e.detail)}
- label={field}
- type="string"
- {bindings}
- />
+ {#if $automationStore.selectedAutomation.automation.testData}
+ onChange(e, field)}
+ {bindings}
+ />
+ {:else}
+ onChange(e, field)}
+ label={field}
+ type="string"
+ {bindings}
+ fillWidth={true}
+ />
+ {/if}
{/if}
{/if}
{/each}
diff --git a/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte b/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte
index 1257563ff..54f5b9016 100644
--- a/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/SchemaSetup.svelte
@@ -1,5 +1,8 @@
@@ -68,7 +72,10 @@
/>
(value[field.name] = e.target.value)}
+ on:change={e => {
+ value[field.name] = e.target.value
+ dispatch("change", value)
+ }}
options={typeOptions}
/>
- import { automationStore } from "builderStore"
- import { database } from "stores/backend"
- import { notifications, Button, Modal, Heading, Toggle } from "@budibase/bbui"
- import AutomationBlockSetup from "./AutomationBlockSetup.svelte"
- import CreateWebookModal from "../Shared/CreateWebhookModal.svelte"
-
- let webhookModal
-
- $: instanceId = $database._id
- $: automation = $automationStore.selectedAutomation?.automation
- $: automationLive = automation?.live
-
- function setAutomationLive(live) {
- if (automationLive === live) {
- return
- }
- automation.live = live
- automationStore.actions.save({ instanceId, automation })
- if (live) {
- notifications.info(`Automation ${automation.name} enabled.`)
- } else {
- notifications.error(`Automation ${automation.name} disabled.`)
- }
- }
-
- async function testAutomation() {
- const result = await automationStore.actions.test({
- automation: $automationStore.selectedAutomation.automation,
- })
- if (result.status === 200) {
- notifications.success(
- `Automation ${automation.name} triggered successfully.`
- )
- } else {
- notifications.error(`Failed to trigger automation ${automation.name}.`)
- }
- }
-
- async function saveAutomation() {
- await automationStore.actions.save({
- instanceId,
- automation,
- })
- notifications.success(`Automation ${automation.name} saved.`)
- }
-
-
-
- Setup
- setAutomationLive(!automationLive)}
- dataCy="activate-automation"
- text="Live"
- />
-
-{#if $automationStore.selectedBlock}
-
-{:else if automation}
- {automation.name}
-
-{/if}
-
-
-
-
-
-
diff --git a/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte b/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte
index 4f9ac05a0..ceb28a37c 100644
--- a/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/TableSelector.svelte
@@ -1,11 +1,20 @@
table.name}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
index 42ea30dbb..84c737eb6 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
@@ -9,7 +9,10 @@
import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte"
import ICONS from "./icons"
+ let openDataSources = []
+
function selectDatasource(datasource) {
+ toggleNode(datasource)
datasources.select(datasource._id)
$goto(`./datasource/${datasource._id}`)
}
@@ -19,6 +22,15 @@
$goto(`./datasource/${query.datasourceId}/${query._id}`)
}
+ function toggleNode(datasource) {
+ const isOpen = openDataSources.includes(datasource._id)
+ if (isOpen) {
+ openDataSources = openDataSources.filter(id => datasource._id !== id)
+ } else {
+ openDataSources = [...openDataSources, datasource._id]
+ }
+ }
+
onMount(() => {
datasources.fetch()
queries.fetch()
@@ -31,8 +43,11 @@
0}
text={datasource.name}
+ opened={openDataSources.includes(datasource._id)}
selected={$datasources.selected === datasource._id}
+ withArrow={true}
on:click={() => selectDatasource(datasource)}
+ on:iconClick={() => toggleNode(datasource)}
>
-
+ {#if openDataSources.includes(datasource._id)}
+
+ {/if}
{#each $queries.list.filter(query => query.datasourceId === datasource._id) as query}
onClickQuery(query)}
>
diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte
index 977369299..ec7994be8 100644
--- a/packages/builder/src/components/common/NavItem.svelte
+++ b/packages/builder/src/components/common/NavItem.svelte
@@ -1,5 +1,6 @@
{#if withArrow}
-
+
{/if}
diff --git a/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte b/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte
index ee2487a9d..e5bfab583 100644
--- a/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte
+++ b/packages/builder/src/components/common/bindings/DrawerBindableInput.svelte
@@ -14,6 +14,7 @@
export let placeholder
export let label
export let disabled = false
+ export let fillWidth
const dispatch = createEventDispatcher()
let bindingDrawer
@@ -45,7 +46,7 @@
{/if}
-
+
Add the objects on the left to enrich your text.
diff --git a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
index 494050f69..33ef0c6ea 100644
--- a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
+++ b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
@@ -1,5 +1,5 @@
@@ -127,6 +127,7 @@
title={`Value for "${filter.field}"`}
value={filter.value}
placeholder="Value"
+ {panel}
{bindings}
on:change={event => (filter.value = event.detail)}
/>
diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte
index 0dbabb31d..4b296854b 100644
--- a/packages/builder/src/pages/builder/_layout.svelte
+++ b/packages/builder/src/pages/builder/_layout.svelte
@@ -6,31 +6,35 @@
let loaded = false
$: multiTenancyEnabled = $admin.multiTenancy
- $: hasAdminUser = $admin?.checklist?.adminUser.checked
+ $: hasAdminUser = $admin?.checklist?.adminUser?.checked
$: tenantSet = $auth.tenantSet
+ $: cloud = $admin.cloud
onMount(async () => {
- await admin.init()
await auth.checkAuth()
+ await admin.init()
loaded = true
})
$: {
- const apiReady = $admin.loaded && $auth.loaded
- // if tenant is not set go to it
- if (loaded && apiReady && multiTenancyEnabled && !tenantSet) {
- $redirect("./auth/org")
- }
- // Force creation of an admin user if one doesn't exist
- else if (loaded && apiReady && !hasAdminUser) {
- $redirect("./admin")
+ // We should never see the org or admin user creation screens in the cloud
+ if (!cloud) {
+ const apiReady = $admin.loaded && $auth.loaded
+ // if tenant is not set go to it
+ if (loaded && apiReady && multiTenancyEnabled && !tenantSet) {
+ $redirect("./auth/org")
+ }
+ // Force creation of an admin user if one doesn't exist
+ else if (loaded && apiReady && !hasAdminUser) {
+ $redirect("./admin")
+ }
}
}
// Redirect to log in at any time if the user isn't authenticated
$: {
if (
loaded &&
- hasAdminUser &&
+ (hasAdminUser || cloud) &&
!$auth.user &&
!$isActive("./auth") &&
!$isActive("./invite")
diff --git a/packages/builder/src/pages/builder/app/[application]/automate/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/automate/_layout.svelte
index d1aaeb024..841acb22c 100644
--- a/packages/builder/src/pages/builder/app/[application]/automate/_layout.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/automate/_layout.svelte
@@ -1,22 +1,50 @@
-
+ {#if automation}
+
+ {:else}
+
+
+
+
+ You have no automations
+ Let's fix that. Call the bots!
+
+
+
+
+ {/if}
- {#if $automationStore.selectedAutomation}
-
-
-
- {/if}
+
+
+
+
+
+
diff --git a/packages/builder/src/pages/builder/app/[application]/automate/index.svelte b/packages/builder/src/pages/builder/app/[application]/automate/index.svelte
index d48bd36e5..e5dea10e0 100644
--- a/packages/builder/src/pages/builder/app/[application]/automate/index.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/automate/index.svelte
@@ -15,13 +15,3 @@
}
})
-
-Create your first automation to get started
-
-
diff --git a/packages/builder/src/pages/builder/auth/org.svelte b/packages/builder/src/pages/builder/auth/org.svelte
index 785cf0591..fea883193 100644
--- a/packages/builder/src/pages/builder/auth/org.svelte
+++ b/packages/builder/src/pages/builder/auth/org.svelte
@@ -8,6 +8,7 @@
let tenantId = get(auth).tenantSet ? get(auth).tenantId : ""
$: multiTenancyEnabled = $admin.multiTenancy
+ $: cloud = $admin.cloud
async function setOrg() {
if (tenantId == null || tenantId === "") {
@@ -25,7 +26,7 @@
onMount(async () => {
await auth.checkQueryString()
- if (!multiTenancyEnabled) {
+ if (!multiTenancyEnabled || cloud) {
$goto("../")
} else {
admin.unload()
diff --git a/packages/builder/src/pages/builder/portal/_layout.svelte b/packages/builder/src/pages/builder/portal/_layout.svelte
index 3b8513b5a..02f49bec5 100644
--- a/packages/builder/src/pages/builder/portal/_layout.svelte
+++ b/packages/builder/src/pages/builder/portal/_layout.svelte
@@ -62,7 +62,7 @@
}
// add link to account portal if the user has access
- if ($auth?.user?.account) {
+ if ($auth?.user?.accountPortalAccess) {
menu = menu.concat([
{
title: "Account",
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 2cc9a1aba..1729e3003 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {
diff --git a/packages/client/package.json b/packages/client/package.json
index 9b60b1edd..45499807a 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/client",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
- "@budibase/bbui": "^0.9.125-alpha.7",
+ "@budibase/bbui": "^0.9.125-alpha.11",
"@budibase/standard-components": "^0.9.124",
- "@budibase/string-templates": "^0.9.125-alpha.7",
+ "@budibase/string-templates": "^0.9.125-alpha.11",
"regexparam": "^1.3.0",
"shortid": "^2.2.15",
"svelte-spa-router": "^3.0.5"
diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock
index 5e6e41476..7815ac54f 100644
--- a/packages/client/yarn.lock
+++ b/packages/client/yarn.lock
@@ -28,10 +28,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@budibase/bbui@^0.9.125":
- version "0.9.125"
- resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.125.tgz#b1a85e38c884de5fa35de3a778be05f279dc8315"
- integrity sha512-amU8NTeuaUrulPQM6kXZbQznZ6fX8uMw7mhsn/23TonbDyHWGSZRJ6pIA2FYc+KOESK1fL62O4yzfQA0OIViNw==
+"@budibase/bbui@^0.9.125-alpha.11":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.130.tgz#cad02a7aa16324eb7a056c5dc0162444fa917964"
+ integrity sha512-ULOC++363K8QEMasmsDmleF7AzjulFk/ZxGPlOJcVKJU8Bx5wG1uNFgTyJyGpmnbUWHd67eYUEettfH7I+VoOw==
dependencies:
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
"@spectrum-css/actionbutton" "^1.0.1"
@@ -77,10 +77,10 @@
svelte-flatpickr "^3.1.0"
svelte-portal "^1.0.0"
-"@budibase/bbui@^0.9.125-alpha.5":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.128.tgz#71a5e81b02a4f64baa6874bfa4b1d4fed8cc9f0b"
- integrity sha512-UCo9SRs1xsMQ0ClJOtNB7JeVF2+0iMVOfAZE7Rrf5d51W+1YeyM9b3BbfhxHRq1yeKLHrbdczerbTHQkmF1RwQ==
+"@budibase/bbui@^0.9.129":
+ version "0.9.129"
+ resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.129.tgz#989bf60d404772d4b308382faba7adac6518ec3e"
+ integrity sha512-U3uO9K3m7Ph5RQpzXx5IIy94s/KdU9Q8eJXFQwH6neYIKQk3OFo8br5px5C7lE38mtazqq9XvQy0f+MUarKk4A==
dependencies:
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
"@spectrum-css/actionbutton" "^1.0.1"
@@ -155,11 +155,11 @@
year "^0.2.1"
"@budibase/standard-components@^0.9.124":
- version "0.9.125"
- resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.125.tgz#92244f009ce22f105694ca85fdc78923f8bcba11"
- integrity sha512-PjCJ39o0EMfrlMTUKDNHr+W1Vpz4saS5HKoOW0kigRvC7pwxnZuApB8uLryQ4hp4YCUelY30B4a7ps/JtYntDg==
+ version "0.9.129"
+ resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.129.tgz#f2cdead99b8f25177c4c291be3032fb9ffd1dac3"
+ integrity sha512-RYWBcrz4MGICg9neIPQ4CbU3WTTJoTofi2D4pwA+qvvN3uhqOCcFIZ3+yadZ5Akz2qwMztQ8WDvetowm2srZcA==
dependencies:
- "@budibase/bbui" "^0.9.125"
+ "@budibase/bbui" "^0.9.129"
"@spectrum-css/button" "^3.0.3"
"@spectrum-css/card" "^3.0.3"
"@spectrum-css/divider" "^1.0.3"
@@ -172,10 +172,10 @@
svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0"
-"@budibase/string-templates@^0.9.125-alpha.5":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.128.tgz#50ee46dc0d726d481bd5139cd0b38364649a8463"
- integrity sha512-4TzmnX2o5S2cts08ukB86El4wYm7cHuV2t6a7yDMGPe1mWeKP1WEtVF6rKhXEdbPTiotW8oYondOlgOP7DT9lA==
+"@budibase/string-templates@^0.9.125-alpha.11":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.130.tgz#1be8affcba0dc8ff2b8044c65dd378dc76a165d0"
+ integrity sha512-DXO6Um18/k16i3hYilxvQ4RYNHhd29OJGbzjfQZ2v7z4Oin5y+WMZzpjX1hQS5g9f/CBbzu7qd7EHiz/n8gMqg==
dependencies:
"@budibase/handlebars-helpers" "^0.11.4"
dayjs "^1.10.4"
@@ -1272,7 +1272,12 @@ date.js@^0.3.1:
dependencies:
debug "~3.1.0"
-dayjs@^1.10.4, dayjs@^1.10.5:
+dayjs@^1.10.4:
+ version "1.10.7"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468"
+ integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==
+
+dayjs@^1.10.5:
version "1.10.6"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63"
integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==
diff --git a/packages/server/package.json b/packages/server/package.json
index c564e00d6..c5642c72c 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"description": "Budibase Web Server",
"main": "src/index.js",
"repository": {
@@ -49,7 +49,8 @@
"!src/automations/tests/**/*",
"!src/utilities/fileProcessor.js",
"!src/utilities/fileSystem/**/*",
- "!src/utilities/redis.js"
+ "!src/utilities/redis.js",
+ "!src/api/controllers/row/internalSearch.js"
],
"coverageReporters": [
"lcov",
@@ -63,9 +64,9 @@
"author": "Budibase",
"license": "AGPL-3.0-or-later",
"dependencies": {
- "@budibase/auth": "^0.9.125-alpha.7",
- "@budibase/client": "^0.9.125-alpha.7",
- "@budibase/string-templates": "^0.9.125-alpha.7",
+ "@budibase/auth": "^0.9.125-alpha.11",
+ "@budibase/client": "^0.9.125-alpha.11",
+ "@budibase/string-templates": "^0.9.125-alpha.11",
"@elastic/elasticsearch": "7.10.0",
"@koa/router": "8.0.0",
"@sendgrid/mail": "7.1.1",
diff --git a/packages/server/src/api/controllers/row/index.js b/packages/server/src/api/controllers/row/index.js
index a50afa77e..1d003ebd1 100644
--- a/packages/server/src/api/controllers/row/index.js
+++ b/packages/server/src/api/controllers/row/index.js
@@ -113,6 +113,7 @@ exports.destroy = async function (ctx) {
exports.search = async ctx => {
const tableId = getTableId(ctx)
try {
+ ctx.status = 200
ctx.body = await pickApi(tableId).search(ctx)
} catch (err) {
ctx.throw(400, err)
diff --git a/packages/server/src/automations/actions.js b/packages/server/src/automations/actions.js
index ef77387a4..13f7c487c 100644
--- a/packages/server/src/automations/actions.js
+++ b/packages/server/src/automations/actions.js
@@ -13,6 +13,7 @@ const zapier = require("./steps/zapier")
const integromat = require("./steps/integromat")
let filter = require("./steps/filter")
let delay = require("./steps/delay")
+let queryRow = require("./steps/queryRows")
const ACTION_IMPLS = {
SEND_EMAIL_SMTP: sendSmtpEmail.run,
@@ -26,6 +27,7 @@ const ACTION_IMPLS = {
SERVER_LOG: serverLog.run,
DELAY: delay.run,
FILTER: filter.run,
+ QUERY_ROWS: queryRow.run,
// these used to be lowercase step IDs, maintain for backwards compat
discord: discord.run,
slack: slack.run,
@@ -44,6 +46,7 @@ const ACTION_DEFINITIONS = {
SERVER_LOG: serverLog.definition,
DELAY: delay.definition,
FILTER: filter.definition,
+ QUERY_ROWS: queryRow.definition,
// these used to be lowercase step IDs, maintain for backwards compat
discord: discord.definition,
slack: slack.definition,
diff --git a/packages/server/src/automations/steps/bash.js b/packages/server/src/automations/steps/bash.js
index 6c44c1bbb..2be6ad7db 100644
--- a/packages/server/src/automations/steps/bash.js
+++ b/packages/server/src/automations/steps/bash.js
@@ -4,7 +4,7 @@ const { processStringSync } = require("@budibase/string-templates")
exports.definition = {
name: "Bash Scripting",
tagline: "Execute a bash command",
- icon: "ri-terminal-box-line",
+ icon: "JourneyEvent",
description: "Run a bash script",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/steps/createRow.js b/packages/server/src/automations/steps/createRow.js
index e3c90fb15..970612643 100644
--- a/packages/server/src/automations/steps/createRow.js
+++ b/packages/server/src/automations/steps/createRow.js
@@ -6,7 +6,7 @@ const usage = require("../../utilities/usageQuota")
exports.definition = {
name: "Create Row",
tagline: "Create a {{inputs.enriched.table.name}} row",
- icon: "ri-save-3-line",
+ icon: "TableRowAddBottom",
description: "Add a row to your database",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/steps/delay.js b/packages/server/src/automations/steps/delay.js
index 899d8f840..ad59df54c 100644
--- a/packages/server/src/automations/steps/delay.js
+++ b/packages/server/src/automations/steps/delay.js
@@ -2,7 +2,7 @@ let { wait } = require("../../utilities")
exports.definition = {
name: "Delay",
- icon: "ri-time-line",
+ icon: "Clock",
tagline: "Delay for {{inputs.time}} milliseconds",
description: "Delay the automation until an amount of time has passed",
stepId: "DELAY",
diff --git a/packages/server/src/automations/steps/deleteRow.js b/packages/server/src/automations/steps/deleteRow.js
index 10f39d2d0..26623d628 100644
--- a/packages/server/src/automations/steps/deleteRow.js
+++ b/packages/server/src/automations/steps/deleteRow.js
@@ -4,7 +4,7 @@ const usage = require("../../utilities/usageQuota")
exports.definition = {
description: "Delete a row from your database",
- icon: "ri-delete-bin-line",
+ icon: "TableRowRemoveCenter",
name: "Delete Row",
tagline: "Delete a {{inputs.enriched.table.name}} row",
type: "ACTION",
diff --git a/packages/server/src/automations/steps/executeQuery.js b/packages/server/src/automations/steps/executeQuery.js
index d5799a8f7..2ca0b2144 100644
--- a/packages/server/src/automations/steps/executeQuery.js
+++ b/packages/server/src/automations/steps/executeQuery.js
@@ -4,7 +4,7 @@ const { buildCtx } = require("./utils")
exports.definition = {
name: "External Data Connector",
tagline: "Execute Data Connector",
- icon: "ri-database-2-line",
+ icon: "Data",
description: "Execute a query in an external data connector",
type: "ACTION",
stepId: "EXECUTE_QUERY",
diff --git a/packages/server/src/automations/steps/executeScript.js b/packages/server/src/automations/steps/executeScript.js
index 70298b9f8..c56dfbd4e 100644
--- a/packages/server/src/automations/steps/executeScript.js
+++ b/packages/server/src/automations/steps/executeScript.js
@@ -4,7 +4,7 @@ const { buildCtx } = require("./utils")
exports.definition = {
name: "JS Scripting",
tagline: "Execute JavaScript Code",
- icon: "ri-terminal-box-line",
+ icon: "Code",
description: "Run a piece of JavaScript code in your automation",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/steps/filter.js b/packages/server/src/automations/steps/filter.js
index 84bdc10c1..80d3198cb 100644
--- a/packages/server/src/automations/steps/filter.js
+++ b/packages/server/src/automations/steps/filter.js
@@ -18,7 +18,7 @@ exports.PrettyFilterConditions = PrettyFilterConditions
exports.definition = {
name: "Filter",
tagline: "{{inputs.field}} {{inputs.condition}} {{inputs.value}}",
- icon: "ri-git-branch-line",
+ icon: "Branch2",
description: "Filter any automations which do not meet certain conditions",
type: "LOGIC",
internal: true,
diff --git a/packages/server/src/automations/steps/outgoingWebhook.js b/packages/server/src/automations/steps/outgoingWebhook.js
index ea0f0ce6b..6194e1052 100644
--- a/packages/server/src/automations/steps/outgoingWebhook.js
+++ b/packages/server/src/automations/steps/outgoingWebhook.js
@@ -20,7 +20,7 @@ const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH]
exports.definition = {
name: "Outgoing webhook",
tagline: "Send a {{inputs.requestMethod}} request",
- icon: "ri-send-plane-line",
+ icon: "Send",
description: "Send a request of specified method to a URL",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/steps/queryRows.js b/packages/server/src/automations/steps/queryRows.js
new file mode 100644
index 000000000..64b757418
--- /dev/null
+++ b/packages/server/src/automations/steps/queryRows.js
@@ -0,0 +1,119 @@
+const rowController = require("../../api/controllers/row")
+const tableController = require("../../api/controllers/table")
+const { FieldTypes } = require("../../constants")
+
+const SortOrders = {
+ ASCENDING: "ascending",
+ DESCENDING: "descending",
+}
+
+const SortOrdersPretty = {
+ [SortOrders.ASCENDING]: "Ascending",
+ [SortOrders.DESCENDING]: "Descending",
+}
+
+exports.definition = {
+ description: "Query rows from the database",
+ icon: "Search",
+ name: "Query rows",
+ tagline: "Query rows from {{inputs.enriched.table.name}} table",
+ type: "ACTION",
+ stepId: "QUERY_ROWS",
+ internal: true,
+ inputs: {},
+ schema: {
+ inputs: {
+ properties: {
+ tableId: {
+ type: "string",
+ customType: "table",
+ title: "Table",
+ },
+ filters: {
+ type: "object",
+ customType: "filters",
+ title: "Filtering",
+ },
+ sortColumn: {
+ type: "string",
+ title: "Sort Column",
+ customType: "column",
+ },
+ sortOrder: {
+ type: "string",
+ title: "Sort Order",
+ enum: Object.values(SortOrders),
+ pretty: Object.values(SortOrdersPretty),
+ },
+ limit: {
+ type: "number",
+ title: "Limit",
+ },
+ },
+ required: ["tableId"],
+ },
+ outputs: {
+ properties: {
+ rows: {
+ type: "array",
+ customType: "rows",
+ description: "The rows that were found",
+ },
+ success: {
+ type: "boolean",
+ description: "Whether the deletion was successful",
+ },
+ },
+ required: ["rows", "success"],
+ },
+ },
+}
+
+async function getTable(appId, tableId) {
+ const ctx = {
+ params: {
+ id: tableId,
+ },
+ appId,
+ }
+ await tableController.find(ctx)
+ return ctx.body
+}
+
+exports.run = async function ({ inputs, appId }) {
+ const { tableId, filters, sortColumn, sortOrder, limit } = inputs
+ const table = await getTable(appId, tableId)
+ let sortType = FieldTypes.STRING
+ if (table && table.schema && sortColumn) {
+ const fieldType = table.schema[sortColumn].type
+ sortType =
+ fieldType === FieldTypes.NUMBER ? FieldTypes.NUMBER : FieldTypes.STRING
+ }
+ const ctx = {
+ params: {
+ tableId,
+ },
+ request: {
+ body: {
+ sortOrder,
+ sortType,
+ sort: sortColumn,
+ query: filters || {},
+ limit,
+ },
+ },
+ appId,
+ }
+ try {
+ await rowController.search(ctx)
+ return {
+ rows: ctx.body ? ctx.body.rows : [],
+ success: ctx.status === 200,
+ }
+ } catch (err) {
+ return {
+ success: false,
+ response: err,
+ }
+ }
+}
diff --git a/packages/server/src/automations/steps/sendSmtpEmail.js b/packages/server/src/automations/steps/sendSmtpEmail.js
index 552c9b4d3..9e4b5a6a3 100644
--- a/packages/server/src/automations/steps/sendSmtpEmail.js
+++ b/packages/server/src/automations/steps/sendSmtpEmail.js
@@ -3,7 +3,7 @@ const { sendSmtpEmail } = require("../../utilities/workerRequests")
exports.definition = {
description: "Send an email using SMTP",
tagline: "Send SMTP email to {{inputs.to}}",
- icon: "ri-mail-open-line",
+ icon: "Email",
name: "Send Email (SMTP)",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/steps/serverLog.js b/packages/server/src/automations/steps/serverLog.js
index 82e7d073e..b88a731d5 100644
--- a/packages/server/src/automations/steps/serverLog.js
+++ b/packages/server/src/automations/steps/serverLog.js
@@ -7,7 +7,7 @@
exports.definition = {
name: "Backend log",
tagline: "Console log a value in the backend",
- icon: "ri-server-line",
+ icon: "Monitoring",
description: "Logs the given text to the server (using console.log)",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/steps/updateRow.js b/packages/server/src/automations/steps/updateRow.js
index 961f75dee..ac5eb16fc 100644
--- a/packages/server/src/automations/steps/updateRow.js
+++ b/packages/server/src/automations/steps/updateRow.js
@@ -4,7 +4,7 @@ const automationUtils = require("../automationUtils")
exports.definition = {
name: "Update Row",
tagline: "Update a {{inputs.enriched.table.name}} row",
- icon: "ri-refresh-line",
+ icon: "Refresh",
description: "Update a row in your database",
type: "ACTION",
internal: true,
diff --git a/packages/server/src/automations/tests/queryRows.spec.js b/packages/server/src/automations/tests/queryRows.spec.js
new file mode 100644
index 000000000..fca03f4e3
--- /dev/null
+++ b/packages/server/src/automations/tests/queryRows.spec.js
@@ -0,0 +1,51 @@
+// lucene searching not supported in test due to use of PouchDB
+let rows = []
+jest.mock("../../api/controllers/row/internalSearch", () => ({
+ fullSearch: jest.fn(() => {
+ return {
+ rows,
+ }
+ }),
+ paginatedSearch: jest.fn(),
+}))
+const setup = require("./utilities")
+
+const NAME = "Test"
+
+describe("Test a query step automation", () => {
+ let table
+ let config = setup.getConfig()
+
+ beforeEach(async () => {
+ await config.init()
+ table = await config.createTable()
+ const row = {
+ name: NAME,
+ description: "original description",
+ tableId: table._id,
+ }
+ rows.push(await config.createRow(row))
+ rows.push(await config.createRow(row))
+ })
+
+ afterAll(setup.afterAll)
+
+ it("should be able to run the query step", async () => {
+ const inputs = {
+ tableId: table._id,
+ filters: {
+ equal: {
+ name: NAME,
+ },
+ },
+ sortColumn: "name",
+ sortOrder: "ascending",
+ limit: 10,
+ }
+ const res = await setup.runStep(setup.actions.QUERY_ROWS.stepId, inputs)
+ expect(res.success).toBe(true)
+ expect(res.rows).toBeDefined()
+ expect(res.rows.length).toBe(2)
+ expect(res.rows[0].name).toBe(NAME)
+ })
+})
\ No newline at end of file
diff --git a/packages/server/src/automations/triggerInfo/app.js b/packages/server/src/automations/triggerInfo/app.js
index 1c64795cf..40d1531fa 100644
--- a/packages/server/src/automations/triggerInfo/app.js
+++ b/packages/server/src/automations/triggerInfo/app.js
@@ -1,7 +1,7 @@
exports.definition = {
name: "App Action",
event: "app:trigger",
- icon: "ri-window-fill",
+ icon: "Apps",
tagline: "Automation fired from the frontend",
description: "Trigger an automation from an action inside your app",
stepId: "APP",
diff --git a/packages/server/src/automations/triggerInfo/cron.js b/packages/server/src/automations/triggerInfo/cron.js
index 31e79a4ab..9547da69f 100644
--- a/packages/server/src/automations/triggerInfo/cron.js
+++ b/packages/server/src/automations/triggerInfo/cron.js
@@ -1,7 +1,7 @@
exports.definition = {
name: "Cron Trigger",
event: "cron:trigger",
- icon: "ri-timer-line",
+ icon: "Clock",
tagline: "Cron Trigger ({{inputs.cron}})",
description: "Triggers automation on a cron schedule.",
stepId: "CRON",
diff --git a/packages/server/src/automations/triggerInfo/rowDeleted.js b/packages/server/src/automations/triggerInfo/rowDeleted.js
index c7ead1fec..7a7de13b1 100644
--- a/packages/server/src/automations/triggerInfo/rowDeleted.js
+++ b/packages/server/src/automations/triggerInfo/rowDeleted.js
@@ -1,7 +1,7 @@
exports.definition = {
name: "Row Deleted",
event: "row:delete",
- icon: "ri-delete-bin-line",
+ icon: "TableRowRemoveCenter",
tagline: "Row is deleted from {{inputs.enriched.table.name}}",
description: "Fired when a row is deleted from your database",
stepId: "ROW_DELETED",
diff --git a/packages/server/src/automations/triggerInfo/rowSaved.js b/packages/server/src/automations/triggerInfo/rowSaved.js
index 3a21a2687..d763ca0a8 100644
--- a/packages/server/src/automations/triggerInfo/rowSaved.js
+++ b/packages/server/src/automations/triggerInfo/rowSaved.js
@@ -1,7 +1,7 @@
exports.definition = {
name: "Row Created",
event: "row:save",
- icon: "ri-save-line",
+ icon: "TableRowAddBottom",
tagline: "Row is added to {{inputs.enriched.table.name}}",
description: "Fired when a row is added to your database",
stepId: "ROW_SAVED",
diff --git a/packages/server/src/automations/triggerInfo/rowUpdated.js b/packages/server/src/automations/triggerInfo/rowUpdated.js
index 099ce0a6b..182c7c810 100644
--- a/packages/server/src/automations/triggerInfo/rowUpdated.js
+++ b/packages/server/src/automations/triggerInfo/rowUpdated.js
@@ -1,7 +1,7 @@
exports.definition = {
name: "Row Updated",
event: "row:update",
- icon: "ri-refresh-line",
+ icon: "Refresh",
tagline: "Row is updated in {{inputs.enriched.table.name}}",
description: "Fired when a row is updated in your database",
stepId: "ROW_UPDATED",
diff --git a/packages/server/src/automations/triggerInfo/webhook.js b/packages/server/src/automations/triggerInfo/webhook.js
index dd83031d8..56e139311 100644
--- a/packages/server/src/automations/triggerInfo/webhook.js
+++ b/packages/server/src/automations/triggerInfo/webhook.js
@@ -1,7 +1,7 @@
exports.definition = {
name: "Webhook",
event: "web:trigger",
- icon: "ri-global-line",
+ icon: "Send",
tagline: "Webhook endpoint is hit",
description: "Trigger an automation when a HTTP POST webhook is hit",
stepId: "WEBHOOK",
diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock
index 115566194..609839ee9 100644
--- a/packages/server/yarn.lock
+++ b/packages/server/yarn.lock
@@ -943,10 +943,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@budibase/auth@^0.9.125-alpha.7":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.128.tgz#6bb6c716b6647b7e9362e3faf12b191650ea0ad4"
- integrity sha512-WCcrtAXilT/4++7PdzyTYgrdVqZcKhUev3NcGrFQf7WbDhkVCuigWbb8Q01KXODjbs0BZC0RshVv/PxrgLbBQA==
+"@budibase/auth@^0.9.125-alpha.11":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.130.tgz#04ff77b862e87e22b08ee7bebd5409ff479a2b35"
+ integrity sha512-wCgbnk8YvBtRQhmWd7w9UGNLL1ocJPHCq10652Dxm8nLnY0oAsgzVVoMsMULyTypfHiYtUEnOs7+JQ/nYa2zkA==
dependencies:
"@techpass/passport-openidconnect" "^0.3.0"
aws-sdk "^2.901.0"
@@ -1015,10 +1015,10 @@
svelte-flatpickr "^3.1.0"
svelte-portal "^1.0.0"
-"@budibase/bbui@^0.9.128":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.128.tgz#71a5e81b02a4f64baa6874bfa4b1d4fed8cc9f0b"
- integrity sha512-UCo9SRs1xsMQ0ClJOtNB7JeVF2+0iMVOfAZE7Rrf5d51W+1YeyM9b3BbfhxHRq1yeKLHrbdczerbTHQkmF1RwQ==
+"@budibase/bbui@^0.9.130":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.130.tgz#cad02a7aa16324eb7a056c5dc0162444fa917964"
+ integrity sha512-ULOC++363K8QEMasmsDmleF7AzjulFk/ZxGPlOJcVKJU8Bx5wG1uNFgTyJyGpmnbUWHd67eYUEettfH7I+VoOw==
dependencies:
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
"@spectrum-css/actionbutton" "^1.0.1"
@@ -1064,14 +1064,14 @@
svelte-flatpickr "^3.1.0"
svelte-portal "^1.0.0"
-"@budibase/client@^0.9.125-alpha.7":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.128.tgz#894f1e9c73cb10b30565e8828244f7ff04a34fce"
- integrity sha512-/CiijM5O/6yc5gtSAFBMP7eJE686QNX1FsCphpA89DjWdNEG5e2e0ZN9Z7AOTD90BUn7JXEAdvmqwDMGF5m8gg==
+"@budibase/client@^0.9.125-alpha.11":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.130.tgz#efff68349667ad315cda2973d530cfe8a30b10d3"
+ integrity sha512-PJiOqEf7QF2/MS5CK9WkJl5JYSz/IBDQ1/H665V4Q1Kf5Y/hL+ymXaC5ztWPt6CZlo6dSoAZaD81h7zd6XeuYA==
dependencies:
- "@budibase/bbui" "^0.9.128"
- "@budibase/standard-components" "^0.9.128"
- "@budibase/string-templates" "^0.9.128"
+ "@budibase/bbui" "^0.9.130"
+ "@budibase/standard-components" "^0.9.130"
+ "@budibase/string-templates" "^0.9.130"
regexparam "^1.3.0"
shortid "^2.2.15"
svelte-spa-router "^3.0.5"
@@ -1122,12 +1122,12 @@
svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0"
-"@budibase/standard-components@^0.9.128":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.128.tgz#5d6e1dd751c6927dcf1ee515a6102bf73b315526"
- integrity sha512-fB6BOwk5uhPxW+U+TrIdD+zXU/l22S2YFcjXhaSpYVM+inzih9e+v2FVy2aW0Y85FdJ+MqT420o9EaolSF0p1w==
+"@budibase/standard-components@^0.9.130":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.130.tgz#ed24eaafcca959e15c76b81e2340371d268ab131"
+ integrity sha512-hsLKnVciI+is6L42IDDcZ8sW/aLD0UyYLQd/hqMZT8WBf58908ujY3nwFZnxV30uwjSmiZeYCYmK3vbHDD0ljQ==
dependencies:
- "@budibase/bbui" "^0.9.128"
+ "@budibase/bbui" "^0.9.130"
"@spectrum-css/button" "^3.0.3"
"@spectrum-css/card" "^3.0.3"
"@spectrum-css/divider" "^1.0.3"
@@ -1140,10 +1140,10 @@
svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0"
-"@budibase/string-templates@^0.9.125-alpha.7", "@budibase/string-templates@^0.9.128":
- version "0.9.128"
- resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.128.tgz#50ee46dc0d726d481bd5139cd0b38364649a8463"
- integrity sha512-4TzmnX2o5S2cts08ukB86El4wYm7cHuV2t6a7yDMGPe1mWeKP1WEtVF6rKhXEdbPTiotW8oYondOlgOP7DT9lA==
+"@budibase/string-templates@^0.9.125-alpha.11", "@budibase/string-templates@^0.9.130":
+ version "0.9.130"
+ resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.130.tgz#1be8affcba0dc8ff2b8044c65dd378dc76a165d0"
+ integrity sha512-DXO6Um18/k16i3hYilxvQ4RYNHhd29OJGbzjfQZ2v7z4Oin5y+WMZzpjX1hQS5g9f/CBbzu7qd7EHiz/n8gMqg==
dependencies:
"@budibase/handlebars-helpers" "^0.11.4"
dayjs "^1.10.4"
diff --git a/packages/string-templates/manifest.json b/packages/string-templates/manifest.json
index 02bd7f8a6..629bb2ebe 100644
--- a/packages/string-templates/manifest.json
+++ b/packages/string-templates/manifest.json
@@ -1090,6 +1090,115 @@
"description": "Block helper that always renders the inverse block unless a is less than or equal to b.
\n"
}
},
+ "object": {
+ "extend": {
+ "args": [
+ "objects"
+ ],
+ "numArgs": 1,
+ "description": "Extend the context with the properties of other objects. A shallow merge is performed to avoid mutating the context.
\n"
+ },
+ "forIn": {
+ "args": [
+ "context",
+ "options"
+ ],
+ "numArgs": 2,
+ "description": "Block helper that iterates over the properties of an object, exposing each key and value on the context.
\n"
+ },
+ "forOwn": {
+ "args": [
+ "obj",
+ "options"
+ ],
+ "numArgs": 2,
+ "description": "Block helper that iterates over the own properties of an object, exposing each key and value on the context.
\n"
+ },
+ "toPath": {
+ "args": [
+ "prop"
+ ],
+ "numArgs": 1,
+ "description": "Take arguments and, if they are string or number, convert them to a dot-delineated object property path.
\n"
+ },
+ "get": {
+ "args": [
+ "prop",
+ "context",
+ "options"
+ ],
+ "numArgs": 3,
+ "description": "Use property paths (a.b.c) to get a value or nested value from the context. Works as a regular helper or block helper.
\n"
+ },
+ "getObject": {
+ "args": [
+ "prop",
+ "context"
+ ],
+ "numArgs": 2,
+ "description": "Use property paths (a.b.c) to get an object from the context. Differs from the get helper in that this helper will return the actual object, including the given property key. Also, this helper does not work as a block helper.
\n"
+ },
+ "hasOwn": {
+ "args": [
+ "key",
+ "context"
+ ],
+ "numArgs": 2,
+ "description": "Return true if key is an own, enumerable property of the given context object.
\n"
+ },
+ "isObject": {
+ "args": [
+ "value"
+ ],
+ "numArgs": 1,
+ "description": "Return true if value is an object.
\n"
+ },
+ "JSONparse": {
+ "args": [
+ "string"
+ ],
+ "numArgs": 1,
+ "description": "Parses the given string using JSON.parse.
\n"
+ },
+ "JSONstringify": {
+ "args": [
+ "obj"
+ ],
+ "numArgs": 1,
+ "description": "Stringify an object using JSON.stringify.
\n"
+ },
+ "merge": {
+ "args": [
+ "object",
+ "objects"
+ ],
+ "numArgs": 2,
+ "description": "Deeply merge the properties of the given objects with the context object.
\n"
+ },
+ "parseJSON": {
+ "args": [
+ "string"
+ ],
+ "numArgs": 1,
+ "description": "Parses the given string using JSON.parse.
\n"
+ },
+ "pick": {
+ "args": [
+ "properties",
+ "context",
+ "options"
+ ],
+ "numArgs": 3,
+ "description": "Pick properties from the context object.
\n"
+ },
+ "stringify": {
+ "args": [
+ "obj"
+ ],
+ "numArgs": 1,
+ "description": "Stringify an object using JSON.stringify.
\n"
+ }
+ },
"date": {
"date": {
"args": [
diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json
index 43b1f6f7d..b97b79601 100644
--- a/packages/string-templates/package.json
+++ b/packages/string-templates/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",
diff --git a/packages/string-templates/scripts/gen-collection-info.js b/packages/string-templates/scripts/gen-collection-info.js
index fcd3cb492..29df10423 100644
--- a/packages/string-templates/scripts/gen-collection-info.js
+++ b/packages/string-templates/scripts/gen-collection-info.js
@@ -11,7 +11,15 @@ const marked = require("marked")
*/
const DIRECTORY = fs.existsSync("node_modules") ? "." : ".."
-const COLLECTIONS = ["math", "array", "number", "url", "string", "comparison"]
+const COLLECTIONS = [
+ "math",
+ "array",
+ "number",
+ "url",
+ "string",
+ "comparison",
+ "object",
+]
const FILENAME = `${DIRECTORY}/manifest.json`
const outputJSON = {}
const ADDED_HELPERS = {
diff --git a/packages/worker/package.json b/packages/worker/package.json
index 59258e388..89e86f6da 100644
--- a/packages/worker/package.json
+++ b/packages/worker/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
- "version": "0.9.125-alpha.7",
+ "version": "0.9.125-alpha.11",
"description": "Budibase background service",
"main": "src/index.js",
"repository": {
@@ -25,8 +25,8 @@
"author": "Budibase",
"license": "AGPL-3.0-or-later",
"dependencies": {
- "@budibase/auth": "^0.9.125-alpha.7",
- "@budibase/string-templates": "^0.9.125-alpha.7",
+ "@budibase/auth": "^0.9.125-alpha.11",
+ "@budibase/string-templates": "^0.9.125-alpha.11",
"@koa/router": "^8.0.0",
"@techpass/passport-openidconnect": "^0.3.0",
"aws-sdk": "^2.811.0",
diff --git a/packages/worker/src/api/controllers/global/users.js b/packages/worker/src/api/controllers/global/users.js
index 13959273c..415808bf8 100644
--- a/packages/worker/src/api/controllers/global/users.js
+++ b/packages/worker/src/api/controllers/global/users.js
@@ -197,10 +197,10 @@ exports.getSelf = async ctx => {
// this will set the body
await exports.find(ctx)
- // append the account portal session information if present
- if (ctx.user.account) {
- ctx.body.account = ctx.user.account
- }
+ // forward session information not found in db
+ ctx.body.account = ctx.user.account
+ ctx.body.budibaseAccess = ctx.user.budibaseAccess
+ ctx.body.accountPortalAccess = ctx.user.accountPortalAccess
}
exports.updateSelf = async ctx => {
diff --git a/packages/worker/src/api/index.js b/packages/worker/src/api/index.js
index 03e782688..e3cc6efbc 100644
--- a/packages/worker/src/api/index.js
+++ b/packages/worker/src/api/index.js
@@ -84,7 +84,10 @@ router
.use(buildTenancyMiddleware(PUBLIC_ENDPOINTS, NO_TENANCY_ENDPOINTS))
// for now no public access is allowed to worker (bar health check)
.use((ctx, next) => {
- if (!ctx.isAuthenticated && !ctx.publicEndpoint) {
+ if (ctx.publicEndpoint) {
+ return next()
+ }
+ if (!ctx.isAuthenticated || !ctx.user.budibaseAccess) {
ctx.throw(403, "Unauthorized - no public worker access")
}
return next()