@@ -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 dfcfc2ab95..e774c366a5 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 d1c5d104d3..8e6cb42ee2 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,158 @@
}
return bindings
}
+
+ function lookForFilters(properties) {
+ 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 +269,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 810e452742..1b410cd86a 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 99f41908e7..3f390e0a4f 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 1257563ff8..54f5b90164 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 4f9ac05a06..ceb28a37ca 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 42ea30dbb0..84c737eb67 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/ConfigChecklist.svelte b/packages/builder/src/components/common/ConfigChecklist.svelte
index 7914a78b65..05f3f7c719 100644
--- a/packages/builder/src/components/common/ConfigChecklist.svelte
+++ b/packages/builder/src/components/common/ConfigChecklist.svelte
@@ -8,9 +8,28 @@
} from "@budibase/bbui"
import { admin } from "stores/portal"
import { goto } from "@roxi/routify"
+ import { onMount } from "svelte"
+
+ let width = window.innerWidth
+ $: side = width < 500 ? "right" : "left"
+
+ const resizeObserver = new ResizeObserver(entries => {
+ if (entries?.[0]) {
+ width = entries[0].contentRect?.width
+ }
+ })
+
+ onMount(() => {
+ const doc = document.documentElement
+ resizeObserver.observe(doc)
+
+ return () => {
+ resizeObserver.unobserve(doc)
+ }
+ })
-
+
@@ -37,7 +56,7 @@
.item {
display: grid;
align-items: center;
- grid-template-columns: 200px 20px;
+ grid-template-columns: 175px 20px;
}
.icon {
cursor: pointer;
diff --git a/packages/builder/src/components/common/NavItem.svelte b/packages/builder/src/components/common/NavItem.svelte
index 977369299d..ec7994be84 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 ee2487a9d6..e5bfab583c 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 a8f1b507f4..3901252ee9 100644
--- a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
+++ b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
@@ -1,6 +1,6 @@
@@ -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/components/start/AppRow.svelte b/packages/builder/src/components/start/AppRow.svelte
index e953027192..a80722733e 100644
--- a/packages/builder/src/components/start/AppRow.svelte
+++ b/packages/builder/src/components/start/AppRow.svelte
@@ -28,7 +28,7 @@
-
+
{#if app.updatedAt}
{processStringSync("Updated {{ duration time 'millisecond' }} ago", {
time: new Date().getTime() - new Date(app.updatedAt).getTime(),
@@ -37,7 +37,7 @@
Never updated
{/if}
-
+
-
+
{#if app.deployed}Published{:else}Unpublished{/if}
@@ -109,4 +109,10 @@
cursor: pointer;
transition: color 130ms ease;
}
+
+ @media (max-width: 640px) {
+ .desktop {
+ display: none !important;
+ }
+ }
diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte
index b70190c706..4310d3322e 100644
--- a/packages/builder/src/components/start/CreateAppModal.svelte
+++ b/packages/builder/src/components/start/CreateAppModal.svelte
@@ -134,7 +134,7 @@
{
- 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 d1aaeb0240..841acb22c0 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 d48bd36e59..e5dea10e0b 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/apps/index.svelte b/packages/builder/src/pages/builder/apps/index.svelte
index c1bdc31cd4..2f9f87d4f6 100644
--- a/packages/builder/src/pages/builder/apps/index.svelte
+++ b/packages/builder/src/pages/builder/apps/index.svelte
@@ -41,17 +41,8 @@
-
-
-
-
- Hey {$auth.user.firstName || $auth.user.email}
-
-
- Welcome to the {$organisation.company} portal. Below you'll find
- the list of apps that you have access to.
-
-
+