Merge branch 'feature/json-backend' of github.com:Budibase/budibase into feature/json-backend

This commit is contained in:
Andrew Kingston 2021-11-30 13:41:58 +00:00
commit ba9d06df34
19 changed files with 179 additions and 55 deletions

View File

@ -1,5 +1,5 @@
{
"version": "0.9.190-alpha.11",
"version": "0.9.190-alpha.12",
"npmClient": "yarn",
"packages": [
"packages/*"

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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
}

View File

@ -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)
}

View File

@ -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) : ""
</script>
@ -40,6 +44,14 @@
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
{:else if type === "longform"}
<TextArea {label} bind:value />
{:else if type === "json"}
<Label>{label}</Label>
<Editor
editorHeight="250"
mode="json"
on:change={({ detail }) => (value = detail.value)}
value={stringVal}
/>
{:else}
<Input
{label}

View File

@ -87,7 +87,10 @@
field.subtype !== AUTO_COLUMN_SUB_TYPES.CREATED_BY &&
field.subtype !== AUTO_COLUMN_SUB_TYPES.UPDATED_BY &&
field.type !== FORMULA_TYPE
$: canBeDisplay = field.type !== LINK_TYPE && field.type !== AUTO_TYPE
$: canBeDisplay =
field.type !== LINK_TYPE &&
field.type !== AUTO_TYPE &&
field.type !== JSON_TYPE
$: canBeRequired =
field.type !== LINK_TYPE && !uneditable && field.type !== AUTO_TYPE
$: relationshipOptions = getRelationshipOptions(field)
@ -452,7 +455,14 @@
</div>
</ModalContent>
<Modal bind:this={jsonSchemaModal}>
<JSONSchemaModal on:save={({ detail }) => console.log(detail)} />
<JSONSchemaModal
schema={field.schema}
json={field.json}
on:save={({ detail }) => {
field.schema = detail.schema
field.json = detail.json
}}
/>
</Modal>
<ConfirmDialog
bind:this={confirmDeleteDialog}

View File

@ -9,36 +9,42 @@
Select,
} from "@budibase/bbui"
import { onMount, createEventDispatcher } from "svelte"
import { FIELDS } from "constants/backend"
import { generate } from "builderStore/schemaGenerator"
export let schema = {}
export let json
let dispatcher = createEventDispatcher()
let mode = "Key/Value"
let json
let fieldCount = 0
let fieldKeys = {},
fieldTypes = {}
let keyValueOptions = ["String", "Number", "Boolean", "Object", "Array"]
let keyValueOptions = [
{ label: "String", value: FIELDS.STRING.type },
{ label: "Number", value: FIELDS.NUMBER.type },
{ label: "Boolean", value: FIELDS.BOOLEAN.type },
{ label: "Object", value: FIELDS.JSON.type },
{ label: "Array", value: FIELDS.ARRAY.type },
]
let invalid = false
$: invalid = false
function onJsonUpdate({ detail }) {
// TODO: make request
async function onJsonUpdate({ detail }) {
const input = detail.value
console.log(input)
}
function saveSchema() {
for (let i of Object.keys(fieldKeys)) {
const key = fieldKeys[i]
schema[key] = {
type: fieldTypes[i],
}
json = input
try {
// check json valid first
let inputJson = JSON.parse(input)
schema = generate(inputJson)
updateCounts()
invalid = false
} catch (err) {
// json not currently valid
invalid = true
}
dispatcher("save", schema)
}
onMount(() => {
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()
})
</script>
@ -56,7 +80,7 @@
title={"Key/Value Schema Editor"}
confirmText="Save Column"
onConfirm={saveSchema}
disabled={invalid}
bind:disabled={invalid}
size="L"
>
<Tabs selected={mode} noPadding>
@ -68,7 +92,8 @@
label="Type"
options={keyValueOptions}
bind:value={fieldTypes[i]}
getOptionValue={field => field.toLowerCase()}
getOptionValue={field => field.value}
getOptionLabel={field => field.label}
/>
</div>
{/each}

View File

@ -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)
}
</script>

View File

@ -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()
}
</script>
@ -19,5 +21,5 @@
Configure the links in your navigation bar.
</svelte:fragment>
<Button cta slot="buttons" on:click={save}>Save</Button>
<NavigationDrawer slot="body" bind:links={value} />
<NavigationDrawer slot="body" bind:links />
</Drawer>

View File

@ -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": {

View File

@ -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"

View File

@ -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);

View File

@ -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",

View File

@ -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

View File

@ -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
}
},
},
}
/**

View File

@ -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",

View File

@ -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",