diff --git a/lerna.json b/lerna.json
index f2b3975169..c1939719a8 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "0.9.190-alpha.11",
+ "version": "0.9.190-alpha.12",
"npmClient": "yarn",
"packages": [
"packages/*"
diff --git a/packages/auth/package.json b/packages/auth/package.json
index 6987c8c88b..2aec96c6f8 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/auth",
- "version": "0.9.190-alpha.11",
+ "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 814a4971bf..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.11",
+ "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 1f7996d1b2..7774dfbffc 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
- "version": "0.9.190-alpha.11",
+ "version": "0.9.190-alpha.12",
"license": "GPL-3.0",
"private": true,
"scripts": {
@@ -65,10 +65,10 @@
}
},
"dependencies": {
- "@budibase/bbui": "^0.9.190-alpha.11",
- "@budibase/client": "^0.9.190-alpha.11",
+ "@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.11",
+ "@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/schemaGenerator.js b/packages/builder/src/builderStore/schemaGenerator.js
new file mode 100644
index 0000000000..33115fc997
--- /dev/null
+++ b/packages/builder/src/builderStore/schemaGenerator.js
@@ -0,0 +1,56 @@
+import { FIELDS } from "constants/backend"
+
+function baseConversion(type) {
+ if (type === "string") {
+ return {
+ type: FIELDS.STRING.type,
+ }
+ } else if (type === "boolean") {
+ return {
+ type: FIELDS.BOOLEAN.type,
+ }
+ } else if (type === "number") {
+ return {
+ type: FIELDS.NUMBER.type,
+ }
+ }
+}
+
+function recurse(schemaLevel = {}, objectLevel) {
+ if (!objectLevel) {
+ return null
+ }
+ const baseType = typeof objectLevel
+ if (baseType !== "object") {
+ return baseConversion(baseType)
+ }
+ for (let [key, value] of Object.entries(objectLevel)) {
+ const type = typeof value
+ // check array first, since arrays are objects
+ if (Array.isArray(value)) {
+ const schema = recurse(schemaLevel[key], value[0])
+ if (schema) {
+ schemaLevel[key] = {
+ type: FIELDS.ARRAY.type,
+ schema,
+ }
+ }
+ } else if (type === "object") {
+ const schema = recurse(schemaLevel[key], objectLevel[key])
+ if (schema) {
+ schemaLevel[key] = schema
+ }
+ } else {
+ schemaLevel[key] = baseConversion(type)
+ }
+ }
+ if (!schemaLevel.type) {
+ return { type: FIELDS.JSON.type, schema: schemaLevel }
+ } else {
+ return schemaLevel
+ }
+}
+
+export function generate(object) {
+ return recurse({}, object).schema
+}
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/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
index 25ad67b52e..0d9ca3644b 100644
--- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
+++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
@@ -6,16 +6,20 @@
Toggle,
TextArea,
Multiselect,
+ Label,
} from "@budibase/bbui"
import Dropzone from "components/common/Dropzone.svelte"
import { capitalise } from "helpers"
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
+ import Editor from "../../integration/QueryEditor.svelte"
export let defaultValue
export let meta
export let value = defaultValue || (meta.type === "boolean" ? false : "")
export let readonly
+ $: stringVal =
+ typeof value === "object" ? JSON.stringify(value, null, 2) : value
$: type = meta?.type
$: label = meta.name ? capitalise(meta.name) : ""
@@ -40,6 +44,14 @@
{:else if type === "longform"}
+{:else if type === "json"}
+
+ (value = detail.value)}
+ value={stringVal}
+ />
{:else}
- console.log(detail)} />
+ {
+ field.schema = detail.schema
+ field.json = detail.json
+ }}
+ />
{
+ function updateCounts() {
if (!schema) {
schema = {}
}
@@ -49,6 +55,24 @@
i++
}
fieldCount = i
+ }
+
+ function saveSchema() {
+ for (let i of Object.keys(fieldKeys)) {
+ const key = fieldKeys[i]
+ // they were added to schema, rather than generated
+ if (!schema[key]) {
+ schema[key] = {
+ type: fieldTypes[i],
+ }
+ }
+ }
+
+ dispatcher("save", { schema, json })
+ }
+
+ onMount(() => {
+ updateCounts()
})
@@ -56,7 +80,7 @@
title={"Key/Value Schema Editor"}
confirmText="Save Column"
onConfirm={saveSchema}
- disabled={invalid}
+ bind:disabled={invalid}
size="L"
>
@@ -68,7 +92,8 @@
label="Type"
options={keyValueOptions}
bind:value={fieldTypes[i]}
- getOptionValue={field => field.toLowerCase()}
+ getOptionValue={field => field.value}
+ getOptionLabel={field => field.label}
/>
{/each}
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/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte
index b7a272e608..ea02b4184d 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/NavigationEditor/NavigationEditor.svelte
@@ -2,13 +2,15 @@
import { Button, ActionButton, Drawer } from "@budibase/bbui"
import { createEventDispatcher } from "svelte"
import NavigationDrawer from "./NavigationDrawer.svelte"
+ import { cloneDeep } from "lodash/fp"
export let value = []
let drawer
+ let links = cloneDeep(value)
const dispatch = createEventDispatcher()
const save = () => {
- 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 e37ef7f849..b43b28a9fc 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
- "version": "0.9.190-alpha.11",
+ "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 96e6ea76cb..32781cfedc 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/client",
- "version": "0.9.190-alpha.11",
+ "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.11",
+ "@budibase/bbui": "^0.9.190-alpha.12",
"@budibase/standard-components": "^0.9.139",
- "@budibase/string-templates": "^0.9.190-alpha.11",
+ "@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 eea2b18124..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.11",
+ "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.11",
- "@budibase/client": "^0.9.190-alpha.11",
- "@budibase/string-templates": "^0.9.190-alpha.11",
+ "@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/src/api/controllers/row/utils.js b/packages/server/src/api/controllers/row/utils.js
index f7a4b13304..71b22375f7 100644
--- a/packages/server/src/api/controllers/row/utils.js
+++ b/packages/server/src/api/controllers/row/utils.js
@@ -50,10 +50,10 @@ exports.validate = async ({ appId, tableId, row, table }) => {
const errors = {}
for (let fieldName of Object.keys(table.schema)) {
const constraints = cloneDeep(table.schema[fieldName].constraints)
+ const type = table.schema[fieldName].type
// special case for options, need to always allow unselected (null)
if (
- table.schema[fieldName].type ===
- (FieldTypes.OPTIONS || FieldTypes.ARRAY) &&
+ (type === FieldTypes.OPTIONS || type === FieldTypes.ARRAY) &&
constraints.inclusion
) {
constraints.inclusion.push(null)
@@ -61,17 +61,20 @@ exports.validate = async ({ appId, tableId, row, table }) => {
let res
// Validate.js doesn't seem to handle array
- if (
- table.schema[fieldName].type === FieldTypes.ARRAY &&
- row[fieldName] &&
- row[fieldName].length
- ) {
+ if (type === FieldTypes.ARRAY && row[fieldName] && row[fieldName].length) {
row[fieldName].map(val => {
if (!constraints.inclusion.includes(val)) {
errors[fieldName] = "Field not in list"
}
})
- } else if (table.schema[fieldName].type === FieldTypes.FORMULA) {
+ } else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
+ // this should only happen if there is an error
+ try {
+ JSON.parse(row[fieldName])
+ } catch (err) {
+ errors[fieldName] = [`Contains invalid JSON`]
+ }
+ } else if (type === FieldTypes.FORMULA) {
res = validateJs.single(
processStringSync(table.schema[fieldName].formula, row),
constraints
diff --git a/packages/server/src/utilities/rowProcessor/index.js b/packages/server/src/utilities/rowProcessor/index.js
index ea63c23f7d..860063f173 100644
--- a/packages/server/src/utilities/rowProcessor/index.js
+++ b/packages/server/src/utilities/rowProcessor/index.js
@@ -81,6 +81,18 @@ const TYPE_TRANSFORM_MAP = {
[FieldTypes.AUTO]: {
parse: () => undefined,
},
+ [FieldTypes.JSON]: {
+ parse: input => {
+ try {
+ if (input === "") {
+ return undefined
+ }
+ return JSON.parse(input)
+ } catch (err) {
+ return input
+ }
+ },
+ },
}
/**
diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json
index 7378b79b60..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.11",
+ "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 63c392d275..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.11",
+ "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.11",
- "@budibase/string-templates": "^0.9.190-alpha.11",
+ "@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",