Files
RenewCMS/web/src/lib/schemaBuilderModel.ts
T

161 lines
3.5 KiB
TypeScript

import { FIELD_TYPE_SPECS, FIELD_TYPES, type FieldType } from '@/lib/fieldTypes'
import { DEFAULT_RELATION_KIND, type RelationKind } from '@/lib/relationField'
export { FIELD_TYPES, type FieldType }
export type KeyMode = 'auto' | 'manual'
export type KeyDisplayMode = KeyMode | 'empty'
export type BuilderStatus =
| 'saving'
| 'offline'
| 'failed'
| 'problems'
| 'dirty'
| 'saved'
| 'none'
export const BUILDER_LIMITS = {
nameMax: 100,
typeKeyMin: 2,
typeKeyMax: 40,
fieldsMax: 50,
fieldKeyMax: 40,
choicesMax: 50,
}
export const RESERVED_TYPE_KEYS = ['new']
export const PREVIEW_KEY_FALLBACK = 'events'
export const STARTER_LABEL = 'Title'
export const STARTER_KEY = 'title'
export interface BuilderField {
uid: number
label: string
key: string
keyMode: KeyMode
type: FieldType
required: boolean
unique: boolean
defaultValue: string
defaultOn: boolean
min: string
max: string
options: string[]
relationType: string
relationKind: RelationKind
saved: boolean
}
export interface BuilderForm {
name: string
key: string
keyMode: KeyMode
keyLocked: boolean
fields: BuilderField[]
}
export function keyDisplayMode(mode: KeyMode, key: string): KeyDisplayMode {
if (mode === 'manual') {
return 'manual'
}
return key ? 'auto' : 'empty'
}
export function createField(uid: number, overrides: Partial<BuilderField> = {}): BuilderField {
return {
uid,
label: '',
key: '',
keyMode: 'auto',
type: 'text',
required: false,
unique: false,
defaultValue: '',
defaultOn: false,
min: '',
max: '',
options: [],
relationType: '',
relationKind: DEFAULT_RELATION_KIND,
saved: false,
...overrides,
}
}
export function starterField(uid: number): BuilderField {
return createField(uid, { label: STARTER_LABEL, key: STARTER_KEY })
}
export function blankForm(uid: number): BuilderForm {
return {
name: '',
key: '',
keyMode: 'auto',
keyLocked: false,
fields: [starterField(uid)],
}
}
export function changeFieldType(field: BuilderField, type: FieldType): BuilderField {
if (field.type === type) {
return field
}
return createField(field.uid, {
label: field.label,
key: field.key,
keyMode: field.keyMode,
required: field.required,
type,
})
}
export function supportsUnique(type: FieldType) {
return FIELD_TYPE_SPECS[type].supportsUnique
}
export function supportsChoices(type: FieldType) {
return FIELD_TYPE_SPECS[type].supportsChoices
}
export function holdsRelation(type: FieldType) {
return FIELD_TYPE_SPECS[type].holdsRelation
}
export function supportsLimits(type: FieldType) {
return FIELD_TYPE_SPECS[type].supportsLimits
}
export function hasDefaultValue(field: BuilderField) {
return !field.unique && field.defaultValue !== ''
}
export function trimmedOptions(field: BuilderField) {
return field.options.map((option) => option.trim())
}
export function clearStaleDefault(field: BuilderField): BuilderField {
if (field.type !== 'select' || field.defaultValue === '') {
return field
}
return trimmedOptions(field).includes(field.defaultValue)
? field
: { ...field, defaultValue: '' }
}
export function isUnique(field: BuilderField) {
return field.unique && supportsUnique(field.type)
}
export function supportsDefault(type: FieldType) {
return FIELD_TYPE_SPECS[type].supportsDefault
}
export function effectiveDefault(field: BuilderField) {
if (!supportsDefault(field.type) || isUnique(field) || field.defaultValue === '') {
return ''
}
if (field.type === 'select') {
return trimmedOptions(field).includes(field.defaultValue) ? field.defaultValue : ''
}
return field.defaultValue
}