1
0
Fork 0
mirror of synced 2024-06-26 18:10:51 +12:00

create model & record - validation hooked up again

This commit is contained in:
Michael Shanks 2020-05-28 22:26:32 +01:00
parent bab7e3ed9e
commit 96c525363a
3 changed files with 69 additions and 34 deletions

View file

@ -13,17 +13,33 @@
const FIELD_TYPES = ["string", "number", "boolean"] const FIELD_TYPES = ["string", "number", "boolean"]
export let field = { type: "string" } export let field = { type: "string", constraints: { type: "string", presence: false } }
export let schema export let schema
export let goBack export let goBack
let errors = [] let errors = []
let draftField = cloneDeep(field) let draftField = cloneDeep(field)
let type = field.type
let constraints = field.constraints
let required = field.constraints.presence && !field.constraints.presence.allowEmpty
const save = () => { const save = () => {
constraints.presence = required ? { allowEmpty: false } : false
draftField.constraints = constraints
draftField.type = type
schema[field.name] = draftField schema[field.name] = draftField
goBack() goBack()
} }
$: constraints =
type === "string" ? { type: "string", length: {}, presence: false }
: type === "number" ? { type: "number", presence: false, numericality: {} }
: type === "boolean" ? { type: "boolean", presence: false }
: type === "datetime" ? { type: "date", datetime: {}, presence: false }
: type.startsWith('array') ? { type: "array", presence: false }
: { type: "string", presence: false }
</script> </script>
<div class="root"> <div class="root">
@ -34,30 +50,22 @@
<Textbox label="Name" bind:text={field.name} /> <Textbox label="Name" bind:text={field.name} />
<Dropdown <Dropdown
label="Type" label="Type"
bind:selected={draftField.type} bind:selected={type}
options={FIELD_TYPES} /> options={FIELD_TYPES} />
<Checkbox label="Required" bind:checked={required} />
{#if field.type === 'string'} {#if type === 'string'}
<NumberBox label="Max Length" bind:value={draftField.maxLength} /> <NumberBox label="Max Length" bind:value={constraints.length.maximum} />
<ValuesList label="Categories" bind:values={draftField.values} /> <ValuesList label="Categories" bind:values={constraints.inclusion} />
{:else if field.type === 'boolean'} {:else if type === 'datetime'}
<!-- TODO: revisit and fix with JSON schema --> <!-- TODO: revisit and fix with JSON schema -->
<Checkbox label="Allow Null" bind:checked={draftField.allowNulls} /> <DatePicker label="Min Value" bind:value={constraints.datetime.earliest} />
{:else if field.format === 'datetime'} <DatePicker label="Max Value" bind:value={constraints.datetime.latest} />
<!-- TODO: revisit and fix with JSON schema --> {:else if type === 'number'}
<DatePicker label="Min Value" bind:value={draftField.minValue} /> <NumberBox label="Min Value" bind:value={constraints.numericality.greaterThanOrEqualTo} />
<DatePicker label="Max Value" bind:value={draftField.maxValue} /> <NumberBox label="Max Value" bind:value={constraints.numericality.lessThanOrEqualTo} />
{:else if field.type === 'number'}
<NumberBox label="Min Value" bind:value={draftField.minimum} />
<NumberBox label="Max Value" bind:value={draftField.maximum} />
{:else if draftField.type.startsWith('array')}
<!-- TODO: revisit and fix with JSON schema -->
<NumberBox
label="Min Length"
bind:value={draftField.typeOptions.minLength} />
<NumberBox
label="Max Length"
bind:value={draftField.typeOptions.maxLength} />
{/if} {/if}
</form> </form>
</div> </div>

View file

@ -8,10 +8,6 @@
import * as api from "../api" import * as api from "../api"
import ErrorsBox from "components/common/ErrorsBox.svelte" import ErrorsBox from "components/common/ErrorsBox.svelte"
const CLASS_NAME_MAP = {
boolean: "uk-checkbox",
}
export let record = {} export let record = {}
export let onClosed export let onClosed
@ -27,14 +23,25 @@
function closed() { function closed() {
onClosed() onClosed()
} }
const isSelect = meta =>
meta.type === "string"
&& meta.constraints
&& meta.constraints.inclusion
&& meta.constraints.inclusion.length > 0
function determineInputType(meta) { function determineInputType(meta) {
if (meta.type === "datetime") return "date" if (meta.type === "datetime") return "date"
if (meta.type === "number") return "number" if (meta.type === "number") return "number"
if (meta.type === "boolean") return "checkbox" if (meta.type === "boolean") return "checkbox"
if (isSelect(meta)) return "select"
return "text" return "text"
} }
function determineOptions(meta) {
return isSelect(meta) ? meta.constraints.inclusion : []
}
async function saveRecord() { async function saveRecord() {
const recordResponse = await api.saveRecord( const recordResponse = await api.saveRecord(
@ -46,7 +53,9 @@
$backendUiStore.selectedModel._id $backendUiStore.selectedModel._id
) )
if (recordResponse.errors) { if (recordResponse.errors) {
errors = recordResponse.errors errors = Object.keys(recordResponse.errors)
.map(k => ({dataPath: k, message: recordResponse.errors[k]}))
.flat()
return return
} }
@ -65,8 +74,8 @@
{#each modelSchema as [key, meta]} {#each modelSchema as [key, meta]}
<div class="uk-margin"> <div class="uk-margin">
<RecordFieldControl <RecordFieldControl
className={CLASS_NAME_MAP[meta.type]}
type={determineInputType(meta)} type={determineInputType(meta)}
options={determineOptions(meta)}
label={key} label={key}
bind:value={record[key]} /> bind:value={record[key]} />
</div> </div>

View file

@ -3,10 +3,16 @@
export let value = "" export let value = ""
export let label export let label
export let errors = [] export let errors = []
export let className = "uk-input" export let options = []
let checked = type === "checkbox" ? value : false let checked = type === "checkbox" ? value : false
const determineClassName = type => {
if (type === "checkbox") return "uk-checkbox"
if (type === "select") return "uk-select"
return "uk-input"
}
const handleInput = event => { const handleInput = event => {
if (event.target.type === "checkbox") { if (event.target.type === "checkbox") {
value = event.target.checked value = event.target.checked
@ -23,11 +29,23 @@
</script> </script>
<label>{label}</label> <label>{label}</label>
{#if type === "select"}
<select
class={determineClassName(type)}
bind:value={value}
class:uk-form-danger={errors.length > 0} >
{#each options as opt}
<option value={opt}>{ opt }</option>
{/each}
</select>
{:else}
<input <input
class={className} class={determineClassName(type)}
class:uk-form-danger={errors.length > 0} class:uk-form-danger={errors.length > 0}
{checked} {checked}
{type} {type}
{value} {value}
on:input={handleInput} on:input={handleInput}
on:change={handleInput} /> on:change={handleInput} />
{/if}