Browse Source

Add new form field component for JSON fields, JSON validation and update autoscreen generation

pull/3776/head
Andrew Kingston 5 years ago
parent
commit
b362068d47
  1. 1
      packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js
  2. 3
      packages/builder/src/components/design/AppPreview/componentStructure.json
  3. 1
      packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js
  4. 34
      packages/client/manifest.json
  5. 71
      packages/client/src/components/app/forms/JSONField.svelte
  6. 33
      packages/client/src/components/app/forms/LongFormField.svelte
  7. 1
      packages/client/src/components/app/forms/index.js
  8. 21
      packages/client/src/components/app/forms/validation.js
  9. 1
      packages/client/src/constants.js

1
packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js

@ -137,6 +137,7 @@ const fieldTypeToComponentMap = {
datetime: "datetimefield",
attachment: "attachmentfield",
link: "relationshipfield",
json: "jsonfield",
}
export function makeDatasourceFormComponents(datasource) {

3
packages/builder/src/components/design/AppPreview/componentStructure.json

@ -43,7 +43,8 @@
"attachmentfield",
"relationshipfield",
"daterangepicker",
"multifieldselect"
"multifieldselect",
"jsonfield"
]
},
{

1
packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js

@ -45,6 +45,7 @@ const componentMap = {
"field/attachment": FormFieldSelect,
"field/link": FormFieldSelect,
"field/array": FormFieldSelect,
"field/json": FormFieldSelect,
// Some validation types are the same as others, so not all types are
// explicitly listed here. e.g. options uses string validation
"validation/string": ValidationEditor,

34
packages/client/manifest.json

@ -2418,6 +2418,40 @@
}
]
},
"jsonfield": {
"name": "Key/Value Field",
"icon": "Brackets",
"styles": ["size"],
"editable": true,
"settings": [
{
"type": "field/json",
"label": "Field",
"key": "field"
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "text",
"label": "Placeholder",
"key": "placeholder"
},
{
"type": "text",
"label": "Default value",
"key": "defaultValue"
},
{
"type": "boolean",
"label": "Disabled",
"key": "disabled",
"defaultValue": false
}
]
},
"dataprovider": {
"name": "Data Provider",
"info": "Pagination is only available for data stored in tables.",

71
packages/client/src/components/app/forms/JSONField.svelte

@ -0,0 +1,71 @@
<script>
import { CoreTextArea } from "@budibase/bbui"
import Field from "./Field.svelte"
import { getContext } from "svelte"
export let field
export let label
export let placeholder
export let disabled = false
export let defaultValue = ""
const component = getContext("component")
const validation = [
{
constraint: "json",
type: "json",
error: "JSON syntax is invalid",
},
]
let fieldState
let fieldApi
$: height = $component.styles?.normal?.height || "124px"
const serialiseValue = value => {
return JSON.stringify(value || undefined, null, 4) || ""
}
const parseValue = value => {
try {
return JSON.parse(value)
} catch (error) {
return value
}
}
</script>
<Field
{label}
{field}
{disabled}
{validation}
{defaultValue}
type="json"
bind:fieldState
bind:fieldApi
>
{#if fieldState}
<div style="--height: {height};">
<CoreTextArea
value={serialiseValue(fieldState.value)}
on:change={e => fieldApi.setValue(parseValue(e.detail))}
disabled={fieldState.disabled}
error={fieldState.error}
id={fieldState.fieldId}
{placeholder}
/>
</div>
{/if}
</Field>
<style>
:global(.spectrum-Form-itemField .spectrum-Textfield--multiline) {
min-height: calc(var(--height) - 24px);
}
:global(.spectrum-Form--labelsAbove
.spectrum-Form-itemField
.spectrum-Textfield--multiline) {
min-height: calc(var(--height) - 24px);
}
</style>

33
packages/client/src/components/app/forms/LongFormField.svelte

@ -1,6 +1,7 @@
<script>
import { CoreTextArea } from "@budibase/bbui"
import Field from "./Field.svelte"
import { getContext } from "svelte"
export let field
export let label
@ -11,6 +12,9 @@
let fieldState
let fieldApi
const component = getContext("component")
$: height = $component.styles?.normal?.height || "124px"
</script>
<Field
@ -24,13 +28,26 @@
bind:fieldApi
>
{#if fieldState}
<CoreTextArea
value={fieldState.value}
on:change={e => fieldApi.setValue(e.detail)}
disabled={fieldState.disabled}
error={fieldState.error}
id={fieldState.fieldId}
{placeholder}
/>
<div style="--height: {height};">
<CoreTextArea
value={fieldState.value}
on:change={e => fieldApi.setValue(e.detail)}
disabled={fieldState.disabled}
error={fieldState.error}
id={fieldState.fieldId}
{placeholder}
/>
</div>
{/if}
</Field>
<style>
:global(.spectrum-Form-itemField .spectrum-Textfield--multiline) {
min-height: calc(var(--height) - 24px);
}
:global(.spectrum-Form--labelsAbove
.spectrum-Form-itemField
.spectrum-Textfield--multiline) {
min-height: calc(var(--height) - 24px);
}
</style>

1
packages/client/src/components/app/forms/index.js

@ -11,3 +11,4 @@ export { default as attachmentfield } from "./AttachmentField.svelte"
export { default as relationshipfield } from "./RelationshipField.svelte"
export { default as passwordfield } from "./PasswordField.svelte"
export { default as formstep } from "./FormStep.svelte"
export { default as jsonfield } from "./JSONField.svelte"

21
packages/client/src/components/app/forms/validation.js

@ -206,6 +206,7 @@ const parseType = (value, type) => {
return value
}
// Parse array, treating no elements as null
if (type === FieldTypes.ARRAY) {
if (!Array.isArray(value) || !value.length) {
return null
@ -213,6 +214,12 @@ const parseType = (value, type) => {
return value
}
// For JSON we don't touch the value at all as we want to verify it in its
// raw form
if (type === FieldTypes.JSON) {
return value
}
// If some unknown type, treat as null to avoid breaking validators
return null
}
@ -290,6 +297,19 @@ const notContainsHandler = (value, rule) => {
return !containsHandler(value, rule)
}
// Evaluates a constraint that the value must be a valid json object
const jsonHandler = value => {
if (typeof value !== "object" || Array.isArray(value)) {
return false
}
try {
JSON.parse(JSON.stringify(value))
return true
} catch (error) {
return false
}
}
/**
* Map of constraint types to handlers.
*/
@ -306,6 +326,7 @@ const handlerMap = {
notRegex: notRegexHandler,
contains: containsHandler,
notContains: notContainsHandler,
json: jsonHandler,
}
/**

1
packages/client/src/constants.js

@ -13,6 +13,7 @@ export const FieldTypes = {
ATTACHMENT: "attachment",
LINK: "link",
FORMULA: "formula",
JSON: "json",
}
export const UnsortableTypes = [

Loading…
Cancel
Save