diff --git a/lerna.json b/lerna.json
index 8b7e036ddc..c1939719a8 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "0.9.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"npmClient": "yarn",
"packages": [
"packages/*"
diff --git a/packages/auth/package.json b/packages/auth/package.json
index 72ca7c90d7..2aec96c6f8 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/auth",
- "version": "0.9.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"description": "Authentication middlewares for budibase builder and apps",
"main": "src/index.js",
"author": "Budibase",
diff --git a/packages/bbui/package.json b/packages/bbui/package.json
index 6d0bc1a8fc..b50a3ded2c 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.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",
diff --git a/packages/builder/package.json b/packages/builder/package.json
index ecda1be172..7774dfbffc 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
- "version": "0.9.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"license": "GPL-3.0",
"private": true,
"scripts": {
@@ -65,10 +65,10 @@
}
},
"dependencies": {
- "@budibase/bbui": "^0.9.190-alpha.8",
- "@budibase/client": "^0.9.190-alpha.8",
+ "@budibase/bbui": "^0.9.190-alpha.12",
+ "@budibase/client": "^0.9.190-alpha.12",
"@budibase/colorpicker": "1.1.2",
- "@budibase/string-templates": "^0.9.190-alpha.8",
+ "@budibase/string-templates": "^0.9.190-alpha.12",
"@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/frontend.js b/packages/builder/src/builderStore/store/frontend.js
index 1f1fb035a4..c94c759792 100644
--- a/packages/builder/src/builderStore/store/frontend.js
+++ b/packages/builder/src/builderStore/store/frontend.js
@@ -524,7 +524,7 @@ export const getFrontendStore = () => {
}
}
},
- paste: async (targetComponent, mode) => {
+ paste: async (targetComponent, mode, preserveBindings = false) => {
let promises = []
store.update(state => {
// Stop if we have nothing to paste
@@ -536,7 +536,7 @@ export const getFrontendStore = () => {
const cut = state.componentToPaste.isCut
// immediately need to remove bindings, currently these aren't valid when pasted
- if (!cut) {
+ if (!cut && !preserveBindings) {
state.componentToPaste = removeBindings(state.componentToPaste)
}
diff --git a/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte b/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte
index 06293e4168..56c5eef2ad 100644
--- a/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte
+++ b/packages/builder/src/components/design/NavigationPanel/ComponentDropdownMenu.svelte
@@ -53,7 +53,7 @@
const duplicateComponent = () => {
storeComponentForCopy(false)
- pasteComponent("below")
+ pasteComponent("below", true)
}
const deleteComponent = async () => {
@@ -69,9 +69,9 @@
store.actions.components.copy(component, cut)
}
- const pasteComponent = mode => {
+ const pasteComponent = (mode, preserveBindings = false) => {
// lives in store - also used by drag drop
- store.actions.components.paste(component, mode)
+ store.actions.components.paste(component, mode, preserveBindings)
}
diff --git a/packages/builder/src/components/design/NavigationPanel/FrontendNavigatePane.svelte b/packages/builder/src/components/design/NavigationPanel/FrontendNavigatePane.svelte
index 51dd44026e..ea9ebbf2c5 100644
--- a/packages/builder/src/components/design/NavigationPanel/FrontendNavigatePane.svelte
+++ b/packages/builder/src/components/design/NavigationPanel/FrontendNavigatePane.svelte
@@ -25,8 +25,7 @@
key: "layout",
},
]
-
- let modal
+ let newLayoutModal
$: selected = tabs.find(t => t.key === $params.assetType)?.title || "Screens"
const navigate = ({ detail }) => {
@@ -93,14 +92,18 @@
{#each $store.layouts as layout, idx (layout._id)}
0} />
{/each}
-
+
-
+
diff --git a/packages/builder/src/components/design/NavigationPanel/NewScreenModal.svelte b/packages/builder/src/components/design/NavigationPanel/NewScreenModal.svelte
index fbd1fc9256..67dbf581f2 100644
--- a/packages/builder/src/components/design/NavigationPanel/NewScreenModal.svelte
+++ b/packages/builder/src/components/design/NavigationPanel/NewScreenModal.svelte
@@ -10,16 +10,39 @@
ProgressCircle,
} from "@budibase/bbui"
import getTemplates from "builderStore/store/screenTemplates"
+ import { onDestroy } from "svelte"
+
+ import { createEventDispatcher } from "svelte"
- export let selectedScreens = []
export let chooseModal
export let save
export let showProgressCircle = false
+
+ let selectedScreens = []
+
const blankScreen = "createFromScratch"
+ const dispatch = createEventDispatcher()
+
+ function setScreens() {
+ dispatch("save", {
+ screens: selectedScreens,
+ })
+ }
$: blankSelected = selectedScreens?.length === 1
$: autoSelected = selectedScreens?.length > 0 && !blankSelected
+
let templates = getTemplates($store, $tables.list)
+
+ const confirm = async () => {
+ if (autoSelected) {
+ setScreens()
+ await save()
+ } else {
+ setScreens()
+ chooseModal(1)
+ }
+ }
const toggleScreenSelection = table => {
if (selectedScreens.find(s => s.table === table.name)) {
selectedScreens = selectedScreens.filter(
@@ -32,14 +55,18 @@
selectedScreens = [...partialTemplates, ...selectedScreens]
}
}
+
+ onDestroy(() => {
+ selectedScreens = []
+ })
-
+
(autoSelected ? save() : chooseModal(1))}
+ onConfirm={() => confirm()}
disabled={!selectedScreens.length}
size="L"
>
@@ -70,29 +97,31 @@
{/if}
- Autogenerated Screens
+ {#if $tables.list.filter(table => table._id !== "ta_users").length > 0}
+ Autogenerated Screens
- {#each $tables.list.filter(table => table._id !== "ta_users") as table}
- x.table === table.name)}
- on:click={() => toggleScreenSelection(table)}
- class="item"
- >
-
+ {#each $tables.list.filter(table => table._id !== "ta_users") as table}
x.table === table.name)}
+ on:click={() => toggleScreenSelection(table)}
+ class="item"
>
- {#if selectedScreens.find(x => x.table === table.name)}
-
-
-
- {/if}
+
+
+ {#if selectedScreens.find(x => x.table === table.name)}
+
+
+
+ {/if}
+
-
- {/each}
+ {/each}
+ {/if}
{#if showProgressCircle}
diff --git a/packages/builder/src/components/design/NavigationPanel/ScreenDetailsModal.svelte b/packages/builder/src/components/design/NavigationPanel/ScreenDetailsModal.svelte
index e5cc839045..6d906da742 100644
--- a/packages/builder/src/components/design/NavigationPanel/ScreenDetailsModal.svelte
+++ b/packages/builder/src/components/design/NavigationPanel/ScreenDetailsModal.svelte
@@ -2,6 +2,7 @@
import { ModalContent, Input, ProgressCircle } from "@budibase/bbui"
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
import { selectedAccessRole, allScreens } from "builderStore"
+ import { onDestroy } from "svelte"
export let screenName
export let url
@@ -32,6 +33,11 @@
screen.routing.roleId === roleId
)
}
+
+ onDestroy(() => {
+ screenName = ""
+ url = ""
+ })
{
let existingScreenCount = $store.screens.filter(
s => s.props._instanceName == draftScreen.props._instanceName
@@ -90,17 +89,14 @@
)
}
- onDestroy(() => {
- selectedScreens = []
- screenName = ""
- url = ""
- createdScreens = []
- })
-
export const showModal = () => {
newScreenModal.show()
}
+ const setScreens = evt => {
+ selectedScreens = evt.detail.screens
+ }
+
const chooseModal = index => {
/*
0 = newScreenModal
@@ -119,7 +115,7 @@
{
- dispatch("change", value)
+ dispatch("change", links)
drawer.hide()
}
@@ -19,5 +21,5 @@
Configure the links in your navigation bar.
-
+
diff --git a/packages/cli/package.json b/packages/cli/package.json
index e37a6f6cad..b43b28a9fc 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
- "version": "0.9.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"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 0ab9d0fc65..32781cfedc 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/client",
- "version": "0.9.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"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.190-alpha.8",
+ "@budibase/bbui": "^0.9.190-alpha.12",
"@budibase/standard-components": "^0.9.139",
- "@budibase/string-templates": "^0.9.190-alpha.8",
+ "@budibase/string-templates": "^0.9.190-alpha.12",
"regexparam": "^1.3.0",
"shortid": "^2.2.15",
"svelte-spa-router": "^3.0.5"
diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte
index 87e5ac3b5b..59765f9305 100644
--- a/packages/client/src/components/app/Layout.svelte
+++ b/packages/client/src/components/app/Layout.svelte
@@ -313,6 +313,9 @@
height: 100%;
overflow: auto;
}
+ .desktop.layout--left .links {
+ overflow-y: auto;
+ }
.desktop .nav--left {
width: 250px;
@@ -379,6 +382,7 @@
justify-content: flex-start;
align-items: stretch;
padding: var(--spacing-xl);
+ overflow-y: auto;
}
.mobile .link {
width: calc(100% - 30px);
diff --git a/packages/server/package.json b/packages/server/package.json
index a16ff8bc49..5966cc81fc 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.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@@ -69,9 +69,9 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
- "@budibase/auth": "^0.9.190-alpha.8",
- "@budibase/client": "^0.9.190-alpha.8",
- "@budibase/string-templates": "^0.9.190-alpha.8",
+ "@budibase/auth": "^0.9.190-alpha.12",
+ "@budibase/client": "^0.9.190-alpha.12",
+ "@budibase/string-templates": "^0.9.190-alpha.12",
"@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0",
diff --git a/packages/server/scripts/integrations/oracle/docker-compose.yml b/packages/server/scripts/integrations/oracle/docker-compose.yml
index 5cd5e02f81..c54cd0a40b 100644
--- a/packages/server/scripts/integrations/oracle/docker-compose.yml
+++ b/packages/server/scripts/integrations/oracle/docker-compose.yml
@@ -4,7 +4,7 @@
version: "3.8"
services:
db:
- container_name: oracle-xe
+ restart: always
platform: linux/x86_64
image: container-registry.oracle.com/database/express:18.4.0-xe
environment:
diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts
index 2226dc99be..af199561dc 100644
--- a/packages/server/src/api/controllers/row/ExternalRequest.ts
+++ b/packages/server/src/api/controllers/row/ExternalRequest.ts
@@ -1,4 +1,5 @@
import {
+ FilterTypes,
IncludeRelationships,
Operation,
PaginationJson,
@@ -118,8 +119,13 @@ module External {
}
// check the row and filters to make sure they aren't a key of some sort
if (config.filters) {
- for (let filter of Object.values(config.filters)) {
- if (typeof filter !== "object" || Object.keys(filter).length === 0) {
+ for (let [key, filter] of Object.entries(config.filters)) {
+ // oneOf is an array, don't iterate it
+ if (
+ typeof filter !== "object" ||
+ Object.keys(filter).length === 0 ||
+ key === FilterTypes.ONE_OF
+ ) {
continue
}
iterateObject(filter)
diff --git a/packages/server/src/definitions/datasource.ts b/packages/server/src/definitions/datasource.ts
index 3760f54f2c..eb65ac994f 100644
--- a/packages/server/src/definitions/datasource.ts
+++ b/packages/server/src/definitions/datasource.ts
@@ -54,6 +54,17 @@ export enum IncludeRelationships {
EXCLUDE = 0,
}
+export enum FilterTypes {
+ STRING = "string",
+ FUZZY = "fuzzy",
+ RANGE = "range",
+ EQUAL = "equal",
+ NOT_EQUAL = "notEqual",
+ EMPTY = "empty",
+ NOT_EMPTY = "notEmpty",
+ ONE_OF = "oneOf",
+}
+
export interface QueryDefinition {
type: QueryTypes
displayName?: string
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 471774db3d..df4f2d511b 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -93,7 +93,7 @@ class InternalBuilder {
if (filters.oneOf) {
iterate(filters.oneOf, (key, array) => {
const fnc = allOr ? "orWhereIn" : "whereIn"
- query = query[fnc](key, array)
+ query = query[fnc](key, Array.isArray(array) ? array : [array])
})
}
if (filters.string) {
@@ -435,8 +435,6 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
id = results?.[0].id
} else if (sqlClient === SqlClients.MY_SQL) {
id = results?.insertId
- } else if (sqlClient === SqlClients.ORACLE) {
- id = response.outBinds[0][0]
}
row = processFn(
await this.getReturningRow(queryFn, this.checkLookupKeys(id, json))
diff --git a/packages/server/src/integrations/oracle.ts b/packages/server/src/integrations/oracle.ts
index 13658399db..bf8e83350e 100644
--- a/packages/server/src/integrations/oracle.ts
+++ b/packages/server/src/integrations/oracle.ts
@@ -348,27 +348,7 @@ module OracleModule {
this.schemaErrors = final.errors
}
- /**
- * Knex default returning behaviour does not work with oracle
- * Manually add the behaviour for the return column
- */
- private addReturning(
- query: SqlQuery,
- bindings: BindParameters,
- returnColumn: string
- ) {
- if (bindings instanceof Array) {
- bindings.push({ dir: oracledb.BIND_OUT })
- query.sql =
- query.sql + ` returning \"${returnColumn}\" into :${bindings.length}`
- }
- }
-
- private async internalQuery(
- query: SqlQuery,
- returnColum?: string,
- operation?: string
- ): Promise> {
+ private async internalQuery(query: SqlQuery): Promise> {
let connection
try {
connection = await this.getConnection()
@@ -376,13 +356,6 @@ module OracleModule {
const options: ExecuteOptions = { autoCommit: true }
const bindings: BindParameters = query.bindings || []
- if (
- returnColum &&
- (operation === Operation.CREATE || operation === Operation.UPDATE)
- ) {
- this.addReturning(query, bindings, returnColum)
- }
-
const result: Result = await connection.execute(
query.sql,
bindings,
@@ -441,13 +414,46 @@ module OracleModule {
}
async query(json: QueryJson) {
- const primaryKeys = json.meta!.table!.primary
- const primaryKey = primaryKeys ? primaryKeys[0] : undefined
- const queryFn = (query: any, operation: string) =>
- this.internalQuery(query, primaryKey, operation)
- const processFn = (response: any) => (response.rows ? response.rows : [])
- const output = await this.queryWithReturning(json, queryFn, processFn)
- return output
+ const operation = this._operation(json)
+ const input = this._query(json, { disableReturning: true })
+ if (Array.isArray(input)) {
+ const responses = []
+ for (let query of input) {
+ responses.push(await this.internalQuery(query))
+ }
+ return responses
+ } else {
+ // read the row to be deleted up front for the return
+ let deletedRows
+ if (operation === Operation.DELETE) {
+ const queryFn = (query: any) => this.internalQuery(query)
+ deletedRows = await this.getReturningRow(queryFn, json)
+ }
+
+ // run the query
+ const response = await this.internalQuery(input)
+
+ // get the results or return the created / updated / deleted row
+ if (deletedRows?.rows?.length) {
+ return deletedRows.rows
+ } else if (response.rows?.length) {
+ return response.rows
+ } else {
+ // get the last row that was updated
+ if (
+ response.lastRowid &&
+ json.endpoint?.entityId &&
+ operation !== Operation.DELETE
+ ) {
+ const lastRow = await this.internalQuery({
+ sql: `SELECT * FROM \"${json.endpoint.entityId}\" WHERE ROWID = '${response.lastRowid}'`,
+ })
+ return lastRow.rows
+ } else {
+ return [{ [ operation.toLowerCase() ]: true }]
+ }
+ }
+ }
}
}
diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json
index b4203429f4..2fafa1f7ab 100644
--- a/packages/string-templates/package.json
+++ b/packages/string-templates/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
- "version": "0.9.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",
diff --git a/packages/worker/package.json b/packages/worker/package.json
index 10389c2f1d..6ac6b2ab61 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.190-alpha.8",
+ "version": "0.9.190-alpha.12",
"description": "Budibase background service",
"main": "src/index.js",
"repository": {
@@ -29,8 +29,8 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
- "@budibase/auth": "^0.9.190-alpha.8",
- "@budibase/string-templates": "^0.9.190-alpha.8",
+ "@budibase/auth": "^0.9.190-alpha.12",
+ "@budibase/string-templates": "^0.9.190-alpha.12",
"@koa/router": "^8.0.0",
"@sentry/node": "^6.0.0",
"@techpass/passport-openidconnect": "^0.3.0",