Add validation for array field

This commit is contained in:
Peter Clement 2021-08-25 14:05:23 +01:00
parent 04ce0abd46
commit 84d85664ef
5 changed files with 43 additions and 13 deletions

View File

@ -9,6 +9,7 @@
Body, Body,
Input, Input,
DatePicker, DatePicker,
Multiselect,
} from "@budibase/bbui" } from "@budibase/bbui"
import { currentAsset, selectedComponent } from "builderStore" import { currentAsset, selectedComponent } from "builderStore"
import { findClosestMatchingComponent } from "builderStore/storeUtils" import { findClosestMatchingComponent } from "builderStore/storeUtils"
@ -102,6 +103,11 @@
Constraints.MinLength, Constraints.MinLength,
Constraints.MaxLength, Constraints.MaxLength,
], ],
["array"]: [
Constraints.Required,
Constraints.MinLength,
Constraints.MaxLength,
],
} }
$: dataSourceSchema = getDataSourceSchema($currentAsset, $selectedComponent) $: dataSourceSchema = getDataSourceSchema($currentAsset, $selectedComponent)
@ -109,7 +115,6 @@
$: schemaRules = parseRulesFromSchema(field, dataSourceSchema || {}) $: schemaRules = parseRulesFromSchema(field, dataSourceSchema || {})
$: fieldType = type?.split("/")[1] || "string" $: fieldType = type?.split("/")[1] || "string"
$: constraintOptions = getConstraintsForType(fieldType) $: constraintOptions = getConstraintsForType(fieldType)
const getConstraintsForType = type => { const getConstraintsForType = type => {
return ConstraintMap[type] return ConstraintMap[type]
} }
@ -283,7 +288,7 @@
/> />
{:else} {:else}
<!-- Otherwise we render a component based on the type --> <!-- Otherwise we render a component based on the type -->
{#if ["string", "number", "options", "longform"].includes(rule.type)} {#if ["string", "number", "options", "longform", "array"].includes(rule.type)}
<Input <Input
disabled={rule.constraint === "required"} disabled={rule.constraint === "required"}
bind:value={rule.value} bind:value={rule.value}

View File

@ -47,6 +47,7 @@ const componentMap = {
// Some validation types are the same as others, so not all types are // Some validation types are the same as others, so not all types are
// explicitly listed here. e.g. options uses string validation // explicitly listed here. e.g. options uses string validation
"validation/string": ValidationEditor, "validation/string": ValidationEditor,
"validation/array": ValidationEditor,
"validation/number": ValidationEditor, "validation/number": ValidationEditor,
"validation/boolean": ValidationEditor, "validation/boolean": ValidationEditor,
"validation/datetime": ValidationEditor, "validation/datetime": ValidationEditor,

View File

@ -2101,7 +2101,7 @@
} }
}, },
{ {
"type": "validation/string", "type": "validation/array",
"label": "Validation", "label": "Validation",
"key": "validation" "key": "validation"
} }

View File

@ -40,10 +40,15 @@
bind:fieldApi bind:fieldApi
bind:fieldSchema bind:fieldSchema
> >
{#if fieldState}
<Multiselect <Multiselect
getOptionLabel={flatOptions ? x => x : x => x.label} getOptionLabel={flatOptions ? x => x : x => x.label}
getOptionValue={flatOptions ? x => x : x => x.value} getOptionValue={flatOptions ? x => x : x => x.value}
id={$fieldState.fieldId}
disabled={$fieldState.disabled}
on:change={e => fieldApi.setValue(e.detail)}
{placeholder} {placeholder}
{options} {options}
/> />
{/if}
</Field> </Field>

View File

@ -25,7 +25,7 @@ export const createValidatorFromConstraints = (
schemaConstraints.presence?.allowEmpty === false schemaConstraints.presence?.allowEmpty === false
) { ) {
rules.push({ rules.push({
type: "string", type: schemaConstraints.type == "array" ? "array" : "string",
constraint: "required", constraint: "required",
error: "Required", error: "Required",
}) })
@ -63,7 +63,7 @@ export const createValidatorFromConstraints = (
} }
// Inclusion constraint // Inclusion constraint
if (exists(schemaConstraints.inclusion)) { if (!schemaConstraints.type == "array" ? exists(schemaConstraints.inclusion) : false) {
const options = schemaConstraints.inclusion || [] const options = schemaConstraints.inclusion || []
rules.push({ rules.push({
type: "string", type: "string",
@ -73,6 +73,18 @@ export const createValidatorFromConstraints = (
}) })
} }
// Inclusion constraint
if (schemaConstraints.type == "array" ? exists(schemaConstraints.inclusion[0]) : false ) {
const options = schemaConstraints.inclusion[0] || []
rules.push({
type: "array",
constraint: "inclusion",
value: options,
error: "Invalid value",
})
}
// Date constraint // Date constraint
if (exists(schemaConstraints.datetime?.earliest)) { if (exists(schemaConstraints.datetime?.earliest)) {
const limit = schemaConstraints.datetime.earliest const limit = schemaConstraints.datetime.earliest
@ -142,7 +154,7 @@ const evaluateRule = (rule, value) => {
* in the same format. * in the same format.
* @param value the value to parse * @param value the value to parse
* @param type the type to parse * @param type the type to parse
* @returns {boolean|string|*|number|null} the parsed value, or null if invalid * @returns {boolean|string|*|number|null|array} the parsed value, or null if invalid
*/ */
const parseType = (value, type) => { const parseType = (value, type) => {
// Treat nulls or empty strings as null // Treat nulls or empty strings as null
@ -202,6 +214,13 @@ const parseType = (value, type) => {
return value return value
} }
if (type === "array") {
if (!Array.isArray(value) || !value.length) {
return null
}
return value
}
// If some unknown type, treat as null to avoid breaking validators // If some unknown type, treat as null to avoid breaking validators
return null return null
} }
@ -239,7 +258,7 @@ const maxValueHandler = (value, rule) => {
// Evaluates an inclusion constraint // Evaluates an inclusion constraint
const inclusionHandler = (value, rule) => { const inclusionHandler = (value, rule) => {
return value == null || rule.value.includes(value) return value == null || rule.type == "array" ? rule.value.map(val => val === value) : rule.value.includes(value)
} }
// Evaluates an equal constraint // Evaluates an equal constraint