Add ability for user to select 'List' data type for a column
This commit is contained in:
parent
bf52642893
commit
295e36f576
|
@ -0,0 +1,17 @@
|
||||||
|
<script>
|
||||||
|
import "@spectrum-css/label/dist/index-vars.css"
|
||||||
|
import { Badge } from "@budibase/bbui"
|
||||||
|
export let value
|
||||||
|
|
||||||
|
const displayLimit = 5
|
||||||
|
|
||||||
|
$: badges = value?.slice(0, displayLimit) ?? []
|
||||||
|
$: leftover = (value?.length ?? 0) - badges.length
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each badges as badge}
|
||||||
|
<Badge size="S" grey>{badge}</Badge>
|
||||||
|
{/each}
|
||||||
|
{#if leftover}
|
||||||
|
<div>+{leftover} more</div>
|
||||||
|
{/if}
|
|
@ -4,7 +4,7 @@
|
||||||
import DateTimeRenderer from "./DateTimeRenderer.svelte"
|
import DateTimeRenderer from "./DateTimeRenderer.svelte"
|
||||||
import RelationshipRenderer from "./RelationshipRenderer.svelte"
|
import RelationshipRenderer from "./RelationshipRenderer.svelte"
|
||||||
import AttachmentRenderer from "./AttachmentRenderer.svelte"
|
import AttachmentRenderer from "./AttachmentRenderer.svelte"
|
||||||
|
import ArrayRenderer from "./ArrayRenderer.svelte"
|
||||||
export let row
|
export let row
|
||||||
export let schema
|
export let schema
|
||||||
export let value
|
export let value
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
options: StringRenderer,
|
options: StringRenderer,
|
||||||
number: StringRenderer,
|
number: StringRenderer,
|
||||||
longform: StringRenderer,
|
longform: StringRenderer,
|
||||||
|
array: ArrayRenderer,
|
||||||
}
|
}
|
||||||
$: type = schema?.type ?? "string"
|
$: type = schema?.type ?? "string"
|
||||||
$: customRenderer = customRenderers?.find(x => x.column === schema?.name)
|
$: customRenderer = customRenderers?.find(x => x.column === schema?.name)
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { Input, Select, DatePicker, Toggle, TextArea } from "@budibase/bbui"
|
import {
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
DatePicker,
|
||||||
|
Toggle,
|
||||||
|
TextArea,
|
||||||
|
Multiselect,
|
||||||
|
} from "@budibase/bbui"
|
||||||
import Dropzone from "components/common/Dropzone.svelte"
|
import Dropzone from "components/common/Dropzone.svelte"
|
||||||
import { capitalise } from "helpers"
|
import { capitalise } from "helpers"
|
||||||
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
|
import LinkedRowSelector from "components/common/LinkedRowSelector.svelte"
|
||||||
|
@ -26,6 +33,11 @@
|
||||||
<Dropzone {label} bind:value />
|
<Dropzone {label} bind:value />
|
||||||
{:else if type === "boolean"}
|
{:else if type === "boolean"}
|
||||||
<Toggle text={label} bind:value data-cy="{meta.name}-input" />
|
<Toggle text={label} bind:value data-cy="{meta.name}-input" />
|
||||||
|
{:else if type === "array"}
|
||||||
|
<Multiselect
|
||||||
|
bind:value
|
||||||
|
options={meta.constraints.inclusion.reduce((p, n) => p.concat(n), [])}
|
||||||
|
/>
|
||||||
{:else if type === "link"}
|
{:else if type === "link"}
|
||||||
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
|
<LinkedRowSelector bind:linkedRows={value} schema={meta} />
|
||||||
{:else if type === "longform"}
|
{:else if type === "longform"}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
const AUTO_TYPE = "auto"
|
const AUTO_TYPE = "auto"
|
||||||
const FORMULA_TYPE = FIELDS.FORMULA.type
|
const FORMULA_TYPE = FIELDS.FORMULA.type
|
||||||
|
const ARRAY_TYPE = FIELDS.ARRAY.type
|
||||||
const LINK_TYPE = FIELDS.LINK.type
|
const LINK_TYPE = FIELDS.LINK.type
|
||||||
let fieldDefinitions = cloneDeep(FIELDS)
|
let fieldDefinitions = cloneDeep(FIELDS)
|
||||||
const { hide } = getContext(Context.Modal)
|
const { hide } = getContext(Context.Modal)
|
||||||
|
@ -81,6 +82,13 @@
|
||||||
if (field.type === AUTO_TYPE) {
|
if (field.type === AUTO_TYPE) {
|
||||||
field = buildAutoColumn($tables.draft.name, field.name, field.subtype)
|
field = buildAutoColumn($tables.draft.name, field.name, field.subtype)
|
||||||
}
|
}
|
||||||
|
if (field.type === ARRAY_TYPE) {
|
||||||
|
let arr = field.constraints.inclusion
|
||||||
|
let newArr = []
|
||||||
|
newArr.push(arr)
|
||||||
|
console.log(newArr)
|
||||||
|
field.constraints.inclusion = newArr
|
||||||
|
}
|
||||||
tables.saveField({
|
tables.saveField({
|
||||||
originalName,
|
originalName,
|
||||||
field,
|
field,
|
||||||
|
@ -262,6 +270,11 @@
|
||||||
label="Options (one per line)"
|
label="Options (one per line)"
|
||||||
bind:values={field.constraints.inclusion}
|
bind:values={field.constraints.inclusion}
|
||||||
/>
|
/>
|
||||||
|
{:else if field.type === "array"}
|
||||||
|
<ValuesList
|
||||||
|
label="Options (one per line)"
|
||||||
|
bind:values={field.constraints.inclusion}
|
||||||
|
/>
|
||||||
{:else if field.type === "datetime"}
|
{:else if field.type === "datetime"}
|
||||||
<DatePicker
|
<DatePicker
|
||||||
label="Earliest"
|
label="Earliest"
|
||||||
|
|
|
@ -113,6 +113,10 @@
|
||||||
label: "Options",
|
label: "Options",
|
||||||
value: FIELDS.OPTIONS.type,
|
value: FIELDS.OPTIONS.type,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "List",
|
||||||
|
value: FIELDS.ARRAY.type,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,15 @@ export const FIELDS = {
|
||||||
inclusion: [],
|
inclusion: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ARRAY: {
|
||||||
|
name: "List",
|
||||||
|
type: "array",
|
||||||
|
constraints: {
|
||||||
|
type: "array",
|
||||||
|
presence: false,
|
||||||
|
inclusion: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
NUMBER: {
|
NUMBER: {
|
||||||
name: "Number",
|
name: "Number",
|
||||||
type: "number",
|
type: "number",
|
||||||
|
|
|
@ -58,12 +58,24 @@ exports.validate = async ({ appId, tableId, row, table }) => {
|
||||||
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
||||||
// special case for options, need to always allow unselected (null)
|
// special case for options, need to always allow unselected (null)
|
||||||
if (
|
if (
|
||||||
table.schema[fieldName].type === FieldTypes.OPTIONS &&
|
table.schema[fieldName].type ===
|
||||||
|
(FieldTypes.OPTIONS || FieldTypes.ARRAY) &&
|
||||||
constraints.inclusion
|
constraints.inclusion
|
||||||
) {
|
) {
|
||||||
constraints.inclusion.push(null)
|
constraints.inclusion.push(null)
|
||||||
}
|
}
|
||||||
const res = validateJs.single(row[fieldName], constraints)
|
let res
|
||||||
|
|
||||||
|
// Validate.js doesn't seem to handle array of array very well
|
||||||
|
if (table.schema[fieldName].type === FieldTypes.ARRAY) {
|
||||||
|
row[fieldName].map(val => {
|
||||||
|
if (constraints.inclusion.includes(val)) {
|
||||||
|
errors[fieldName] = "Field not in list"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res = validateJs.single(row[fieldName], constraints)
|
||||||
|
}
|
||||||
if (res) errors[fieldName] = res
|
if (res) errors[fieldName] = res
|
||||||
}
|
}
|
||||||
return { valid: Object.keys(errors).length === 0, errors }
|
return { valid: Object.keys(errors).length === 0, errors }
|
||||||
|
|
|
@ -12,6 +12,7 @@ exports.FieldTypes = {
|
||||||
OPTIONS: "options",
|
OPTIONS: "options",
|
||||||
NUMBER: "number",
|
NUMBER: "number",
|
||||||
BOOLEAN: "boolean",
|
BOOLEAN: "boolean",
|
||||||
|
ARRAY: "array",
|
||||||
DATETIME: "datetime",
|
DATETIME: "datetime",
|
||||||
ATTACHMENT: "attachment",
|
ATTACHMENT: "attachment",
|
||||||
LINK: "link",
|
LINK: "link",
|
||||||
|
|
|
@ -29,6 +29,11 @@ const TYPE_TRANSFORM_MAP = {
|
||||||
[null]: null,
|
[null]: null,
|
||||||
[undefined]: undefined,
|
[undefined]: undefined,
|
||||||
},
|
},
|
||||||
|
[FieldTypes.ARRAY]: {
|
||||||
|
"": [],
|
||||||
|
[null]: [],
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
[FieldTypes.STRING]: {
|
[FieldTypes.STRING]: {
|
||||||
"": "",
|
"": "",
|
||||||
[null]: "",
|
[null]: "",
|
||||||
|
|
Loading…
Reference in New Issue